[Spring Web MVC] 응답 정보 다루기
정적 리소스 / 뷰 템플릿 (동적) / HTTP 메세지
응답도 이렇게 세 가지 방법으로 나눌 수 있다.
정적 리소스
/src/main/resources 다음 경로의
/static /public / resources /META-INF/resources 해당 디렉토리에 정적 리소스를 제공한다.
src/main/resources/static/basic/adsf.html 파일이 들어있으면 웹 브라우저에서는 basic/asdf.html 을 입력해서 파일을 열어볼 수 있다.
뷰 템플릿
뷰 템플릿을 거쳐 HTML이 생성되고, 뷰가 응답을 만들어 전달한다. (HTML 외에 뷰 템플릿이 만들 수 있는건 다 가능)
보통 WEB-INF 디렉토리에 위치하도록 해서 웹 브라우저에서 직접 접근이 불가능하도록 설정한다.
이 부분은 서블릿 컨테이너의 규약으로, 애플리케이션의 보안을 강화한다.
@Controller
public class ResponseViewController {
@RequestMapping("/response-view-v1")
public ModelAndView responseViewV1(){
ModelAndView mav = new ModelAndView("response/hello")
.addObject("data", "hello!~!");
return mav;
}
}
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p th:text="${data}">empty</p>
</body>
</html>
뷰 템플릿으로는 Thymeleaf를 사용한다.
컨트롤러에서 ModelAndView를 저렇게 넘겨주면 ${data} 에서 해당하는 키를 찾아서 변환한다.
@RequestMapping("/response-view-v2")
public String responseViewV2(Model model){
model.addAttribute("data", "hello!~!");
return "/response/hello";
}
반환 타입을 String으로 바꾸면 컨트롤러에서 해당하는 뷰 이름을 찾고 뷰 리졸버를 실행해 반환한다.
이때 파라미터로 모델을 입력받아 데이터를 전달해야 한다.
이 외에도 반환타입을 void로 설정하고 몇 가지 설정을 조작해도 같은 결과를 얻을 수 있는데.. 명시성이 너무 떨어지니 사용하지 말자.
HTTP API를 제공하는 경우는 HTML 대신 데이터를 전달해야 한다.
메세지 바디에 특정 형식으로 데이터를 담아서 응답하자. (JSON이 가장 많이 사용된다.)
당연히 전에 했던 HTML 이나 뷰 템플릿을 사용하는 예시도 메세지 바디를 사용하는데, 여기서는 메세지 바디에 HTML이 아니라 다른 타입의 데이터를 전송함을 의미한다.
@GetMapping("/response-body-json-v1")
public ResponseEntity<HelloData> responseBodyJsonV1() {
HelloData helloData = new HelloData();
helloData.setUsername("userA");
helloData.setAge(20);
return new ResponseEntity<>(helloData, HttpStatus.OK);
}
@ResponseStatus(HttpStatus.OK)
@ResponseBody
@GetMapping("/response-body-json-v2")
public HelloData responseBodyJsonV2() {
HelloData helloData = new HelloData();
helloData.setUsername("userA");
helloData.setAge(20);
return helloData;
}
반환 타입을 객체로 바로 지정할 때는 @ResponseStatus 애너테이션으로 응답 코드를 설정할 수 있다.
응답 코드를 동적으로 설정하려면 ResponseEntity를 사용해야 한다.
@RestController 애너테이션은 @Controller와 @ResponseBody를 합친 애너테이션으로 생각하면 된다.
뷰 템플릿을 사용하지 않고 HTTP 메세지 바디에 직접 데이터를 입력하는 컨트롤러이다. (Rest API를 만들 때 사용한다.)
@ResponseBody 애너테이션을 사용하면 viewResolver 대신 HttpMessageConverter가 대신 동작해 HTTP 메세지 바디에 내용을 직접 반환한다.
문자열을 반환하면 StringHttpMessageConverter가 호출되고, 객체를 반환하면 MappingJackson2HttpMessageConverter가 호출되는 등... 여러 메세지 컨버터가 기본으로 등록돼있다.
클라이언트 요청 메세지의 Accept 헤더와 서버의 컨트롤러 반환 타입 정보를 조합해서 메세지 컨버터를 호출한다.
HTTP 메세지 컨버터는 HTTP 요청에 있는 메세지를 읽어 특정 객체로 바꿔 컨트롤러의 파라미터로 넘겨주는 역할과 컨트롤러에서의 리턴값을 가지고 응답에도 넣어준다. (양방향)
HTTP 요청 데이터를 읽을 때는 content-type의 미디어 타입을 지원하는지 확인하고, HTTP 응답 데이터를 생성할 때는 HTTP 요청 메세지의 Accept 미디어 타입을 지원하는지 확인한다. (@RequestMapping 의 produce)
메세지 컨버터는 우선순위대로 확인한다.
1. ByteArrayHttpMessageConverter : 클래스 byte[] / 미디어 */*
2. StringHttpMessageConverter : 클래스 String / 미디어 */*
3. MappingJackson2HttpMessageConverter : 클래스 객체, 해시맵 / 미디어 application/json 관련
...
content-type : application/json
@RequestMapping
void hello(@RequestBody String data){ ... }
이런 메서드가 있을 때는 클래스타입이 String 이고 미디어 타입은 아무거나 다 되니까 2번 메세지 컨버터가 동작한다.
HTTP 메세지 컨버터는 @RequestMapping 을 처리하는 핸들러 어댑터인 RequestMappingHandlerAdapter 에서 사용된다.
핸들러 어댑터가 호출됐다.
핸들러 어댑터는 컨트롤러를 호출하는데, 컨트롤러가 가지는 다양한 파라미터들은 누가 처리해줄까?
여기서 ArgumentResolver가 사용된다.
컨트롤러를 호출하기 전 ArgumentResolver 를 호출해 해당 컨트롤러가 필요로 하는 다양한 파라미터 값들을 모두 생성하고 컨트롤러를 호출하면서 값들을 넘겨준다.
ArgumentResolver의 supportParameter() 메서드를 호출해 해당 파라미터를 지원하는지 확인하고, 지원한다면 resolveArgument() 메서드를 호출해 컨트롤러에게 넘겨줄 객체를 생성한다. (ArgumentResolver를 직접 만들 수도 있다.)
이후 컨트롤러의 반환 값을 변환할 때 ReturnValueHandler 가 사용돼 응답 값을 변환해서 처리한다.
String 으로 뷰 이름만 반환해도 동작하는 이유가 다 ReturnValueHandler 덕분이다.
HTTP 메세지 컨버터는 파라미터를 생성할 때와 반환 값을 변환할 때 사용된다.
요청의 경우 ArgumentResolver 는 HTTP 메세지 컨버터의 read를 사용해서 필요한 객체를 생성한다.
응답의 경우 ReturnValueHandler 가 HTTP 메세지 컨버터의 writer를 사용해서 응답 결과를 만든다.
스프링은 필요한 기능의 대부분을 제공하기 때문에 기능을 확장할 일이 거의 없지만, 그래도 확장이 가능하다.
WebMvcConfigurer 를 상속받아서 스프링 빈으로 등록하면 되니, 기능 확장이 필요할 때 사용하자.
'Spring > Spring Web MVC' 카테고리의 다른 글
[Spring Web MVC] Thymeleaf (1) (0) | 2022.08.19 |
---|---|
[Spring Web MVC] Spring MVC와 Thymeleaf 예시 (0) | 2022.08.18 |
[Spring Web MVC] 요청 정보 다루기 (0) | 2022.08.17 |
[Spring Web MVC] Spring MVC (0) | 2022.08.16 |
[Spring Web MVC] Adaptor (0) | 2022.08.16 |
댓글
이 글 공유하기
다른 글
-
[Spring Web MVC] Thymeleaf (1)
[Spring Web MVC] Thymeleaf (1)
2022.08.19 -
[Spring Web MVC] Spring MVC와 Thymeleaf 예시
[Spring Web MVC] Spring MVC와 Thymeleaf 예시
2022.08.18 -
[Spring Web MVC] 요청 정보 다루기
[Spring Web MVC] 요청 정보 다루기
2022.08.17 -
[Spring Web MVC] Spring MVC
[Spring Web MVC] Spring MVC
2022.08.16