IT recording...

[스프링 MVC1] 6. MVC 기본 기능 본문

Spring

[스프링 MVC1] 6. MVC 기본 기능

I-one 2022. 1. 15. 13:48

원문 링크

https://adorable-aspen-d23.notion.site/MVC1-6-MVC-9b59951ec4af4e779869255454e17f55

 

[스프링 MVC1] 6. MVC 기본 기능

요약

adorable-aspen-d23.notion.site

김영한님의 [스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술] 강의를 듣고 작성한 글입니다.

 

요약

------------------------------------------
1. GET - 쿼리 파라미터
2. POST - HTML Form

요청 - @RequestParam, @ModelAttribute
------------------------------------------
3. HTTP message body에 데이터 직접 넣어서 전달

요청 - @HttpEntity<T>, @RequestBody
------------------------------------------
------------------------------------------
1. 정적 리소스
2. 뷰 템플릿

3. HTTP 메시지
응답 - @ResponseBody , @HttpEntity<T>
------------------------------------------

** 로깅

* SLF4J
* Logback
**@Slf4j**
@RestController
public class LogTestController {
    //private final Logger log = LoggerFactory.getLogger(getClass());
    //@Slf4j를 넣으면 자동으로 이게 넣어진다.

    @RequestMapping("/log-test")
    public String logTest(){
        String name = "Spring";
        System.out.println("name = " + name);
        //log.info("name = "+ name); //사용할 수 있지만 사용하지 말자! (+연산이 일어나서 쓸모없는 리소스가 사용되는 것임)

        //log의 레벨을 정할 수 있다.
        **log.trace("trace log = {}", name);
        log.debug("debug log = {}", name);
        log.info("info log = {}",name);
        log.warn("warn log = {}",name);
        log.error("error log = {}",name);**
        return "ok";
    }
}
  • 로그 레벨 설정
    • LEVEL : TRACE > DEBUG > INFO > WARN > ERROR
#전체 로그 레벨 설정(기본 info)
logging.level.root=info

#hello.springmvc 패키지와 그 하위 로그 레벨 설정
logging.level.hello.springmvc=debug
  • 로그 사용 장점
    • 쓰레드 정보, 클래스 이름 같은 부가 정보를 함께 볼 수 있고, 출력 모양을 조정할 수 있다.
    • 로그 레벨에 따라 개발 서버에서는 모든 로그를 출력하고, 운영서버에서는 출력하지 않는 등 로그를 상황에 맞게 조절할 수 있다.
    • 시스템 아웃 콘솔에만 출력하는 것이 아니라, 파일이나 네트워크 등 로그를 별도의 위치에 남길 수 있다.
    • 특히 파일로 남길 때는 일별, 특정 용량에 따라 로그를 분할하는 것도 가능하다.
    • 성능도 일반 System.out보다 좋다. (내부 버퍼링, 멀티 쓰레드 등)
    ⇒ 실무에서는 반드시 로그를 사용하자!

1. 요청 매핑

  • URL주소 형태
    • /hello-basic
    • /hello-basic
    모두 같은 요청으로 매핑한다. (/hello-basic)
@RequestMapping(value = "/hello-basic", method = RequestMethod.GET) 
// url로 매핑 , 배열도 가능
  public String helloBasic(){
      log.info("helloBasic");
      return "ok";
}
  • HTTP 메서드 매핑
/**
 * method 특정 HTTP 메서드 요청만 허용
 * **GET, HEAD, POST, PUT, PATCH, DELETE**
 */
@RequestMapping(value = "/mapping-get-v1", **method = RequestMethod.GET**)
public String mappingGetV1() {
    log.info("mappingGetV1");
    return "ok";
}
  • HTTP 메서드 매핑 축약
/**
 * 편리한 축약 애노테이션 (코드보기)
 *** @GetMapping
 * @PostMapping
 * @PutMapping
 * @DeleteMapping
 * @PatchMapping**
 */
**@GetMapping**(value = "/mapping-get-v2")
public String mappingGetV2() {
    log.info("mapping-get-v2");
    return "ok";
}
  • PathVariable(경로 변수)사용
/**
     * PathVariable 사용
     * 변수명이 같으면 생략 가능
     *
     * **@PathVariable("userId") String userId -> @PathVariable userId**
     * /mapping/userA
     * */

    @GetMapping("/mapping/**{userId}**") //url에서 직접 파라미터 받아옴
    public String mappingPath(**@PathVariable("userId") String data**){
        log.info("mappingPath userId = {}", data);
        return "ok";
    }
  • PathVariable 다중 사용
