Spring MVC

DispatcherServlet 서블릿 등록
DispatcherServlet 도 부모 클래스에서 HttpServlet 을 상속 받아서 사용하고, 서블릿으로 동작한다.
- DispatcherServlet FrameworkServlet HttpServletBean HttpServlet
- 스프링 부트는 DispatcherServlet 을 서블릿으로 자동으로 등록하면서 모든 경로( urlPatterns="/" )에 대해서 매핑한다.
더 자세한 경로가 우선순위가 높다. 그래서 기존에 등록한 서블릿도 함께 동작한다.
요청 흐름
- 서블릿이 호출되면 HttpServlet 이 제공하는 service() 가 호출된다.
- 스프링 MVC는 DispatcherServlet 의 부모인 FrameworkServlet 에서 service() 를 오버라이드 해두었다.
- FrameworkServlet.service() 를 시작으로 여러 메서드가 호출되면서 DispatcherServlet.doDispatch() 가 호출된다.
DispatcherServlet.doDispatch()
protected void doDispatch(HttpServletRequest request, HttpServletResponseresponse) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
ModelAndView mv = null;
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
processDispatchResult(processedRequest, response, mappedHandler, mv,
dispatchException);
}
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView
mv, Exception exception) throws Exception {
render(mv, request, response);
}
protected void render(ModelAndView mv, HttpServletRequest request,
HttpServletResponse response) throws Exception {
View view;
String viewName = mv.getViewName();
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
view.render(mv.getModelInternal(), request, response);
}
1. HandlerMapping(핸들러 매핑)
핸들러 매핑에서 내 컨트롤러를 찾을 수 있어야 한다.
예) 스프링 빈의 이름으로 핸들러를 찾을 수 있는 핸들러 매핑이 필요하다.

2. HandlerAdapter(핸들러 어댑터)
핸들러 매핑을 통해서 찾은 핸들러를 실행할 수 있는 핸들러 어댑터가 필요하다.
예) Controller 인터페이스를 실행할 수 있는 핸들러 어댑터를 찾고 실행해야 한다.

