@Controller는 반환 값이 String이면 뷰 이름으로 인식된다. 그래서 뷰를 찾고 뷰가 랜더링 된다.@RestController는 반환 값으로 뷰를 찾는 것이 아니라, HTTP 메시지 바디에 바로 입력한다.
    @GetMapping("/mapping/{userId}") 
public String mappingPath(@PathVariable("userId") String data)
@PathVariable("userId") String userId) -> @PathVariable userId@GetMapping("/mapping/users/{userId}/orders/{orderId}") 
public String mappingPath(@PathVariable String userId, @PathVariable Long orderId)
@PostMapping(value = "/mapping-consume", consumes = "application/json")
@PostMapping(value = "/mapping-produce", produces = "text/html")
Content-Type 헤더와 Accept 헤더 둘 다 데이터 타입(MIME)을 다루는 헤더이다. 하지만 Content-Type 헤더는 현재 전송하는 데이터가 어떤 타입인지에 대한 설명을 하는 개념이고, Accept 헤더는 클라이언트가 서버에게 어떤 특정한 데이터 타입을 보낼 때 클라이언트가 보낸 특정 데이터 타입으로만 응답을 해야한다.
애노테이션 기반의 스프링 컨트롤러는 다양한 파라미터를 지원한다.
HttpServletRequestHttpServletResponseHttpMethod : HTTP 메서드를 조회한다. org.springframework.http.HttpMethodLocale : Locale 정보를 조회한다.@RequestHeader MultiValueMap<String, String> headerMap
    @RequestHeader("host") String host
    requireddefaultValue@CookieValue(value = "myCookie", required = false) String cookie
    클라이언트에서 서버로 요청 데이터를 전달할 때는 주로 다음 3가지 방법을 사용한다.
/url?username=hello&age=20content-type: application/x-www-form-urlencodedusername=hello&age=20GET 쿼리 파리미터 전송 방식이든, POST HTML Form 전송 방식이든 둘 다 형식이 같으므로 구분 없이 조회할 수 있다.
이것을 간단히 요청 파라미터(request parameter) 조회라 한다.
스프링이 제공하는 @RequestParam을 사용하면 요청 파라미터를 매우 편리하게 사용할 수 있다
@RequestMapping("/request-param-v2") 
public String requestParamV2(@RequestParam("username") String memberName,
														 @RequestParam("age") int age)
HTTP 파라미터 이름이 변수 이름과 같으면 @RequestParam(name="xx") 생략 가능
public String requestParamV4(String username, int age)
@RequestParam이 있으면 명확하게 요청 파리미터에서 데이터를 읽는다는 것을 알 수 있다.@RequestMapping("/request-param-required") 
public String requestParamRequired(@RequestParam(required = false) String username,
                                    @RequestParam(required = false) int age)
@RequestParam.required
    /request-param?username=/request-param 요청@RequestParam(required = false) int ageInteger로 변경하거나, 또는 다음에 나오는 defaultValue 사용@RequestMapping("/request-param-default") 
public String requestParamDefault(@RequestParam(defaultValue = "guest") String username, 
                                  @RequestParam(defaultValue = "-1") int age)
