[스프링 MVC 1편] 6 - (4) 응답 & 메세지 컨버터 & 핸들러 어댑터
* 스프링 입문 = window, 스프링 MVC 1편 = Mac 으로 진행합니다
* 진도 : 섹션6 - (11)~(14)
* : 자바 클래스명, : 코드, : 단축키
1. HTTP 응답
스프링(서버)에서 응답 데이터를 만드는 방법은 크게 3가지이다
정적 리소스 | 정적인 HTML, css, js를 제공할 때는 정적 리소스를 사용 경로: /static, /public, /resources, /META-INF/resources |
|
뷰 템플릿 | 동적인 HTML을 제공할 때는 뷰 템플릿을 사용 | |
HTTP 메시지 사용 | HTTP 메시지 바디에 JSON 같은 형식으로 데이터를 실어 보내기 |
예시 1) 뷰 템플릿
[ src - main - java - hello.springmvc - basic - response - ResponseViewController ]
@Controller
public class ResponseViewController {
@RequestMapping("/response-view-v1")
public ModelAndView responseViewV1(){
ModelAndView mav = new ModelAndView("response/hello")
.addObject("data", "hello!");
return mav;
}
}
- @Controller
- 요청 정보 매핑 @RequestMapping
- 요청 정보를 매핑 (해당 URL이 호출되면 이 메서드가 호출 )
- 모델 & 뷰 영역 객체 생성 ~ new ModelandView("// 논리 이름 //")
- 데이터 추가 add.Object()
@Controller
public class ResponseViewController {
@RequestMapping("/response-view-v2")
public String responseViewV2(Model model){
model.addAttribute("data", "hello!");
return "response/hello";
}
}
- @Controller
- @ResponseBody 가 없으면 response/hello 로 뷰 리졸버가 실행되어서 뷰를 찾아 렌더링 한다
- @ResponseBody 가 있으면 HTTP 메시지 바디에 직접 response/hello 라는 문자가 입력
- 요청 정보 매핑 @RequestMapping
- 요청 정보를 매핑 (해당 URL이 호출되면 이 메서드가 호출 )
- String으로 반환 public String ~
- Model 객체 생성 및 저장
- Model에 데이터 추가 .addAttribute()
- addAttribute(String name, Object value)
value 객체를 name 이름으로 추가
** @Controller를 사용하면서 String으로 반환하면 [반환값 = 뷰의 논리적이름]이 된다 **
예시 2) HTTP API, 메세지 사용
[ src - main - java - hello.springmvc - basic - response - ResponseBodyController ]
@Slf4j
@Controller
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(){
return new ResponseEntity<>("ok", HttpStatus.OK);
}
@ResponseBody
@GetMapping("/response-body-string-v3")
public String responseBodyV3(){
return "ok";
}
@ResponseStatus(HttpStatus.OK)
@ResponseBody
@GetMapping("/response-body-json-v1")
public HelloData responseBodyJsonV1(){
HelloData helloData = new HelloData();
helloData.setUsername("UserA");
helloData.setAge(20);
return helloData;
}
}
- responseBodyV1
- HttpServletResponse 객체를 통해서 HTTP 메시지 바디에 직접 ok 응답 메시지를 전달 (서블릿과 유사)
- responseBodyV2
- ResponseEntity<String> ~ ( = HttpEntity 를 상속 받고, HttpEntity는 HTTP 메시지의 헤더, 바디 정보를 갖고 있다)
- ResponseEntity는 HTTP 응답 코드를 설정 가능
- responseBodyV3
- @ResponseBody와 public String을 사용해 반환 값 view가 아닌 문자로 받기
(@RestController 사용하면 @ResponseBody 삭제 가능) - ResponseEntity 도 동일한 방식으로 동작
- responseBodyJsonV1
- ResponseEntity<HelloData> 반환 (JSON 형식)
- @ResponseBody 사용하면 ResponseEntity 생략 가능하고 반환값은 helloData로 변경
(@RestController 사용하면 @ResponseBody 삭제 가능) - 반환 형식이 바뀌어서 응답코드 임의로 설정 불가하므로 @ResponseStatus 애노테이션을 사용
2. HTTP 메세지 컨버터
뷰템플릿으로 HTML을 생성해서 응답하는 것이 아니라 HTTP API 처럼 JSON 데이터를 HTTP 메세지 바디에서 직접 읽고 쓰는 경우에 HTTP 메세지 컨버터를 사용한다
< @ ResponseBody 과정 >
localhost:8080 실행
↓
내장 톰켓 서버가 입력 받음
↓
스프링에서 Controller 찾기
↓
ResponeseBody
↓
MVC의 View 대신에 Http Messager Converter 사용
↓
기본 문자처리 String / 기본 객체처리 JSON
↓
웹에서 출력
- HTTP 메시지 컨버터를 적용하는 경우
- HTTP 요청 : @RequestBody / HttpEntity(RequestEntity)
- HTTP 응답 : @ResponseBody / HttpEntity(ResponseEntity
- canRead() , canWrite() : 메시지 컨버터가 해당 클래스, 미디어타입을 지원하는지 체크
- read() , write() : 실제로 메시지를 읽고 쓰는 기능
< 컨버터 종류 참고 >
- 클래스 타입: byte[] , 미디어타입: */* ,
요청 예) @RequestBody byte[] data
응답 예) @ResponseBody return byte[] 쓰기 미디어타입 application/octet-stream - 클래스 타입: String , 미디어타입: */*
요청 예) @RequestBody String data
응답 예) @ResponseBody return "ok" 쓰기 미디어타입 text/plain - 클래스 타입: 객체 또는 HashMap , 미디어타입 application/json 관련
요청 예) @RequestBody HelloData data
응답 예) @ResponseBody return helloData 쓰기 미디어타입 application/json 관련
< HTTP 요청 데이터 읽기 과정>
1. HTTP 요청 데이터 읽기
2. 컨트롤러에서 @RequestBody , HttpEntity 파라미터를 사용
3. 메시지 컨버터가 메시지를 읽을 수 있는지 확인하기 위해 canRead() 를 호출
4. 대상 클래스 타입을 지원하는가 / HTTP 요청의 Accept 미디어 타입을 지원하는가
( byte[] , String , HelloData ) / ( text/plain , application/json , */* )
5. canRead() 조건을 만족하면 read() 를 호출해서 객체 생성 및 반환
< HTTP 응답 데이터 생성 과정>
1. 컨트롤러에서 @RequestBody , HttpEntity로 값 반환
3. 메시지 컨버터가 메시지를 쓸 수 있는지 확인하기 위해 canWrite() 를 호출
4. 대상 클래스 타입을 지원하는가 / HTTP 요청의 Accept 미디어 타입을 지원하는가
( byte[] , String , HelloData ) / ( text/plain , application/json , */* )
5. canWrite() 조건을 만족하면 write() 를 호출해서 HTTP 응답 메세지 바디에 데이터 생성
3. 요청 매핑 핸들러 어댑터 구조
< RequestMappingHandlerAdapter 동작 방식 >
Dispatcher Servlet
↓
RequestMapping 핸들러 어댑터 호출
↓
파라미터를 유연하게 처리할 수 있는 ArgumentResolver 호출
↓
컨트롤러(핸들러)가 필요로 하는 다양한 파라미터의 값(객체)을 생성 / 이 때 HTTP 메세지 컨버터 동작
( HttpServletRequest, Model, @RequestParam, @ModelAttribute, @RequestBody , HttpEntity )
↓
파리미터의 값 준비되면 컨트롤러를 호출하면서 값을 넘겨주기
↓
ReturnValueHandler / 이 때 HTTP 메세지 컨버터 동작
( ModelAndView , @ResponseBody , HttpEntity , String )
** ReturnValueHandler **
ArgumentResolver 와 비슷한데 이것은 응답 값을 변환하고 처리한다
컨트롤러에서 String으로 뷰 이름을 반환해도 동작하는 이유가 바로 ReturnValueHandler 덕분이다
[ 정리 ]
스프링은 다음을 모두 인터페이스로 제공한다
- HandlerMethodArgumentResolver
- HandlerMethodReturnValueHandler
- HttpMessageConverter