/**
 * PathVariable 다중 사용
 */
@GetMapping("/mapping/users/**{userId}/orders/{orderId}**")
public String mappingPath(**@PathVariable("userId") String userId, @PathVariable("orderId") Long orderId**){
    log.info("mappingPath userId = {}, orderId = {}",userId,orderId);
    return "ok";
}
  • 특정 파라미터 조건 매핑
/**
 * 파라미터로 추가 매핑
 *** params="mode",
 * params="!mode"
 * params="mode=debug"
 * params="mode!=debug" (! = )
 * params = {"mode=debug","data=good"}**
 */
@GetMapping(value = "/mapping-param", **params = "mode=debug"**) //파라미터에 debug라는게 있어야만 호출이 된다.
public String mappingParam() {
    log.info("mappingParam");
    return "ok";
}
  • 특정 헤더 조건 매핑
/**
 * 특정 헤더로 추가 매핑
 *** headers="mode",
 * headers="!mode"
 * headers="mode=debug"
 * headers="mode!=debug" (! = )**
 */
@GetMapping(value = "/mapping-header", **headers = "mode=debug"**)
public String mappingHeader() {
 log.info("mappingHeader");
 return "ok";
}
  • 미디어 타입 조건 매핑 - HTTP 요청 Content-Type, consume
    • HTTP요청의 Content-Type 헤더를 기반으로 미디어 타입으로 매핑한다.
    • 만약 맞지 않으면 HTTP 415상태코드(Unsupported Media Type)을 반환한다.
/**
 * **Content-Type 헤더 기반 추가 매핑 Media Type**
 * **consumes="application/json"
 * consumes="!application/json"
 * consumes="application/*"
 * consumes="*\\/*"
 * MediaType.APPLICATION_JSON_VALUE**
 */
@PostMapping(value = "/mapping-consume", **consumes = "application/json"**)
public String mappingConsumes() {
    log.info("mappingConsumes");
    return "ok";
}
  • 미디어 타입 조건 매핑 - HTTP 요청 Accept, produce
    • HTTP요청의 Accept 헤더를 기반으로 미디어 타입으로 매핑한다.
    • 만약 맞지 않으면 HTTP 406상태코드(Not Acceptable)을 반환한다.
/**
 * **Accept 헤더 기반 Media Type**
 * **produces = "text/html"
 * produces = "!text/html"
 * produces = "text/*"
 * produces = "*\\/*"**
 */
@PostMapping(value = "/mapping-produce", **produces = "text/html"**)
public String mappingProduces() {
    log.info("mappingProduces");
    return "ok";
}
  • 매핑 예시
@RestController
@RequestMapping("/mapping/users")
public class MappingClassController {
    @GetMapping
    public String user(){
        return "get users";
    }

    @PostMapping
    public String addUser(){
        return "post user";
    }

    @GetMapping("/{userId}")
    public String findUser(@PathVariable String userId){
        return "get UserID ="+userId;
    }

    @PatchMapping("/{userId}")
    public String updateUser(@PathVariable String userId){
        return "update UserId ="+userId;
    }

    @DeleteMapping("/{userId}")
    public String deleteUser(@PathVariable String userId){
        return "delete userId = "+ userId;
    }
}

2. HTTP요청

** HTTP요청 데이터 조회 종류

  • 클라이언트 → 서버로 요청 데이터를 전달하는 방법
1. GET - 쿼리 파라미터
2. POST - HTML Form

요청 - @RequestParam, @ModelAttribute
응답 - @ResponseBody
------------------------------------------
3. HTTP message body에 데이터 직접 넣어서 전달

요청 - @HttpEntity<T>, @RequestBody
응답 - @ResponseBody

2-1) 기본,헤더 조회

@Slf4j
@RestController
public class RequestHeaderController {

