[Spring] 스프링 MVC

jinsung·5일 전

Spring

목록 보기
10/11
post-thumbnail

Spring MVC

DispatcherServlet 서블릿 등록

DispatcherServlet 도 부모 클래스에서 HttpServlet 을 상속 받아서 사용하고, 서블릿으로 동작한다.

  • DispatcherServlet FrameworkServlet HttpServletBean HttpServlet
  • 스프링 부트는 DispatcherServlet 을 서블릿으로 자동으로 등록하면서 모든 경로( urlPatterns="/" )에 대해서 매핑한다.
    더 자세한 경로가 우선순위가 높다. 그래서 기존에 등록한 서블릿도 함께 동작한다.

요청 흐름

  1. 서블릿이 호출되면 HttpServlet 이 제공하는 service() 가 호출된다.
  • 스프링 MVC는 DispatcherServlet 의 부모인 FrameworkServlet 에서 service() 를 오버라이드 해두었다.
  1. FrameworkServlet.service() 를 시작으로 여러 메서드가 호출되면서 DispatcherServlet.doDispatch() 가 호출된다.

DispatcherServlet.doDispatch()

protected void doDispatch(HttpServletRequest request, HttpServletResponseresponse) throws Exception {

  HttpServletRequest processedRequest = request;
  HandlerExecutionChain mappedHandler = null;
  ModelAndView mv = null;

  // 1. 핸들러 조회
  mappedHandler = getHandler(processedRequest);
  if (mappedHandler == null) {
  noHandlerFound(processedRequest, response);
  return;
  
  }

  // 2. 핸들러 어댑터 조회 - 핸들러를 처리할 수 있는 어댑터
  HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

  // 3. 핸들러 어댑터 실행 -> 4. 핸들러 어댑터를 통해 핸들러 실행 -> 5. ModelAndView 반환
  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();

  // 6. 뷰 리졸버를 통해서 뷰 찾기, 7. View 반환
  view = resolveViewName(viewName, mv.getModelInternal(), locale, request);

  // 8. 뷰 렌더링
  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

  • HTTP 메서드를 조회한다

Locale

  • Locale 정보를 조회한다.

@RequestHeader MultiValueMap<String, String> headerMap

  • 모든 HTTP 헤더를 MultiValueMap 형식으로 조회한다.

@RequestHeader("host") String host

  • 특정 HTTP 헤더를 조회한다.
  • 속성
    • 필수 값 여부: required
    • 기본 값 속성: defaultValue
  • 특정 쿠키를 조회한다.
  • 속성
    • 필수 값 여부: 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

  1. Dto 객체를 생성한다.
  2. 요청 파라미터의 이름으로 Dto 객체의 프로퍼티를 찾는다. 그리고 해당 프로퍼티의 setter를 호출해서 파라미터의 값을 입력(바인딩) 한다.

InputStream(Reader)

  • 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 로 지정한 객체를 자동으로 넣어준다.
profile
Backend Engineer

0개의 댓글