춤추는 개발자

[inflearn] 스프링 MVC 1편 review 본문

Developer's_til/스프링 프레임워크

[inflearn] 스프링 MVC 1편 review

Heon_9u 2023. 4. 9. 18:04
728x90
반응형

✅ 강의 소개

웹 애플리케이션을 개발할 때 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. 스프링 MVC의 핵심 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니다.

 

✅ 강의별 후기

[ Servlet ]

Servlet은 톰캣같은 웹 어플리케이션 서버를 직접 설치하고, 그 위에 서블릿 코드를 클래스 파일로 빌드해서 올린 다음, 톰캣 서버를 실행.
Servlet을 생성하여 실제 Http 요청/응답을 수행.
HttpServletReqeust / HttpServletResponse를 기반으로 각 객체에 담기는 Parameter에 대한 이해.

- Application 클래스 @ServletComponentScan으로 Servlet을 직접 등록해서 사용.
- HttpServlet을 상속받은 클래스에 @WebServlet으로 이름과 urlPattern을 설정, service 메서드를 오버라이딩하여 Servlet으로 활용할 수 있다.
- application.properties에서 로깅 레벨을 설정 - ('logging.level.org.apache.coyote.http11=debug')

- Servlet은 Http 요청 메시지를 파싱하고 HttpServletRequest 객체에 담아서 제공 및 임시 저장소 역할

- setAttribute / getAttribute / getSession 등, START LINE / Header / Body 관련 메서드 제공

 

- Http 요청 데이터

- GET: URL의 쿼리 파라미터(/url?username=hello&age=20)에 데이터를 포함해서 전달

 o HttpServletRequest가 제공하는 메서드로 쿼리 파라미터를 조회할 수 있다.

 o getParameter / getParameterNames / getParameterMap / getParameterValues

 o getParameterNames().asIterator().forEachRemaining()

 o 만약 파라미터 이름이 중복된 경우, getParamterValues를 활용

 

- POST: content-type: application/x-www-form-urlencoded, 메시지 바디에 쿼리 파라미터 형식으로 전달

 o GET에서 사용한 쿼리 파라미터 조회 메서드를 그대로 사용

 o POST HTML Form 형식으로 데이터를 전달하면 HTTP 메시지 바디에 해당 데이터를 포함해서 보내기 때문에 바디에 포함된 데이터가 어떤 형식인지 content-type을 지정해야 한다.

 

- HTTP message body에 데이터를 직접 담아서 요청: HTTP API (Json, Xml, Text), POST / PUT / PATCH

 o 단순 텍스트를 메시지 바디에 담을 경우, inputStream으로 읽을 수 있다.

 o Json 형식은 content-type: application/json

 o Json 형식의 데이터를 ObjectMapper를 활용하여 직접 만든 객체에 담아 파싱할 수 있다.

 

- Http 응답 데이터 ( HttpServletResponse )

- HTTP 응답코드 지정 / 헤더, 바디 생성

- content-type, cookie, redirect 기능 제공


[ Servlet, JSP, MVC 패턴 ]

회원 저장/조회 기능을 단순 Servlet으로 시작하여 JSP, MVC 패턴으로 개발
단계별로 한계점과 불편한 점들을 개선

- 지난 Servlet 강의 내용을 바탕으로 요구사항 기능 개발 / 자바 코드에 View화면을 위한 HTML이 섞여 지저분하고 복잡.

- 정적인 HTML 문서의 불편함을 동적인 HTML인 JSP로 개발 / 하지만 다양한 코드(비즈니스 로직, 뷰 로직 등)가 섞여있어서 JSP가 많은 역할을 담당.

- 비즈니스 로직과 뷰 로직을 분리한 MVC 패턴으로 개발 / Servlet은 컨트롤러, JSP는 View 역할

 o Controller: HTTP 요청을 받아서 파라미터 검증 및 비즈니스 로직 수행, 뷰에 전달할 결과 데이터를 모델에 담는다.

 o Model: 뷰에 출력할 데이터를 담는 역할.

 o View: 모델에 담겨있는 데이터를 화면에 출력.

 

