이번에는 어노테이션 기반 컨트롤러에서 요청을 처리하는 방법에 대해서 알아보려고한다.
이전에는 어떻게 처리했는지와 어노테이션 기반의 처리방법들을 살펴보자.
HttpRequest
헤더 처리
Servlet 이용
- 먼저 HttpServlet를 이용한 방법이다.
@RestController
public class RequestHeaderController {
@RequestMapping("/headers")
public String headers(HttpServletRequest request, HttpServletResponse response){
return "ok";
}
}
- HttpServletRequest, HttpServletResponse
- 우리가 이전에도 사용해봤었던 요소이다.
- 요청, 응답 정보에 대한 정보를 가져오거나 넣을 수 있다.
- ex_) request.getHeader(), response.setHeader() .. 등등을 이용할 수 있다.
어노테이션 이용
- 다음으로는 어노테이션을 이용한 방법이다.
@RestController
public class RequestHeaderController {
@RequestMapping("/headers")
public String headers(@RequestHeader MultiValueMap<String, String> headerMap,
@RequestHeader("host") String host,
@CookieValue(value = "myCookie", required = false) String cookie)){
return "ok";
}
}
- @RequestHeader
- @RequestHeader(”host”) String Host 처럼 헤더 값을 가져와 사용할 수 있다.
- 혹은 헤더 하나에 여러 변수가 들어올 떄 MultiValueMap을 사용할 수 있다.
- MultiValueMap
- Map이랑 유사한데, 하나의 키에 여러가지 값을 받아올 수 있다.
- ex_) key1:[value1, value2, ...] 와 같은 형식
- @CookieValue
- 특정 쿠키를 조회할 수 있다.
- 필수 값 여부를 required 속성으로 지정할 수 있다.
그외에도 여러가지 가져오는 방법들이 있다.
@RestController
public class RequestHeaderController {
@RequestMapping("/headers")
public String headers(HttpMethod httpMethod,
Locale locale,){
return "ok";
}
}
- HttpMethod
- method 전송 형식을 얻어올 수 있다.
- ex_) GET, POST
- Locale
- Http 헤더 중 Locale의 정보를 얻어올 수 있다.
- 외에도 timezone, Principle 등 여러 값을 가져올 수 있다. (아래 스프링 문서에서 확인 가능)
- https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-ann-arguments
파라미터 처리
- 다음에는 파라미터 처리에 대해서 알아보려고 한다.
Servlet 이용
- 이번에도 먼저 HttpServlet를 이용한 방법이다.
@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");
}
- 이전에 사용해봤던 것 처럼 request.getParameter() 를 이용하여 파라미터를 꺼내올 수 있다.
어노테이션 이용
- 다음으로는 @RequestParam을 이용한 방법이다.
@ResponseBody // RestController와 같은 기능을함, 반환 값을 메시지에 바디에 넣는다.
@RequestMapping("/request-param-v2")
public String requestParamV2(@RequestParam("username") String memberName,
@RequestParam(defaultValue ="-1") int age) {
log.info("username={}, age={}", memberName, memberAge);
return "ok";
} // @RequestParam => request.getParameter와 같은 효과이다.
- @RequestParam() 을 이용해서 파라미터에 매핑 할 수 있다.
- age 처럼 메서드 파라미터의 이름과 요청 파라미터의 이름이 같으면 생략이 가능하다.
- 심지어는 @RequestParam 까지 생략이 가능하다.
- 이용가능한 속성
- required
- true, false 값이 들어가며, 해당 파라미터가 필수 값인지를 설정할 수 있다.
- 기본 값은 true이다.
- default
- default 값을 설정해줄 수 있으며, 값이 넘어오지 않을 때 기본 값으로 설정되게 된다.
- required
@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";
}
- 위처럼 Map으로 파라미터를 받아 처리 할 수도 있다.
@ResponseBody
@RequestMapping("/model-attribute-v1")
public String modelAttributeV1(@ModelAttribute HelloData helloData){
log.info("username={}, age={}", helloData.getUsername(), helloData.getAge());
log.info("heolloData={}" + helloData.toString());
return "ok";
} // @ModelAttribute 를 이용하면 모델(Data) 객체를 생성하고 값을 자동으로 바인딩해준다.
- @ModelAttribute를 이용해서 @Data 객체를 매핑할 수도 있다.
- 참고로 Modelattribute도 생략이 가능한데, 스프링은 어노테이션 생략이 다음과 같은 매커니즘으로 어노테이션을 자동으로 붙혀준다.
- String, Int, Integer 같은 단순 타입들은 @RequestParam
- 그 외 나머지 것들 ex_) helloData 같은 것들은 @Modelattribute를 붙혀서 처리한다.
- ArgumentResolver로 지정해둔 타입들은 제외된다.
- 이에 대해서는 후에 자세히 알아보자.
메시지 바디 처리
- 이번엔 PlainText, Json과 같은 메시지 바디를 처리하는 방법에 대해서 알아보자.
Servlet 이용
@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");
}
- 메시지 바디를 읽어올 때에는 InputStream을 이용하게 된다.
- StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8) 을 이용해 UTF_8로 인코딩이 가능하다.
@PostMapping("/request-body-string-v2")
public void requestBodyStringV2(InputStream inputStream, Writer reponseWriter) throws IOException{
String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
log.info("messageBody={}", messageBody);
reponseWriter.write("ok");
}
- InputStream을 파라미터 자체로 받아서 처리할 수도 있다.
- Json은 파싱을 위한 JsonMapper가 필요하다.
- 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");
}
- 받아오는 방식은 동일하지만 ObjectMapper를 통해서 데이터를 가공해주어야한다.
HttpEntity 사용
- HttpEntity를 사용해서 메시지 바디의 내용을 가져올 수도 있다.
@PostMapping("/request-body-string-v3")
public HttpEntity<String> requestBodyStringV3(HttpEntity<String> httpEntity){
String messageBody = httpEntity.getBody();
log.info("messageBody={}", messageBody);
return new HttpEntity<>("ok");
}
- 헤더와 바디정보를 편하게 조회할 수 있게 도와주는 기능을 한다.
- 상속받은 RequestEntity, ResponseEntity를 통해 특별 기능을 사용할 수도 있다.
@ResponseBody
@PostMapping("/request-body-json-v4")
public String requestBodyJsonV4(HttpEntity<HelloData> data){
HelloData helloData = data.getBody();
log.info("username={}, age={}", helloData.getUsername(), helloData.getAge());
return "ok";
}
- HttpEntity를 이용하면 Http 메시지 컨버터가 Http 메시지 바디의 내용을 우리가 원하는 문자나 객체 등으로 자동 변환해준다.
어노테이션 사용
@ResponseBody
@PostMapping("/request-body-string-v4")
public String requestBodyStringV4(@RequestBody String messageBody){
log.info("messageBody={}", messageBody);
return "ok";
}
- @RequestBody 어노테이션을 이용하여 메시지 바디의 내용을 그대로 가져올 수 있다.
@ResponseBody
@PostMapping("/request-body-json-v3")
public String requestBodyJsonV3(@RequestBody HelloData helloData){
log.info("username={}, age={}", helloData.getUsername(), helloData.getAge());
return hellodata;
}
- @RequestBody 또한 HttpEntity 와 같이 Http 메시지 컨버터가 작동하여 메시지 바디의 내용을 우리가 워하는 형식으로 변환해주게된다.
- 당연히 반환 값에서도 Json 형식으로 출력되게 된다. (위 코드에서는 Json → 객체 → Json의 순서를 거치게 됨)
- 참고로 @RequestBody는 생략이 불가능하다.
- 만약 생략하게된다면 스프링의 매커니즘에 의해 @ModelAttribute가 붙게 된다.
HttpResponse
- 응답은 크게 3가지의 종류로 나뉘는데 이에 대해서 살펴보자.
정적 리소스
- 정적 리소스는 말그대로 정적 리소스를 제공하는 쓰인다.
- 경로 자체가 url이 되며, 경로 상에 있는 파일들에 접근할 수 있다.
- http://localhost:8080/basic/hello-form.html
뷰 템플릿 사용(동적)
- 동적으로 뷰를 설정하는 방법을 말하며, 우리가 가장 많이 사용할 방법이다.
ModelAndView
@RequestMapping("/response-view-v1")
public ModelAndView responseViewV1(){
ModelAndView mav = new ModelAndView("response/hello")
.addObject("data", "hello!");
return mav;
}
- ModelandView를 통해서 뷰와 데이터 모두 설정하여 반환 값으로 넘기는 방법이다.
Model 이용
@RequestMapping("/response-view-v2")
public String responseViewV2(Model model){
model.addAttribute("data", "hello!");
return "response/hello";
}
- Model을 이용하여 데이터를 설정하고, 반환 값으로는 뷰의 논리적 이름을 반환하는 방법이다.
- 가장 명시적이며 많이 사용되는 방법이다.
- 만약 반환 값이 없으면 @RequestMapping 에 설정된 경로로 설정된다.
HTTP 메시지 사용(API)
서블릿 이용
@GetMapping("/response-body-string-v1")
public void responseBodyV1(HttpServletResponse response) throws IOException {
response.getWriter().write("ok");
}
- 일반적으로 데이터를 넘길 때는 위와 같이 response를 이용하여 메시지 바디에 값을 담는다.
HttpEntity 이용
@GetMapping("/response-body-string-v2")
public ResponseEntity<String> responseBodyV2() {
return new ResponseEntity<>("ok", HttpStatus.OK);
}
- HttpEntity를 상속받은 ResponseEntity를 이용해서 메시지 바디에 값을 담을 수 있다.
-
- 상태코드 까지 전달 가능
- Json 형식의 데이터를 전달할 때는 다음과 같다.
@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);
}
- 이전에 설명했던 것 처럼 ReponseEntity는 원하는 포맷으로 자동으로 변환해준다.
@ResponseBody
@ResponseBody
@GetMapping("/response-body-string-v3")
public String responseBodyV3() {
return "ok";
}
- @ResponseBody를 이용하여 메시지 바디에 값을 바로 담을 수 있다.
@ResponseStatus(HttpStatus.OK)
@ResponseBody
@GetMapping("/response-body-json-v2")
public HelloData responseBodyJsonV2(){
HelloData helloData = new HelloData();
helloData.setUsername("userA");
helloData.setAge(20);
return helloData;
}
- @ResponseBody도 원하는 포맷으로 자동으로 변환해준다.
- 또한, @ResponseStatus()을 통해 설정할 수 없었던 상태코드도 설정해줄 수 있다.
- 클래스 레벨에 @ResponseBody를 사용하면 전체 메서드에 적용되는데, 이를 대체하기 위한 것이 @RestController 이다.
- @RestController = @Controller + @ResponseBody 인 것을 기억하자.
참고 -
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1
'Spring' 카테고리의 다른 글
[Spring] AOP와 Proxy (0) | 2024.04.01 |
---|---|
[Spring] HTTP 메시지 컨버터 (0) | 2022.05.23 |
[SpringMVC] 매핑 (Mapping) (0) | 2022.05.23 |
[SpringMVC] 로깅 (Logging) (0) | 2022.05.23 |
[Spring MVC] Spring MVC 패턴 (0) | 2022.05.11 |