    @RequestMapping("/headers")
    public String headers(HttpServletRequest request,
                          HttpServletResponse response,
                          HttpMethod httpMethod,
                          Locale locale,
                          @RequestHeader MultiValueMap<String, String> headerMap,
                          @RequestHeader("host") String host,
                          @CookieValue(value = "myCookie", required = false) String cookie
                          ){
        log.info("request={}", request);
        log.info("response={}", response);
        log.info("httpMethod={}", httpMethod); //HTTP메서드 조회
        log.info("locale={}", locale); // Locale정보 조회
        log.info("headerMap={}", headerMap); //모든 HTTP헤더를 MultiValueMapp형태로 조회
        log.info("header host={}", host); //특정 HTTP헤더를조회
        log.info("myCookie={}", cookie); //특정 쿠키 조회
        return "ok";
    }
}
  • MutliValueMap
    • MAP과 유사한데, 하나의 키에 여러 값을 받을 수 있다.
    • HTTP header, HTTP 쿼리 파라미터와 같이 하나의 키에 여러 값을 받을 때 사용한다.
    • keyA=value1&keyA=value2

2-2) HTTP요청 파라미터 - @RequestParam

요청 파라미터(request parameter) 조회

  • GET 쿼리 파라미터, HTML Form 전송 방식 모두 사용
  • V1 - 서블릿과 비슷한 모양
//서블릿과 비슷한 모양
@RequestMapping("/request-param-v1")
public void requestParamV1(HttpServletRequest request, HttpServletResponse response) throws IOException {
    String username = request.getParameter("username");
    int age = Integer.parseInt(request.getParameter("age"));

    log.info("username={}, age = {}",username,age);
    response.getWriter().write("ok");
}
  • V2 - RequestParam사용
//RequestParam 사용하기
@ResponseBody //return값이 string일 때 view 조회를 하지 않고 바로 응답에 string이 박혀서 나간다. (RestController와 같은 역할)
@RequestMapping("/request-param-v2")
public String requestParamV2(
        **@RequestParam("username") String memberName,
        @RequestParam("age") int memberAge**
){
    log.info("username={}, age={}",memberName,memberAge);
    return "ok";
}
  • V3 - RequestParam사용 시 매핑값과 이름 같을 때
    • 생략가능
@ResponseBody //return값이 string일 때 view 조회를 하지 않고 바로 응답에 string이 박혀서 나간다. (RestController와 같은 역할)
@RequestMapping("/request-param-v3")
public String requestParamV3(
    **@RequestParam String username, //매핑값과 이름이 같으면 이름 생략 가능
    @RequestParam int age**
){
log.info("username={}, age={}",username,age);
return "ok";
}
  • required 정보 명시
@ResponseBody
@RequestMapping("/request-param-required")
public String requestParamRequired(
        @RequestParam(**required = true**) String username, //꼭 들어와야 함
        @RequestParam(**required = false**) Integer age //안들어와도 됨
){
    log.info("username={}, age={}",username,age);
    return "ok";
}
  • defaultValue 사용
//defaultValue는 "" 빈 문자의 경우도 빈 것으로 간주한다.
@ResponseBody
@RequestMapping("/request-param-default")
public String requestParamDefault(
        @RequestParam(required = true, **defaultValue = "guest"**) String username, //꼭 들어와야 함
        @RequestParam(required = false, **defaultValue = "-1"**) int age //안들어와도 됨
){
    log.info("username={}, age={}",username,age);
    return "ok";
}
  • 파라미터 Map으로 한번에 받기
    • 파라미터 값이 하나가 아닌게 확실한 경우 사용
      • 근데 이런 경우 별로 없다.
//파라미터를 한꺼번에 Map으로 받을 수 있다.
@ResponseBody
@RequestMapping("/request-param-map")
public String requestParamMap(@RequestParam **Map<String,Object> paramMap**){
    log.info("username={}, age={}",paramMap.get("username"),paramMap.get("age"));
    return "ok";
}

2-3) HTTP요청 파라미터 - @ModelAttribute

: 요청 파라미터에 객체를 사용한다면 일일이 매핑을 해줘야 하지만 ModelAttribute는 이런 수고를 덜어준다.

@Data
public class HelloData {
 private String username;
 private int age;
}
  • V1 - 직접 매핑
@ResponseBody
@RequestMapping("/model-attribute-v1")
public String modelAttributeV1(@RequestParam String username, @RequestParam int age){
    HelloData helloData = new HelloData();
    helloData.setUsername(username);
    helloData.setAge(age);

    log.info("username={}, age={}",helloData.getUsername(),helloData.getAge());
    log.info("helloData = {}",helloData);
    return "ok";
}
  • V2 - ModelAttribute사용
    • HelloData를 생성한 후, 요청 파라미터의 이름으로 HelloData 객체의 프로퍼티를 찾는다.
    • 각 프로퍼티의 setter를 호출한 후 데이터를 바인딩한다.
