배운 내용 정리
[ ch. 02 Spring MVC ]
05. 클라이언트와 서버
> Tomcat의 내부 구조
: 톰캣 서버 안에 서비스가 있고, 그 서비스를 처리하는 게 엔진임.
: 엔진 안에는 호스트가 여러 개 존재할 수 있고,
그 중에서 어떤 호스트를 디폴트로 할 것인지 지정할 수 있음.
: 호스트 안에는 컨텍스트(스프링 프로젝트)가 여러 개 존재할 수 있음.

출처: [스프링의 정석 - 기초편] 남궁성과 끝까지 간다.
> 요청 | 8080
: 브라우저로 요청하면, 8080 포트로 요청이 감.
→ 톰캣 설정이 8080으로 되어 있기 때문에.
> 스레드 풀 (Thread Pool)
: 여러 스레드를 미리 만들어 놨다가 요청이 오면 스레드 하나가 맡아서 처리하는 것.
: 미리 스레드 풀을 만들어 놓으면 스레드를 그때그때 만들 필요가 없음.
: 요청이 왔을 때 요청을 처리하고 있지 않는 스레드가 받아서 처리함.
> 커넥터 (Connector)
: 어떠한 프로토콜로 요청했는지에 따라 처리할 커넥터가 달라짐.
: 요청을 엔진(Engine)한테 전달함.
> 호스트 (Host)
: 보통 하나의 톰캣 서버에 한 개의 호스트가 있으나 여러 개의 호스트가 존재할 수도 있음.
: 필요에 의해 도메인 네임이 다른 호스트를 여러 개 설치할 수 있음.
> 컨텍스트 (Context)
: 하나의 웹 애플리케이션(Web App).
: 하나의 호스트에 여러 개의 웹 애플리케이션이 설치될 수 있음.
: 컨텍스트 하나가 STS 프로젝트가 되는 것임.
: STS 프로젝트는 서로 영향을 주지 않는 독립적인 공간에서 실행되는 것.
> 서블릿 ( ≒ 컨트롤러 )
: 작은 서버 프로그램(서버에서 실행되는 프로그램)이라는 뜻.
: 여러 개의 서버 프로그램이, 같은 컨텍스트 안에서 실행될 수 있음.
: URL과 연결된 서블릿이 실행되는 것임.
: 서블릿이 작업을 수행하고, 클라이언트한테 작업 결과가 전달되며 프로그램 실행이 종료됨.
> Dispatcher Servlet
: 컨트롤러의 main 메서드를 호출함.
06. 설정 파일 - server.xml, web.xml
> Tomcat의 설정 파일
톰캣설치경로/conf/server.xml : Tomcat 서버 설정 파일
톰캣설치경로/conf/web.xml : Tomcat의 모든 web app의 공통 설정
웹앱이름/WEB-INF/web.xml : web app의 개별 설정
: 공통 설정을 먼저 적용한 후 각 앱마다 개별 설정을 적용함.
: 공통 설정을 개별 설정에서 덮어쓸 수도 있음.
07. HTTP 요청과 응답 - 이론
> 프로토콜 (Protocol)
: 서로 간의 통신을 위한 약속 혹은 규칙.
: 주고 받을 데이터에 대한 형식을 정의한 것.
+ 포수-투수 사인, 비즈니스 편지 형식 같은 거라고 생각하면 쉬움.
> HTTP (Hyper Text Transfer Protocol)의 특징
1. 단순하고 읽기 쉽다.
: 텍스트 기반의 프로토콜.
: Human readable (사람이 읽을 수 있는 텍스트)
: 요청할 때나 응답할 때 이런 메시지(HTTP)가 이동하는 것임.
2. 상태를 유지하지 않는다. (stateless)
: 클라이언트의 정보를 저장하지 않음.
: 같은 클라이언트가 요청을 한 번 보낸 후 다시 요청을 보내도,
서버는 두 요청이 같은 클라이언트라는 것을 구분하지 못함.
: 이를 보완하기 위해 쿠키와 세션을 사용함.
3. 확장 가능하다.
: 커스텀 헤더(header)를 추가할 수 있음.
> 헤더
: 형식 | 헤더이름: 값 (줄바꿈 표시)
: 헤더이름은 대소문자를 구분하지 않음.
: 공백을 무시함.
: 헤더는 여러 개가 나올 수 있음.
> 커스텀 헤더
: 표준에 정해 놓지 않은 헤더를 추가할 수 있음.
: 기존에 정의된 HTTP 기능을 마음대로 확장할 수 있는 것임.
: 서버와 클라이언트가 서로 약속이 되면 원하는 내용을 추가해서 주고 받을 수 있음.