스프링 부트는 InternalResourceViewResolver 라는 뷰 리졸버를 자동으로 등록하는데, 이때 application.properties 에 등록한spring.mvc.view.prefix, spring.mvc.view.suffix 설정 정보를 사용해서 등록한다.
@RequestMapping
- 스프링은 애노테이션을 활용한 매우 유연하고, 실용적인 컨트롤러를 만들었는데 이것이 바로 @RequestMapping 애노테이션을 사용하는 컨트롤러이다.
- 요청 정보를 매핑하고, 해당 URL이 호출되면 이 메서드가 호출된다.
- 애노테이션을 기반으로 동작하기 때문에, 메서드의 이름은 임의로 지으면 된다.
RequestMappingHandlerMapping
- 스프링 빈 중에서 @RequestMapping 또는 @Controller 가 클래스 레벨에 붙어 있는 경우에 매핑 정보로 인식한다.
RequestMappingHandlerAdapter
@Controller
스프링이 자동으로 스프링 빈으로 등록한다.
- 내부에 @Component 애노테이션이 있어서 컴포넌트 스캔의 대상이 됨
- 스프링 MVC에서 애노테이션 기반 컨트롤러로 인식한다.
Model 파라미터
- ViewName 직접 반환 뷰의 논리 이름을 반환할 수 있다
@RequestParam
- 스프링은 HTTP 요청 파라미터를 @RequestParam 으로 받을 수 있다.
@RestController
- @Controller 는 반환 값이 String 이면 뷰 이름으로 인식된다.
그래서 뷰를 찾고 뷰가 랜더링 된다.
- @RestController 는 반환 값으로 뷰를 찾는 것이 아니라, HTTP 메시지 바디에 바로 입력한다.
@RequestMapping의 HTTP 메서드
- method 속성으로 HTTP 메서드를 지정하지 않으면 HTTP 메서드와 무관하게 호출된다.
- 모두 허용 GET, HEAD, POST, PUT, PATCH, DELETE
@PathVariable(경로 변수) 사용
- @RequestMapping 은 URL 경로를 템플릿화 할 수 있는데, @PathVariable 을 사용하면 매칭 되는 부분을 편리하게 조회할 수 있다.
- @PathVariable 의 이름과 파라미터 이름이 같으면 생략할 수 있다.
- 다중 매핑 가능
HTTP 요청 - 기본, 헤더 조회
애노테이션 기반의 스프링 컨트롤러는 다양한 파라미터를 지원한다
HttpServletRequest
HttpServletResponse
HttpMethod
Locale
- 모든 HTTP 헤더를 MultiValueMap 형식으로 조회한다.
- 특정 HTTP 헤더를 조회한다.
- 속성
- 필수 값 여부: required
- 기본 값 속성: defaultValue
@CookieValue(value = "myCookie", required = false) String cookie
- 특정 쿠키를 조회한다.
- 속성
- 필수 값 여부: required
- 기본 값: defaultValue
MultiValueMap
- MAP과 유사한데, 하나의 키에 여러 값을 받을 수 있다.
- HTTP header, HTTP 쿼리 파라미터와 같이 하나의 키에 여러 값을 받을 때 사용한다.
- keyA=value1&keyA=value2
@RequestParam
- 파라미터 이름으로 바인딩
- HTTP 파라미터 이름이 변수 이름과 같으면 @RequestParam(name="xx") 생략 가능
- String , int , Integer 등의 단순 타입이면 @RequestParam 도 생략 가능
@ResponseBody
- View 조회를 무시하고, HTTP message body에 직접 해당 내용 입력
@ModelAttribute
- Dto 객체를 생성한다.
- 요청 파라미터의 이름으로 Dto 객체의 프로퍼티를 찾는다. 그리고 해당 프로퍼티의 setter를 호출해서 파라미터의 값을 입력(바인딩) 한다.
- HTTP 요청 메시지 바디의 내용을 직접 조회
OutputStream(Writer)
- HTTP 응답 메시지의 바디에 직접 결과 출력
HttpEntity
- HTTP header, body 정보를 편리하게 조회
- 메시지 바디 정보를 직접 조회
- 요청 파라미터를 조회하는 기능과 관계 없음 @RequestParam X, @ModelAttribute X
HttpEntity는 응답에도 사용 가능
- 메시지 바디 정보 직접 반환
- 헤더 정보 포함 가능
- view 조회X
HttpEntity 를 상속받은 다음 객체들도 같은 기능을 제공
RequestEntity
- HttpMethod, url 정보가 추가, 요청에서 사용
ResponseEntity
- HTTP 상태 코드 설정 가능, 응답에서 사용
return new ResponseEntity<String>("Hello World", responseHeaders,
HttpStatus.CREATED)
@RequestBody
- @RequestBody 를 사용하면 HTTP 메시지 바디 정보를 편리하게 조회할 수 있다.
- 헤더 정보가 필요하다면 HttpEntity 를 사용하거나 @RequestHeader 를 사용하면 된다.
@ResponseBody
- @ResponseBody 를 사용하면 응답 결과를 HTTP 메시지 바디에 직접 담아서 전달할 수 있다.
요청 파라미터 vs HTTP 메시지 바디
- 요청 파라미터를 조회하는 기능: @RequestParam , @ModelAttribute
- HTTP 메시지 바디를 직접 조회하는 기능: @RequestBody
@RestController
- @Controller 대신에 @RestController 애노테이션을 사용하면, 해당 컨트롤러에 모두 @ResponseBody 가 적용되는 효과가 있다.
- 뷰 템플릿을 사용하는 것이 아니라, HTTP 메시지 바디에 직접 데이터를 입력한다.
- 이름 그대로 Rest API(HTTP API)를 만들 때 사용하는 컨트롤러이다.
스프링 MVC는 다음의 경우에 HTTP 메시지 컨버터를 적용
HTTP 요청
- @RequestBody , HttpEntity(RequestEntity) ,
HTTP 응답
- @ResponseBody , HttpEntity(ResponseEntity) ,
HTTP 메시지 컨버터는 HTTP 요청, HTTP 응답 둘 다 사용
- canRead() , canWrite() : 메시지 컨버터가 해당 클래스, 미디어타입을 지원하는지 체크
- read() , write() : 메시지 컨버터를 통해서 메시지를 읽고 쓰는 기능
@ModelAttribute
- 요청 파라미터 처리
- @ModelAttribute 는 Dto 객체를 생성하고, 요청 파라미터의 값을 프로퍼티 접근법(setXxx)으로 입력해준다.
@ModelAttribute - Model 추가
- @ModelAttribute 는 모델(Model)에 @ModelAttribute 로 지정한 객체를 자동으로 넣어준다.