//ModelAttribute를 사용하면 자동으로 HelloData 객체를 생성한다.
//요청 파라미터의 이름으로 HelloData의 프로퍼티를 찾고 알아서 set시킨다.(바인딩)
@ResponseBody
@RequestMapping("/model-attribute-v2")
public String modelAttributeV2(**@ModelAttribute HelloData helloData**){

    log.info("username={}, age={}",helloData.getUsername(),helloData.getAge());
    log.info("helloData = {}",helloData);
    return "ok";
}
  • V3 - ModelAttribute 생략 가능
/**
 * @ModelAttribute 생략 가능
 * **String, int 같은 단순 타입 = @RequestParam
 * argument resolver 로 지정해둔 타입 외 = @ModelAttribute**
 */
@ResponseBody
@RequestMapping("/model-attribute-v2")
public String modelAttributeV2(**HelloData helloData**) {
	 log.info("username={}, age={}", helloData.getUsername(),
	 helloData.getAge());
	 return "ok";
}

2-4) HTTP요청 파라미터 - 단순 텍스트

: HTTP message body에 직접 데이터를 담아 요청하는 경우

  • @RequestParam, @ModelAttribute를 사용할 수 없다.
  • V1 - 직접 inputstream사용
@PostMapping("/request-body-string-v1")
public void requestBodyString(HttpServletRequest request, HttpServletResponse response) throws IOException {
    ServletInputStream inputStream = request.getInputStream();
    String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);

    log.info("messageBody = {}",messageBody);
		response.getWriter().write("ok");
}
  • V2 - 불필요한 request,resonse제거
//불필요한 Request,Response 제거
@PostMapping("/request-body-string-v2")
public void requestBodyStringV2(InputStream inputStream, Writer responseWriter) throws IOException {
    String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);

    log.info("messageBody = {}",messageBody);
    responseWriter.write("ok");
}
  • V3 - HttpEntity<T> 사용
    • 문자가 들어왔을 때 HTTP Converter가 작동해서 자동으로 컨버트해준다.
    • HttpEntity
      • HTTP header, body정보를 편리하게 조회
      • 메시지 바디 정보 직접 조회
      • 요청 파라미터 조회는 하지 않음 (@RequestParam X, @ModelAttribute X)
      • 응답에도 사용 가능하다. (메시지 정보 직접 반환)
//String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
//하는 것도 귀찮음. 스프링 너가 대신 해줘!
//-> HttpEntity<String>과 같이 해놓으면 문자가 들어왔을 때 HttpBody에 있는거를 convert해줄게
@PostMapping("/request-body-string-v3")
public HttpEntity<String> requestBodyStringV3(**HttpEntity<String> httpEntity**) throws IOException {
    String messageBody = httpEntity.getBody();

    log.info("messageBody = {}",messageBody);
    return new HttpEntity<>("ok");
}
  • V4 - @RequestBody , @ResponseBody
//다 귀찮다. 다 해줘!!! @RequestBody, @ResponseBody

/**
 * **@RequestBody
 * - 메시지 바디 정보를 직접 조회(@RequestParam X, @ModelAttribute X)
 * - HttpMessageConverter 사용 -> StringHttpMessageConverter 적용
 *
 * @ResponseBody
 * - 메시지 바디 정보 직접 반환(view 조회X)
 * - HttpMessageConverter 사용 -> StringHttpMessageConverter 적용**
 */

**@ResponseBody**
@PostMapping("/request-body-string-v4")
public String requestBodyStringV4(**@RequestBody String messageBody**) throws IOException {
    log.info("messageBody = {}",messageBody);
    return "ok";
}

2-5) HTTP요청 파라미터 - JSON

  • V1 - mapping직접
private ObjectMapper objectMapper = new ObjectMapper();

@PostMapping("/request-body-json-v1")
public void requestBodyJsonV1(HttpServletRequest request, HttpServletResponse response) throws IOException {
    ServletInputStream inputStream = request.getInputStream();
    String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);

    log.info("messageBody = {}",messageBody);
    HelloData helloData = objectMapper.readValue(messageBody, HelloData.class);
    log.info("username={}, age={}",helloData.getUsername(),helloData.getAge());

    response.getWriter().write("ok");
}
  • V2 - @RequestBody 스트링, @ResponseBody 스트링 사용