> HTTP 응답 메시지 형식 (format)
: 서버가 클라이언트한테 응답해 주는 내용 형식.
: 형식대로 응답해 주어야 클라이언트가 이해할 수 있음.

출처: [스프링의 정석 - 기초편] 남궁성과 끝까지 간다.
> 상태 코드에 대한 분류표
→ 1xx Informational
: HTTP 1.1에서 추가된 것.
: 클라이언트와 서버 간에 정보 교환이 목적임.
: 잘 사용하지 않음.
→ 3xx Redirect
: 다른 URL로 재요청하라는 뜻.
→ 4xx Client Error
: 가장 유명한 에러 - 404 Not Found
: 클라이언트가 요청을 잘못한 것.
→ 5xx Server Error
: 클라이언트가 요청을 제대로 했으나 서버 처리하는 중에 에러가 발생한 것.
> 상태 라인 (status line)
: 요청이 어떻게 처리되었는지를 알려주는 줄.
: HTTP 1.11 프로트콜로 통신했고 요청에 대한 결과가 코드 200인 것.
: 상태 코드의 뒤쪽은 상태 코드에 대한 설명
> 헤더
: 헤더는 여러 줄이 될 수 있음(n줄).
: 각 횡마다 줄바꿈으로 구분함.
: 개수가 가변적이기 때문에 헤더와 바디 사이에 빈줄을 넣어 바디와 구분함.
> 바디
: 응답내용.
> HTTP 요청 메시지 - GET, POST
: GET은 읽기(Read), POST는 글쓰기(Write)라고 볼 수 있음.
> GET
: 서버한테 리소스를 요청해서 얻어 오려고 하는 것.
: 서버에 있는 리소스를 단순히 가져오는 것임.
: 리소스 URL만 작성하면 돼서 바디가 필요하지 않음.
: 대신 데이터를 보낼 게 있으면, 쿼리 스트링으로 추가 데이터를 보낼 수 있음.
> POST
: 서버에 데이터를 제공해야 될 때 사용함.
: 서버에 전송할 데이터를 바디에 담고 있음.
: posting(게시판 글쓰기) 용도로 만들어진 게 포스트 메서드임.

