@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); //HttpServlet Request
log.info("response={}", response);
log.info("httpMethod={}", httpMethod);
log.info("locale={}", locale); //localeResolver
log.info("headerMap={}", headerMap);
log.info("header host={}", host);
log.info("myCookie={}", cookie);
//HttpSession , InputStream, OutputStream , RequestPart, RedirectAttribute
//BindingResult
return "ok";
}
서블릿 객체를 통해 request, response 정보 전체를 읽어올 수 있음
@RequestHeader, @CookieValue 등의 애노테이션을 통해 헤더, 쿠키 정보만을 조회
추가 ) Controller에서 사용 가능한 파라미터 목록 :
https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-methods/arguments.html
쿼리파라미터와 htmlForm은 request.getParameter()을 사용하면 다음 두가지 요청 파라미터를 조회할 수 있다.
1. HttpServletRequest 사용
//서블릿에서 요청 파라미터를 직접 꺼내는 방식
@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");
}
2. @RequestParam 사용
@ResponseBody
@RequestMapping("/request-param-v2")
public String requestParamV2(
@RequestParam("username") String memberName,
@RequestParam("age") int memberAge) {
log.info("username={}, age={}", memberName, memberAge);
return "ok";
}
/**
* @RequestParam 사용
* Map을 사용하면 전체 쿼리파라미터를 가져올 수 있다.
*/
@ResponseBody
@RequestMapping("/request-param-test")
public String requestParamTest(@RequestParam Map<String,Object> paramMap) {
log.info("username={},",paramMap);
return "ok";
}
추가 ) @ResponseBody
Controller 어노테이션에 String반환을 하게 되면 ViewResolver가 호출이 된다.
해결방법
html폼으로 해도 정상적으로 동작한다.
쿼리스트링 형태 혹은 요청 본문에 삽입되는 Form 형태의 데이터를 처리
@ResponseBody
@RequestMapping("/model-attribute-v1")
public String modelAttributeV1(@ModelAttribute HelloData helloData) {
log.info("username={}, age={}", helloData.getUsername(),
helloData.getAge());
return "ok";
}
바인딩 할 객체에 @Data 애노테이션이 있어야 한다.
@ModelAttribute 과정
HelloData 객체를 생성한 후 요청 파라미터의 이름으로 HelloData 객체의 프로퍼티를 찾는다. 그리고 해당 프로퍼티의 setter를 호출해서 파라미터의 값을 입력(바인딩) 한다
데이터 타입이 다르게 들어가는 경우 바인딩 오류가 발생 -> 검증 부분에서 처리 필요
요청 파라미터와 다르게, HTTP 메시지 바디를 통해 데이터가 직접 넘어오는 경우는 @RequestParam , @ModelAttribute 사용이 불가하다.
1. HttpServletRequest
request.getInputStream()
으로 직접 String을 읽어오거나 objectMapper을 사용하여 객체로 바인딩해준다. 2. InputStream
3. HttpEntity
4. @RequestBody
응답 데이터를 만드는 방식 3가지
1. HttpServletResponse
response.getWriter().write("ok")
HTTP 메시지 바디에 직접 응답 메시지를 전달한다. 2. ResponseEntity<>
3. @ResponseBody
@ResponseBody의 사용 원리
HTTP Body에 문자내용을 직접 반환
viewResolver 대신에 HttpMessageConverter가 동작
스프링 MVC가 HTTP 메시지 컨버터를 적용하는 경우
http 요청 데이터 읽기: 대상 클래스 타입을 지원하는지 확인, http 요청의 Content-Type 확인
http 응답 데이터 생성: 대상 클래스 타입을 지원하는지 확인, http 요청의 accept 미디어 타입을 확인
Controller 에서의 동작
content-type:application/json
@RequestMapping
public void hello(@RequestBody String data){}
메시지 컨버터의 동작
이 때, 클래스 타입과 미디어타입을 같이 확인한다.
미디어타입 */*
이기 때문에 어떤 미디어타입이든 가능하다.
=>StringHttpMessageConverter가 동작한다.
우선순위상 콘텐츠 타입이 json이여도 String컨버터가 먼저 사용이 된다.
안되는 경우
content-type: text/html
@RequestMapping
public void Hello(@RequestBody HelloData data){}
1.우선순위 상 ByteArray컨버터의 canRead()호출->Pass
3.MappingJackson2컨버터의 canRead() 호출
Class 타입이 객체이기 때문에 만족,
그러나 미디어 타입은 text/html이기 때문에 만족하지 않는다.
HTTP 메시지 컨버터는 스프링 MVC 어디쯤에서 사용되는 것일까?/
요청 매핑 핸들러 어댑터의 동작
RequestMappingHandlerAdapter가 호출이 되었다고 할 때,
먼저, 컨트롤러 클래스의 메소드를 보면 파라미터에 서블렛리퀘스트, 서블렛리스폰스 등의 정보를 던져준다.
ArgumentResolver.
애노테이션 기반의 컨트롤러는 매우 다양한 파라미터를 사용할 수 있다. 이렇게 파라미터를 유연하게 처리할 수 있는 이유가 바로 ArgumentResolver덕분이다.
supportsParameter()
- 핸들러(Controller)가 받아야 하는 파라미터 정보를 지원하는지 판단resolveArgument()
를 통해 객체를 만들어서 반환한다. ReturnValueHandler
ArgumentResolver
와 비슷하며, 응답 값을 변환하고 처리한다.