- redirect는 실제 클라이언트에 나갔다가, 다시 서버로 요청 / forward는 서버 내부에서 일어나는 호출로 클라이언트가 인지하지 못함.

- 현재 Controller 역할을 하는 Servlet 코드에 중복된 로직이 많음 / 이를 다음 강의에서 해결

 o Forward와 Viewpath, 사용하지 않는 코드, 공통 처리의 한계


[ MVC 프레임워크 만들기 ]

프론트 컨트롤러를 도입하여 View 분리 / Model 추가
v1 ~ v5까지 단계별로 로직을 리팩토링

- v1: 요청의 입구가 되는 FrontController 도입

 o Servlet과 비슷한 모양의 Controller 인터페이스를 도입, 이를 상속받아 활용하여 process 메서드를 오버라이딩

 o 공통 로직의 반복

 

- v2: v1에서 중복된 로직 중 ViewPath와 ReqeustDispatcher.forward를 공통 처리

 o MyView라는 클래스에 View를 반환하는 공통 로직을 담은 메서드를 만든다.

 o 사용하지 않는 Servlet 코드

 o View 이름 중복

 

- v3: v2의 Servlet 종속성과 View 이름 중복 제거

 o 요청 파라미터 정보를 request 대신 별도의 ModelView 객체를 만들어서 반환.

 o ModelView에는 뷰 이름을 담는 viewName과 요청 변수를 담는 Map형식의 model 생성.

 o 프론트 컨트롤러에는 HttpServletRequest에 담긴 파라미터를 map에 저장하여 요청에 맞는 controller에 전달.

 o Controller들은 view이름이 담긴 ModelView를 반환.

 o Controller는 뷰의 논리 이름을 반환하고, 프론트 컨트롤러에서 뷰의 물리 위치를 처리하도록 viewResolver 메서드를 생성.

 o MyView 객체에는 model에 담긴 데이터를 request에서 저장하여 반환.

 o 항상 ModelView 객체를 생성하고 반환하는 번거로움 존재.

 

- v4: ModeView를 반환하지 않고, 뷰 이름만 반환

 o 프론트 컨트롤러에서 model 객체를 생성해서 controller에 넘겨준다.

 o 여기에 유연성을 더해준다.

 

- v5: 어댑터 패턴을 적용

 o 핸들러 어댑터: 다양한 종류의 컨트롤러를 호출

 o supports 메서드:  어댑터가 해당 컨트롤러를 처리할 수 있는지 판단.

 o handle 메서드: 실제 컨트롤러를 호출하고 ModelView를 반환.

 o 핸들러: 더 넓은 범위의 컨트롤러를 의미

 o 프론트 컨트롤러에서는 요청받은 URI를 처리할 수 있는 어댑터를 조회

 o 매핑된 어댑터가 있으면 handle메서드를 호출하여 ModelView를 반환받고, 뷰 렌더링

 

- 다음에는 어노테이션 기반으로 컨트롤러를 통합한다.


[ 스프링 MVC - 구조 이해 ]

직접 만든 프레임워크 < --- > 스프링 MVC 비교
FrontController < - > DispatcherServlet
handlerMappingMap < - > HandlerMapping
MyHandlerAdapter < - > HandlerAdapter 
ModelView < - > ModelAndView
viewResolver < - > ViewResolver
MyView < - > View

스프링 MVC 구조와 동작 순서를 파악하고 기존 코드 리팩토링

- DispatchServlet도 HttpServlet을 상속받아서 사용하고, 모든 경로에 대해 매핑, 더 자세한 경로가 우선순위가 높다.