출처: [스프링의 정석 - 기초편] 남궁성과 끝까지 간다.
+ 추가 정리
> GET
2) 원래 데이터 전송이 목적이 아니기 때문에 소용량만 가능함.
크롬은 약 7,000자 정도 들어감.
4) URL과 데이터가 같이 있기 때문에 다른 사람에게 전달하기 쉬움.
> POST
4) 포스트 메서드로 전송했다고 해서 보안에 유리한 것은 아님.
HTTP에 TLS 프로토콜을 적용해야 함. ( https:// )
TLS는 암호화 프로토콜로, HTTP 메시지를 전송할 때 암호화해서 보내줌.
TLS 없이 포스트 방식으로 보냈다고 안전한 것이 아님.
SSL → TLS (new 보안 프로토콜) 바뀜.
+ General 헤더
: 요청 헤더, 응답 헤더를 제외한 일반적인 헤더.
: 요청과 응답의 공통적인 헤더가 분류돼서 나옴.
> Postman 확장 프로그램
: get 방식이나 post 방식, 그외의 다른 방식으로도 요청할 수 있음.
: 반복적인 요청을 할 때 요청한 기록을 다 저장하기 때문에 편리함.
: 여러 번 테스트할 때 유용함.



08. 텍스트와 바이너리, MIME, Base64
> 텍스트 파일
: 문자만 저장되어 있는 파일.
: 숫자를 문자로 변환 후 사용함.
> 바이너리 파일
: 문자와 숫자(데이터)가 저장되어 있는 파일.
: 숫자가 들어 있어서 값들이 어떤 것을 의미하는지 알기 어려움.
: 데이터를 있는 그대로 읽고 사용함.
> 텍스트 파일 vs 바이너리 파일
: 메모장으로 열었을 때
→ 읽기 어려우면 바이너리 파일.
→ 읽기 쉬우면 텍스트 파일.
: 메모장은 Text Editor(텍스트 편집기)임.
: 텍스트라고 생각하고 읽고 보여주는 것임.
: 데이터를 다 문자로 바꿔서 보여주는 것.
> MIME (Multipurpose Internet Mail Extensions)
: 바이너리 파일인지, 텍스트 파일인지 구분하기 위해 MIME 타입을 정해줌.
: 텍스트 기반 프로토콜에 바이너리 데이터를 전송하기 위해 고안됨.
: HTTP의 Content-Type헤더에 사용함.
: 데이터의 타입을 명시하는 것임.

출처: [스프링의 정석 - 기초편] 남궁성과 끝까지 간다.
+ 추가 내용
response.setContentType("text/html")
out.print("HTML")
: 이걸 적어 주어야 브라우저가 응답을 받았을 때 해석할 수 있음.
: html 문서인 것을 알아야 그 다음에 오는 내용을 제대로 해석할 수 있음.
ex. "text/html"이 아니라 "image/jpg"로 잘못 작성하는 경우,
보내준 내용이 HTML임에도 불구하고 이미지로 해석하게 됨.
> 바이너리 → 서버 실습


> boundary
: 텍스트 데이터와 바이너리 데이터를 경계로 구분하는 것.
> Limitations
: 포스트맨의 한계.
: 크롬에서 자동으로 보내주는 헤더들은 볼 수 없음.
: 폼 데이터 파일을 일부만 볼 수 있음.
> RequestHeader 실습


> Base64
: 바이너리 데이터를 텍스트 데이터로 변환할 때 사용함.
: 64진법은 모두 64개의 문자로 구성됨. '0'~'9', 'A'~'Z', 'a'~'z', '+', '/'

출처: [스프링의 정석 - 기초편] 남궁성과 끝까지 간다.
: 바이너리 2진수를 6bit씩 잘라서 변환함.
: 남는 자리는 0으로 채우고, 나머지 여섯 자리가 남으면 패딩문자로 채움.
: 자릿수를 맞추기 위해 빈자리를 채운다고 생각하면 됨.
: ASCII 128개, 특수문자와 출력할 수 없는 글자를 포함함.
: 7bit인 ASCII로 변환하면 안전하지 않음.
: 어떤 인코딩이든 6bit는 존재하기 때문에, 6bit로 변환하면,
서로 다른 OS를 가진 PC끼리 데이터를 전달해도 문제가 발생하지 않음.
: 6bit씩 끊어서 문자 1개, 즉 8bit로 바꾸니까 데이터가 늘어난다는 단점이 있음.
+ 인코딩의 종류에 따라 문자 하나의 크기가 다를 수 있음.
UTF-8에서는 영문자와 숫자가 1byte임.
: 주는 쪽과 받는 쪽이 문자체계가 다를 수 있음.
: 가장 안전한, 공통적인 문자세트인 64개만 골라서 변환해서 보내는 것임.
> 바이너리 데이터를 HTTP 프로토콜에 보내기 위한 방법
1. MIME 타입을 사용해서 바이너리를 그대로 넣기.
2. base64를 써서 바이너리를 텍스트로 변환해서 보내기.
> Base64 인코딩, 디코딩 실습





+ 페이지 소스 보기
: 바이너리 파일이 텍스트 파일로 다 들어간 것.
: 이미지 파일이 html과 하나가 됐기 때문에, 이미지 파일 없이 html 파일 하나만 있으면 됨.
: 하나의 html 파일 안에 이미지를 다 변환해서 직접 넣으면, html 파일에서 링크가 잘못되는 것을 걱정하지 않아도 됨.
: 파일의 사이즈는 약간 커지겠지만, html 파일과 연결된 이미지의 링크가 깨지는 것을 걱정하지 않아도 되니까 편리함.
09. 관심사의 분리와 MVC패턴 - 이론
> oop 5대 설계원칙 - SOLID
① SRP - 단일 책임의 원칙
: 하나의 메서드는 하나의 책임만 짐.
: 하나의 메서드는 하나의 관심사만 있어야 함.
> 분리
: 객체지향적으로 좋은 설계를 하려면 코드의 분리를 잘 해야 함.
: main에 있는 3개의 관심사를 분리해야 함.
: 분리하지 않아도 프로그램은 돌아갈 수 있겠지만,
객체지향 설계 원칙에서 보면 좋은 설계라고 할 수 없음.
1. 관심사의 분리
2. 변하는 것과 자주 변하지 않는 것의 분리
(common code / uncommon code)
3. 공통(중복) 코드의 분리
1. 관심사의 분리 (Separation of Concerns)
> 관심사 (concern)
: 해야할 작업.
2. 공통 코드의 분리 - 입력의 분리
: 대부분의 컨트롤러(Controller)는 입력, 처리, 출력의 형태로 되어 있음.
: 입력 부분에서는 request.getParameter( )를 많이 사용함.
→ 공통 코드, 중복되는 부분이 나타남.
: 입력을 처리하는 부분을 공통 코드로 뽑아내서 분리하는 것.

출처: [스프링의 정석 - 기초편] 남궁성과 끝까지 간다.

+ 추가 설명
: 여태 매개변수로 request 객체를 받아서 그 값을 getParameter( )로 받아서 사용했음.
: 이를 개별 매개변수로 직접 받도록 바꿀 수 있음.
: request.getParameter( ) 부분을 없앨 수 있음.
: int로 쓸 경우 Integer.parseInt( ) 부분도 필요하지 않게 됨.
→ "2023" 문자열이 아닌 2023 숫자로, 자동으로 변환된 값을 넘겨 주기 때문에.
: 이렇게 공통 코드를 분리함으로써 하나의 관심사를 제거할 수 있게 됨.
: int가 아닌 String으로 쓸 수도 있음.


3. 출력(view)의 분리 - 변하는 것과 변하지 않는 것의 분리
: 처리와 출력 두 관심사가 같은 메서드 안에 있을 때는 접근하는 데 문제가 없음.
: 그러나 별도의 메서드로 분리되면, yoil 값을 읽을 수가 없게 됨.
: 이런 경우 Model 객체가 필요해짐.
: 객체를 하나 만들어서 결과를 출력하는데 필요한 값을 다 저장함.
: 이후 Model 객체를 출력하는 부분에 전달해 주면, 값을 읽어서 출력을 만들 수 있음.
: 이런 방식으로 처리하는 것이 MVC 패턴임.

출처: [스프링의 정석 - 기초편] 남궁성과 끝까지 간다.
> MVC 패턴
: 실제 작업을 처리하는 부분 : Controller
: 출력하는 부분 : View
: 둘 간에 데이터를 주고 받을 수 있는 객체 : Model
: 서로 관심사와 역할이 다르기 때문에 별도의 코드로 분리하고,
서로 간에 데이터 전달을 위해서 Model이 필요한 것임.


출처: [스프링의 정석 - 기초편] 남궁성과 끝까지 간다.
> Spring MVC의 구조
: 사용자의 요청이 들어오면, DispatcherServlet(입력)이 앞에서 입력 처리를 함.
: Model 객체를 만들고 해당 Controller(처리)에 넘겨줌.
: Controller가 처리한 후 결과를 Model에 저장함.
: DispatcherServlet은 작업 결과가 담긴 Model을 View(응답)에게 전달하는 것임.
: View에서는 작업한 결과를 읽고 최종 응답을 만들어서 클라이언트한테 전송하게 됨.
> MVC 패턴
: 출력 부분(View)을 Contoller와 분리하고 나니까
상황에 따라 다른 View를 보여주는 것이 편리해짐.

출처: [스프링의 정석 - 기초편] 남궁성과 끝까지 간다.
+ 추가 설명
(1) 요청
: 클라이언트에서 요청이 오면, DispatcherServlet이
입력과 변환을 자동으로 처리해 주고, 모델을 생성해 줌.
(2)
: Model 객체는 결과저장소로, 이를 Contoller에 넘겨줌.
: getYoil 메서드가 호출된 결과를 변수 yoil에 담고,
Model 객체에 작업 결과를 Key Value 형태로 저장함.
: 이 Model을 DispatcherServlet이 View에게 전달함.
: Contoller가 어떠한 View를 통해서 결과를 보여줄지 지정할 수 있음.
: yoil이라고 작성할 경우 yoil.jsp를 통해 결과를 보여달라고 지정해 주는 것임.
(3)
: 따라서 "yoil" 이 반환됨.
: "yoil" = 결과를 보여줄 Veiw 이름.
(4)
: 작업 결과를 저장한 Model을 yoil.jsp로 전달함.
: 값을 출력하는 부분에 Model을 통해 전달된 값이 들어가는 것임.
+ 값을 출력하는 부분 : ${year}
(5) 응답
: 값이 채워진 내용으로 최종 결과물이 만들어지고,
이를 클라이언트한테 응답을 보내는 것임.
[yoilError.jsp]
: year, month, day 값이 잘못 들어와서 유효성 검사를 실패할 경우
Model에 값을 저장하지 않고, 바로 yoilError View로 감.
: Contoller가 yoilError 라는 이름을 반환하게 되면,
DispatcherServlet이 yoilError.jsp를 이용해서 응답하게 됨.
: 에러만 보여주면 되기 때문에 Model이 필요하지 않음.
> MVC 패턴을 잘 활용한 예
: 은행 거래내역을 조회할 때 PDF, CSV, Excel의 별도의 View가 제공되는 것.
10. 관심사의 분리와 MVC패턴 - 실습
> 컨트롤러 메서드의 반환 타입 - String 실습







+ 추가 설명
: 반환 타입은 String (void에서 바뀜)
: DispatcherServlet이 준 Model을 받아야 하니까 매개변수로 Model을 추가해 줌.
: request 받는 것과 똑같음.
DispatcherServlet이 매개변수를 보고 new model( ); 로 객체를 만들어서 넘겨주는 것임.
: DispatcherServlet에서 만든 것이기 때문에 다시 돌려줄 필요가 없음.
: 반환할 때는 어떤 View를 통해서 작업 결과를 보여줄지 적어 주어야 함.
: DispatcherServlet이 "yoil"을 받으면, yoil.jsp를 이용해서 결과를 출력하기를 원한다는 것임.

> 컨트롤러 메서드의 반환 타입 - void 실습



> 컨트롤러 메서드의 반환 타입 - ModelAndView 실습

+ 추가 설명
: 매개변수로 Model을 선언하지 않으면,
Controller에서 직접 Model을 만들어서 사용할 수도 있음.
: mv를 반환하면 DispatcherServlet에 Model과 View가 같이 전달됨.
: DispatcherServlet에서 다시 Model을 꺼내서 View에 전달하게 됨.
> 컨트롤러 메서드의 반환 타입
: 반환 타입을 String으로 설정해서 Veiw 이름을 반환하게 하고,
Model을 선언하는 방법을 많이 사용함.

출처: [스프링의 정석 - 기초편] 남궁성과 끝까지 간다.
+ [void]
: 뷰 이름을 반환하는 return문을 사용하면 안 됨.
11. 관심사의 분리와 MVC패턴 - 원리(1)

> javax.servlet.http.HttpServletRequest
: 매개변수 타입
> arg0
: 매개변수 이름
+ 추가 설명
: YoilTeller를 보면 매개변수 이름이 request, response인 것을 확인할 수 있지만,
Console에는 arg0, arg1로 바뀌어 있음.
: 컴파일러한테 매개변수 타입은 중요하지만, 매개변수 이름은 별로 중요한 정보가 아님.
: YoilTeller 클래스를 컴파일할 때 혹은 컴파일된 상태에서는 매개변수 이름을 저장하지 않음.
→ arg0, arg1와 같이 보여줄 수밖에 없음.
: YoilTeller가 가지고 있는 매개변수의 이름을 보여줄 수가 없는 것임.

+ 추가 설명
: 매개변수 이름을 저장하려면 컴파일 옵션에 parameters라는 옵션을 주어야 함.
: parameters는 매개변수의 이름을 저장한 옵션임.
: parameters가 없으면 클래스 파일에 매개변수 이름을 저장하지 않음.
: Jdk 1.8부터 추가됨.



: Maven에서 Update Project를 클릭해 주어야 함.
: MVC 프로젝트는 Maven을 이용해서 관리함.
: pom.xml 파일이 Maven 설정 파일임.
: 사용자는 pom.xml 파일을 통해서 이 프로젝트에 대한 설정을 바꾸어줄 수 있고,
이 파일에 손을 대면, Update Project를 꼭 해주어야 함.
: JRE System Library [JavaSE-11] 로 바뀐 것을 확인할 수 있음.

> Spring에서 매개변수 이름을 얻는 방법
1. Reflection API 이용하기
: Parameters 옵션을 넣고 컴파일을 해야 함.
: Java 8, Jdk 1.8부터 가능함.
2. Classfile 직접 읽기
: 클래스 파일의 정보를 이용함.
+ 스프링의 소스를 보면
먼저 Reflection API로 매개변수 이름을 알아내려고 함.
실패하면, 클래스 파일을 직접 읽어서 매개변수 이름을 얻어옴.

> Navigator
: 탐색기 같은 것임.
: 소스파일과 클래스 파일이 다 나옴.
> scr
: *.java
> target
: *.class
> YoilTeller.class
: 클래스 파일의 내용을 해석해서 보여주는 것임.
: 원래 클래스 파일은 binary 파일이라 보기 어렵게 되어 있음.
: STS에서 가지고 있는 Open With-Class File Viewer 를 통해서 해석하고 보여주는 것임.
> Local variable table
: 매개변수는 지역변수임.
: 여기에 있는 이름을 읽어서 알아내는 것.





출처: [스프링의 정석 - 기초편] 남궁성과 끝까지 간다.
+ MethodCall 실습 단계별 설명
1. main 메서드가 올라감.
2. 100번지에 map을 만듦.
3. HashMap이 만들어짐. (Key, Value)
4. ModelController(mc)의 main 메서드에게 map을 넘겨줌.
5. mc의 main 메서드가 호출됨.
6. mc의 main 메서드에 매개변수 map이 있음.
7. mc의 map에 main 메서드의 map을 넘겨줌.
8. 같이 HashMap을 가리킴.
9. HashMap에 값을 저장함.
10. viewName을 반환함.
11. mc의 main 메서드가 작업을 다 마쳤기 때문에 종료되면서
viewName으로 txtView2를 반환함.
12. 작업 결과가 담긴 map(data)과 viewName(txtView2)을
render라는 메서드에 넘겨줌.
13. render라는 함수는 data를 txtView2로 보여주는 것임.
14. 그 뒤로는 주석 내용


+ Console 내용 주저리..
: before은 map을 처음 생성하자마자는 비어있음.
: ModelController의 main 메서드를 호출하고 난 다음
map을 출력하니까 값이 채워짐.
: render 메서드를 호출하니까 map에 있는 데이터를
viewName을 통해 결과를 콘솔에 출력하게 한 것임.
12. 관심사의 분리와 MVC패턴 - 원리(2)








> @WebServlet
: maven 설정 때문에 에러가 남.
> 해결방법
1. pom.xml 파일을 변경하기
2. tomcat의 라이브러리를 import 하기
: tomcat 라이브러리가 @WebServlet을 가지고 있기 때문에 해석할 수 있게 됨.
: 스프링에서는 클래스 앞에 Controller를 붙이고,
메서드 앞에 RequestMapping으로 연결해 줬음.
: 서블릿에서는 메서드 단위로 매핑이 불가능하고, 클래스 단위로만 가능함.
→ 서블릿은 스프링에 비해 클래스를 많이 만들어야 한다는 단점이 있음.
> 항상 고정인 내용
: 서블릿은 HttpServlet을 상속 받아야 함.
: 메서드는 꼭 service라는 이름으로 해야 함.
: 매개변수는 request, response를 꼭 작성해 주어야 함.
후기
생각보다 확 높아진 난이도에 적응을 못 하고
방황하게 되는 일주일이었다..
기초를 건너뛰고 듣고 있다는 게 느껴진달까..?
이해가 안 가는 부분은 따로 검색해 보면서 따라가 보는 중이다..
용어가 갑자기 복잡해진 느낌인데,
스프링 선생님은 필기가 깔끔하고, 자막이 있어서
강의를 조금이라도 수월하게 들을 수 있어서 좋았다.
이제 2주밖에 안 남았으니까 남은 기간에는 최선을 다해보자ㅏ
다음 주도 화이팅!
'패캠 학습일지' 카테고리의 다른 글
| [패스트캠퍼스] Spring 강의 8주차 학습일지 (0) | 2024.01.03 |
|---|---|
| [패스트캠퍼스] Spring 강의 7주차 학습일지 (0) | 2023.12.26 |
| [패스트캠퍼스] Spring 강의 5주차 학습일지 (0) | 2023.12.12 |
| [패스트캠퍼스] 자바 강의 4주차 학습일지 (0) | 2023.12.05 |
| [패스트캠퍼스] 자바 강의 3주차 학습일지 (0) | 2023.11.28 |