defaultValue를 사용하면 기본값을 적용할 수 있다.required는 의미가 없다.defaultValue는 빈 문자의 경우에도 설정한 기본값이 적용된다.@RequestMapping("/request-param-map") 
public String requestParamMap(@RequestParam Map<String, Object> paramMap) {
실제 개발을 하면 요청 파라미터를 받아서 필요한 객체를 만들고 그 객체에 값을 넣어주어야 한다.
스프링은 이 과정을 완전히 자동화해주는 @ModelAttribute 기능을 제공한다.
@RequestMapping("/model-attribute-v1") 
public String modelAttributeV1(@ModelAttribute HelloData helloData) {
스프링MVC는 @ModelAttribute가 있으면 다음을 실행한다.
HelloData 객체를 생성한다.HelloData 객체의 프로퍼티를 찾는다. 그리고 해당 프로퍼티의 setter를 호출해서 파라미터의 값을 입력(바인딩) 한다.username이면 setUsername() 메서드를 찾아서 호출하면서 값을 입력한다.public String modelAttributeV2(HelloData helloData) {
스프링은 해당 생략시 다음과 같은 규칙을 적용한다.
String , int , Integer 같은 단순 타입 = @RequestParam@ModelAttribute (argument resolver로 지정해둔 타입 외)@PostMapping("/add") 
public String addItemV2(@ModelAttribute("item") Item item) {
@ModelAttribute는 중요한 한 가지 기능이 더 있는데, 바로 모델(Model)에 @ModelAttribute로 지정한 객체를 자동으로 넣어준다.@ModelAttribute에 지정한 name(value) 속성을 사용한다.@ModelAttribute의 이름을 생략할 수 있다.요청 파라미터와 다르게, HTTP 메시지 바디를 통해 데이터가 직접 데이터가 넘어오는 경우는 @RequestParam , @ModelAttribute를 사용할 수 없다. (물론 HTML Form 형식으로 전달되는 경우는 요청 파라미터로 인정된다.)
@ResponseBody @PostMapping("/request-body-string-v4") 
public String requestBodyStringV4(@RequestBody String messageBody) throws IOException {
}
@RequestBody
@RequestBody를 사용하면 HTTP 메시지 바디 정보를 편리하게 조회할 수 있다.HttpEntity를 사용하거나 @RequestHeader를 사용하면 된다.@RequestParam, @ModelAttribute와는 전혀 관계가 없다.@ResponseBody
@ResponseBody를 사용하면 응답 결과를 HTTP 메시지 바디에 직접 담아서 전달할 수 있다. 물론 이 경우에도 view를 사용하지 않는다.
@ResponseBody @PostMapping("/request-body-json-v2") 
public String requestBodyJsonV2(@RequestBody String messageBody) throws IOException {
    HelloData data = objectMapper.readValue(messageBody, HelloData.class);
    return "ok"; 
}
objectMapper를 사용해서 자바 객체로 변환한다.
    @ResponseBody @PostMapping("/request-body-json-v3") 
public String requestBodyJsonV3(@RequestBody HelloData helloData) throws IOException {
    return "ok"; 
}
@RequestBody 객체 파라미터
@RequestBody HelloData data@RequestBody에 직접 만든 객체를 지정할 수 있다@RequestBody는 생략 불가능
@ModelAttribute에서 학습한 내용을 떠올려보자.
스프링은 @ModelAttribute , @RequestParam 해당 생략 시 다음과 같은 규칙을 적용한다.
따라서 이 경우 HelloData에 @RequestBody를 생략하면 @ModelAttribute가 적용되어버린다.
HelloData data -> @ModelAttribute HelloData data
따라서 생략하면 HTTP 메시지 바디가 아니라 요청 파라미터를 처리하게 된다.
@ResponseBody 
@PostMapping("/request-body-json-v5")
public HelloData requestBodyJsonV5(@RequestBody HelloData data) {
    return data; 
}
@ResponseBody
응답의 경우에도 @ResponseBody를 사용하면 해당 객체를 HTTP 메시지 바디에 직접 넣어줄 수 있다
@RequestBody 요청
    @ResponseBody 응답
    스프링(서버)에서 응답 데이터를 만드는 방법은 크게 3가지이다.
다음 경로에 파일이 들어있으면
src/main/resources/static/basic/hello-form.html
웹 브라우저에서 다음과 같이 실행하면 된다.
http://localhost:8080/basic/hello-form.html
정적 리소스는 해당 파일을 변경 없이 그대로 서비스하는 것이다.
뷰 템플릿을 거쳐서 HTML이 생성되고, 뷰가 응답을 만들어서 전달한다.
일반적으로 HTML을 동적으로 생성하는 용도로 사용하지만, 다른 것들도 가능하다. 뷰 템플릿이 만들 수 있는 것이라면 뭐든지 가능하다.
String을 반환하는 경우 - View or HTTP 메시지
@RequestMapping("/response-view-v2") 
public String responseViewV1(Model model) {  
    model.addAttribute("data", "hello!");  
    return "/response/hello"; 
}
@ResponseBody가 없으면 response/hello로 뷰 리졸버가 실행되어서 뷰를 찾고, 렌더링 한다.@ResponseBody가 있으면 뷰 리졸버를 실행하지 않고, HTTP 메시지 바디에 직접 response/hello라는 문자가 입력된다.HTTP API를 제공하는 경우에는 HTML이 아니라 데이터를 전달해야 하므로, HTTP 메시지 바디에 JSON 같은 형식으로 데이터를 실어 보낸다
뷰 템플릿으로 HTML을 생성해서 응답하는 것이 아니라, HTTP API처럼 JSON 데이터를 HTTP 메시지 바디에서 직접 읽거나 쓰는 경우 HTTP 메시지 컨버터를 사용하면 편리하다

@ResponseBody 사용 원리
@ResponseBody를 사용
    viewResolver 대신에 HttpMessageConverter가 동작StringHttpMessageConverterMappingJackson2HttpMessageConverterHttpMessageConverter가 기본으로 등록 되어 있음스프링 MVC는 다음의 경우에 HTTP 메시지 컨버터를 적용한다.
@RequestBody, HttpEntity(RequestEntity)@ResponseBody, HttpEntity(ResponseEntity)스프링 부트는 다양한 메시지 컨버터를 제공하는데, 대상 클래스 타입과 미디어 타입 둘을 체크해서 사용 여부를 결정한다. 만약 만족하지 않으면 다음 메시지 컨버터로 우선순위가 넘어간다.
몇 가지 주요한 메시지 컨버터
ByteArrayHttpMessageConverter : byte[] 데이터를 처리한다
    byte[] , 미디어타입: / ,@RequestBody byte[] data@ResponseBody return byte[] 쓰기 미디어타입 application/octet-streamStringHttpMessageConverter : String 문자로 데이터를 처리한다.
    String, 미디어타입: */*@RequestBody String data@ResponseBody return "ok" 쓰기 미디어타입 text/plainMappingJackson2HttpMessageConverter : application/json
    HashMap, 미디어타입 application/json@RequestBody HelloData data@ResponseBody return helloData 쓰기 미디어타입 application/json 관련HTTP 요청 데이터 읽기
@RequestBody, HttpEntity 파라미터를 사용한다.canRead() 를 호출한다.
    대상 클래스 타입을 지원하는가.
` • 예) @RequestBody의 대상 클래스 (byte[], String,  HelloData)
HTTP 요청의 Content-Type 미디어 타입을 지원하는가.
canRead() 조건을 만족하면 read()를 호출해서 객체 생성하고, 반환한다HTTP 응답 데이터 생성
@ResponseBody , HttpEntity로 값이 반환된다.canWrite()를 호출한다.
    byte[] , String , HelloData )@RequestMapping 의 produces)
        canWrite() 조건을 만족하면 write()를 호출해서 HTTP 응답 메시지 바디에 데이터를 생성한다HTTP 메시지 컨버터는 스프링 MVC 어디쯤에서 사용되는 것일까?
 모든 비밀은 애노테이션 기반의 컨트롤러,
모든 비밀은 애노테이션 기반의 컨트롤러, @RequestMapping을 처리하는 핸들러 어댑터인 RequestMappingHandlerAdapter(요청 매핑 헨들러 어뎁터)에 있다.
ArgumentResolver (HandlerMethodArgumentResolver)애노테이션 기반의 컨트롤러는 HttpServletRequest, Model은 물론이고, @RequestParam, @ModelAttribute 같은 애노테이션 그리고  @RequestBody, HttpEntity 같은 HTTP 메시지를 처리하는 부분까지 매우 큰 유연함을 보여주었다.
 애노테이션 기반 컨트롤러를 처리하는
애노테이션 기반 컨트롤러를 처리하는 RequestMappingHandlerAdaptor는 바로 이 ArgumentResolver를 호출해서 컨트롤러(핸들러)가 필요로 하는 다양한 파라미터의 값(객체)을 생성한다.
그리고 이렇게 파리미터의 값이 모두 준비되면 컨트롤러를 호출하면서 값을 넘겨준다.
ReturnValueHandler (HandlerMethodReturnValueHandler)컨트롤러에서 String으로 뷰 이름을 반환해도, 동작하는 이유가 바로 ReturnValueHandler 덕분이다.

HTTP 메시지 컨버터를 사용하는 @RequestBody도 컨트롤러가 필요로 하는 파라미터의 값에 사용된다.
@ResponseBody의 경우도 컨트롤러의 반환 값을 이용한다
@RequestBody를 처리하는 ArgumentResolver 있고,  HttpEntity를 처리하는 ArgumentResolver가 있다. 이 ArgumentResolver들이 HTTP 메시지 컨버터를 사용해서 필요한 객체를 생성한다.@ResponseBody와 HttpEntity를 처리하는 ReturnValueHandler가 있다. 그리고 여기에서 HTTP 메시지 컨버터를 호출해서 응답 결과를 만든다.