//@RequestBody, @ResponseBody사용하자!
@ResponseBody
@PostMapping("/request-body-json-v2")
public String requestBodyJsonV2(**@RequestBody String messageBody**) throws IOException {
    log.info("messageBody = {}",messageBody);
    HelloData helloData = objectMapper.readValue(messageBody, HelloData.class);
    log.info("username={}, age={}",helloData.getUsername(),helloData.getAge());

    return "ok";
}
  • V3 - @RequsetBody 객체
    • @RequestBody에 직접 만든 객체를 지정하면 알아서 HttpMessageConverter가 이름 알아서 찾아서 바인딩해 준다.
    • @RequestBody 직접만든객체 의 경우 애노테이션을 생략하면 @ModelAttribute(parameter 받아오는 것)이 동작하므로 오류가 난다. ⇒ 생략XX!!
//json 매핑하는것도 귀찮은데?
//RequestBody에 직접 만든 객체를 지정하면 알아서 HttpMessageConverter가 이름 알아서 찾아서 바인딩해 준다.
//@RequestBody 직접만든객체 의 경우 애노테이션을 생략하면 @ModelAttribute(parameter 받아오는 것)이 동작하므로 오류가 난다.
@ResponseBody
@PostMapping("/request-body-json-v3")
public String requestBodyJsonV3(**@RequestBody HelloData helloData**) throws IOException {
    log.info("username={}, age={}",helloData.getUsername(),helloData.getAge());

    return "ok";
}
  • V4 - response json으로 보내기 @ResponseBody 객체
//response를 json으로 보내기
**@ResponseBody**
@PostMapping("/request-body-json-v4")
public HelloData requestBodyJsonV4(@RequestBody HelloData helloData) throws IOException {
    log.info("username={}, age={}",helloData.getUsername(),helloData.getAge());

    **return helloData**;
}

3. HTTP응답

3-1) HTTP응답 - 정적 리소스, 뷰 템플릿

  1. 정적 리소스
/static, /public, /resources, /META-INF/resources
  1. 뷰 템플릿

: 뷰 템플릿을 거쳐서 HTML이 생성되고, 뷰가 응답을 만들어 전달한다.

src/main/resources/templates
  • src/main/resources/templates/response/hello.html
@Controller
public class ResponseViewController {
	//1. ModelAndView 직접 반환
  @RequestMapping("/response-view-v1")
  public ModelAndView responseViewV1(){
      **ModelAndView mav = new ModelAndView("response/hello")**
              .addObject("data","hello!");
      return mav;
  }
	//2. Model은 파라미터로, 반환은 뷰 논리 이름
  @RequestMapping("/response-view-v2")
  public String responseViewV2(**Model model**){
      model.addAttribute("data","hello!");
      return "response/hello";
  }
}

3-2) HTTP응답 - HTTP API, 메시지 바디에 직접 입력

: 응답으로 JSON과 같은 데이터를 보낼 때

@Slf4j
@Controller
//ResponseBody는 클래스 레벨에 붙여도 된다.

public class ResponseBodyController {

    @GetMapping("/response-body-string-v1")
    public void responseBodyV1(HttpServletResponse response) throws IOException{
        response.getWriter().write("ok");

    }

		//응답코드 설정 가능
    @GetMapping("/response-body-string-v2")
    public ResponseEntity<String> responseBodyV2() throws IOException{
        return new **ResponseEntity<>("ok", HttpStatus.OK);**
    }

    **@ResponseBody**
    @GetMapping("/response-body-string-v3")
    public String responseBodyV3() throws IOException{
        return "ok";
    }

    @GetMapping("/response-body-json-v1")
    public **ResponseEntity<HelloData>** responseBodyJsonV1(){
        HelloData helloData = new HelloData();
        helloData.setUsername("userA");
        helloData.setAge(20);

        return new **ResponseEntity<HelloData>(helloData,HttpStatus.OK);**
    }