- 동작 순서

 o 핸들러 조회: 핸들러 매핑을 통해 URL에 매핑된 핸들러(컨트롤러)를 조회

 o 핸들러 어댑터 조회: 핸들러를 실행할 수 있는 핸들러 어댑터를 조회

 o 핸들러 어댑터 실행: 핸들러 어댑터를 실행

 o 핸들러 실행: 핸들러 어댑터가 실제 핸들러를 실행

 o ModelAndView 반환: 핸들러 어댑터는 핸들러가 반환하는 정보를 ModelAndView로 변환해서 반환

 o viewResolver 호출: 뷰 리졸버를 찾고 실행

 o View 반환: 뷰 리졸버는 뷰의 논리 이름을 물리 이름으로 바꾸고, 렌더링 역할을 하는 뷰 객체를 반환

 o 뷰 렌더링: 뷰를 통해서 뷰를 렌더링

 

- 주요 인터페이스 목록

 o 핸들러 매핑: org.springframework.web.servlet.HandlerMapping

 o 핸들러 어댑터: org.springframework.web.servlet.HandlerAdapter

 o 뷰 리졸버: org.springframework.web.servlet.ViewResolver

 o  뷰: org.springframework.web.servlet.View

 

- 스프링 부트가 자동 등록하는 핸들러 매핑과 핸들러 어댑터

 o RequestMappingHandlerMapping: 어노테이션 기반의 컨트롤러인 @RequestMapping에서 사용

 o BeanNameUrlHandlerMapping: 스프링 빈의 이름으로 핸들러를 찾는다.

 o RequestMappingHanlderAdapter: 어노테이션 기반의 컨트롤러인 @RequestMapping에서 사용

 o HttpRequestHandlerAdapter: HttpRequestHandler 처리

 

- 가장 우선순위가 높은 핸들러 매핑과 핸들러 어댑터를 활용할 수 있는 @RequestMapping으로 스프링 MVC의 컨트롤러를 통합

- @RequestMappng 대신, Http 메서드를 나타내는 @GetMapping, @PostMapping으로 처리


[ 스프링 MVC - 기본 기능 ]

로깅 레벨에 대한 이해.
Http 요청 매핑과 요청 파라미터와 관련된 Http 메서드와 어노테이션에 대한 이해.
Http 응답의 종류
요청에 따른 Http 메시지 컨버터

- System.out.print() 대신 SLF4J / LogBack과 같은 로깅 라이브러리의 성능(내부 버퍼링, 멀티 스레드 등등)이 좋다. / 기본적으로 시간, 로그 레벨, 클래스명 등 출력되어 유지보수에 용이

- Log 레벨: TRACE > DEBUG > INFO > WARN > ERROR

- 올바른 로그 사용법: log.debug("data = {}", data)

- @Controller는 반환값이 String이면 뷰 이름으로 인식하여 뷰가 렌더링

- @RestController는 반환값이 Http 메시지 바디에 바로 입력, @ResponseBody와 연관

- @PathVariable로 URL경로에 매칭되는 데이터를 편리하게 조회, pathName과 변수명이 같으면 생략 가능

- @RequestMapping에 특정 헤더나 미디어 타입 조건을 매핑할 수 있다.

- @RequestMapping기반의 컨트롤러에 다양한 파라미터를 지원

 o HttpServletRequest

 o HttpServletResponse

 o HttpMethod: Http 메서드를 조회

 o Locale: Locale 정보를 조회

 o @RequestHeader MultivalueMap<String, String> headerMap: 모든 Http 헤더 정보를 조회

 o @RequestHeader("host"): 특정 Http 헤더 정보를 조회

 o @CookieValue(value = "xxx"): 특정 쿠키를 조회

 

- @RequestParam

 o 요청 파라미터를 편리하게 조회 (HttpServletRequest.getParameter("name"))

 o String, int, Integer 등 단순 타입이면 생략 가능

 o 생략하는 대신, required = false

 o 파라미터에 값이 없는 경우, 빈문자 or NULL 반환 or defaultValue 사용

 o @RequestParam map<string, object>으로 요청 파리미터와 매핑가능

 