    //status값을 지정 가능
    **@ResponseStatus(HttpStatus.OK)**
    **@ResponseBody**
    @GetMapping("/response-body-json-v2")
    public HelloData responseBodyJsonV2(){
        HelloData helloData = new HelloData();
        helloData.setUsername("userA");
        helloData.setAge(20);

        **return helloData;**
    }
}
  • @ResponseEntity를 사용하면 함수적으로 상태코드를 설정할 수 있다.
  • @RequestBody를 사용하면 상태코드는 하드코딩해야 한다.
  • → 상황에 따라 골라 쓰자!
  • @RestController
    • @ResponseBody를 사용하면 뷰 템플릿을 사용하지 않고 바로 HTTP 메시지 바디에 데이터를 입력한다.
    • Rest API 를 만들 때 사용하는 컨트롤러이다.
**@Controller + @ResponseBody = @RestController!**

4. HTTP 메시지 컨버터

4-1) HTTP 메시지 컨버터란?

  • ex) @ResponseBody를 사용
    • viewResolver대신에 HttpMessageConverter가 동작한다.
      • 기본 문자 처리 : StringHttpMessageConverter
      • 기본 객체 처리 : MappingJackson2HttpMessageConverter
  • HTTP 메시지 컨버터 사용 경우
    • HTTP 요청 : @RequestBody, @HttpEntity(RequestEntity)
    • HTTP 응답 : @ResponseBody, @HttpEntity(ResponseEntity)
0 = ByteArrayHttpMessageConverter
		클래스 타입 : byte[]
		미디어 타입 : */*

1 = StringHttpMessageConverter
		클래스 타입 : String
		미디어 타입 : */*

2 = MappingJackson2HttpMessageConverter
		클래스 타입 : 객체,HashMap
		미디어 타입 : application/json
  • 대상 클래스 타입 + 미디어 타입을 체크해서 사용 여부를 결정한다.
    • 예시
      • SpringHttpMessageConverter
      content-type: application/json
      
      @RequestMapping
      void hello(@RequetsBody String data) {}
      
      • Mapping2Jackson2HttpMessageConverter
      content-type: application/json
      
      @RequestMapping
      void hello(@RequetsBody HelloData data) {}
      
      • ??
      content-type: text/html
      @RequestMapping
      void hello(@RequetsBody HelloData data) {}
      
  • Http 요청 데이터 읽기
    1. Http요청이 오고, 컨트롤러에서 @RequestBody, @HttpEntity 파라미터를 사용한다.
    2. 메시지 컨버터가 메시지를 읽을 수 있는지 확인하기 위해 canRead()를 호출한다.
      1. 대상 클래스 타입 확인 (요청 데이터의 byte[], String, 객체)
      2. Content-Type 확인 (text/plain, application.json, /)
    3. canRead()를 만족하면 read()를 호출해서 객체를 생성하고, 반환한다.
  • Http 응답 데이터 생성
    1. 컨트롤러에서 @ResponseBody, @HttpEntity로 값이 반환된다.
    2. 메시지 컨버터가 메시지를 쓸 수 있는지 확인하기 위해 canWrite()를 호출한다.
      1. 대상 클래스 타입 확인
      2. Accept 미디어 타입 확인 (@RequestMapping의 produces)
    3. canWrite()를 만족하면 write()를 호출해서 HTTP응답 메시지 바디에 데이터를 생성한다.

4-2) 요청 매핑 핸들러 어댑터 구조

  • 핸들러 어댑터에 요청이 들어왔을 때,
  • 변경 가능한 요청의 형태인지를 확인하고 그렇게 변경해주는 Argument Resolver가 동작한다.
--요청--
HttpServletRequest, Model 
@RequestParam, @ModelAttribute, @RequestBody, HttpEntity
  • 등이 요청 형태로 controller에 존재할 수 있는데,
  • Argument Resolver는 변환이 가능한지를 확인하고, 변환해서 핸들러에 넘겨준다.
--응답--
ModelAndView, @ResponseBody, HttpEntity

Argument Resolver는
변환이 가능한지를 확인하고, 변환해서 어댑터에 리턴한다. 
  • 등이 응답으로 들어오면,
  • Argument Resolver는 변환이 가능한지를 확인하고, 변환해서 어댑터에 리턴한다.
--요청--
@RequestBody, HttpEntity
--응답--
@ResponseBody, HttpEntity
  • 가 요청,응답으로 들어오면
  • Argument Resolver는 HTTP 메시지 컨버터를 호출해서 HTTP 형태로 데이터를 변환한다.
Comments