- @ModelAttribute

 o 요청 파라미터를 특정 객체에 자동으로 매핑해준다.

 o 요청 파라미터의 이름으로 객체의 프로퍼티를 setter로 찾아서 등록한다.

 o @RequestParam처럼 생략가능

 

- @HttpEntity

 o HTTP 헤더와 바디 정보를 편리하게 조회

 o 요청 파라미터를 조회하는 @RequestParam, @ModelAttribute와 관계 없음

 o 응답에도 사용 가능하며, view 조회는 불가

 o @RequestEntity: HttpMethod, url 정보가 추가

 o @ResponseEntity: HTTP 상태 코드 설정 가능

 

- @ResponseBody / @RequestBody

 o HTTP 메시지 바디 정보를 편리하게 조회

 o @ModelAttribute처럼 직접 만든 객체를 지정할 수 있다.

 o 대신, 생략하면 요청 파라미터처럼 동작하게 되어서 생략할 수 없다.

 o 응답으로 사용하면 Http 메시지 바디에 데이터를 그대로 입력한다.

 

- Http 메시지 컨버터

 o 스프링MVC 내부에서 HTTP 메시지 바디를 읽어서 문자나 객체로 변환하여 전달하는데, 이때 Http 메시지 컨버터라는 기능을 사용한다.

 o ByteArrayHttpMessageConverter: byte[], */*

 o StringHttpMessageConverter: String, */*

 o MappingJackson2HttpMessageConverter: 객체 또는 HashMap, application/json

 o RequestMappingHandlerAdapter 동작 과정에서 호출된다.

- ArgumentResolver

 o RequestMappingHandlerAdapter에서 핸들러가 필요로하는 다양한 파라미터의 값을 생성하여 전달

 o 이와 유사하게 ReturnValueHandler는 응답값을 변환하고 처리


[ 스프링 MVC - 웹 페이지 만들기 ]

상품에 대한 CRUD 기능을 제작하며 요청/응답에 대한 객체를 처리
핸들러 응답에 따른 브라우저 동작을 이해

- 지금까지 들은 내용을 바탕으로 Controller를 개발

- @RestController, @GetMapping, @PostMapping ,@PathVariable, @ModelAttribute 등 활용

- PRG (Post, Redirect / GET)

 o 웹 브라우저의 새로고침은 마지막에 서버에 전송한 데이터를 다시 전송해서 상품 등록 후, 새로고침하면 새로운 데이터가 계속 등록된다.

 o 상품 저장 후에 뷰 템플릿이 아닌, 상품 상세 화면으로 리다이렉트

 o RedirectAttiributes.addAttribute("itemId", savedItem.getId());

 o return "redirect:/basic/items/{itemId}";

 o 이외에 addAttribute("status", true)와 같은 방식으로 쿼리 파라미터 처리가 가능


✅ review

 스프링 MVC에 대해서는 현업에서 API를 개발하며 당연시하게 사용해왔다. 하지만 MVC가 지금까지 어떤 방식으로 개선되어 왔으며 각각의 어노테이션을 왜 사용하는지 이해할 수 있었다. 특히, MVC 전체 동작 방식을 정확하게 이해하는데 가장 큰 도움이 되었다.

 강의 내용을 실무에 적용할 때, 강의에서 다룬 내용에 맞춰 레거시 코드를 파악하고, 개선점을 찾아 리팩토링 방향을 잡을 수 있게 됐다. (물론, 사이드 이팩트로 인해 아직까지 손대기 힘든 코드가 많다...)

 가장 최근에는 보안성 이슈가 있었던 기능에 HttpEntity를 활용하며 해결하기도 했다. 임시 방편이였지만, 리다이렉트 형식으로 리팩토링할 예정이다.

728x90
반응형