HTTP 헤더 정보 조회 방법
@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);
log.info("response={}", response);
log.info("httpMethod={}", httpMethod);
log.info("locale={}", locale);
log.info("headerMap={}", headerMap);
log.info("header host={}", host);
log.info("myCookie={}", cookie);
return "ok";
}
주요 파라미터
@RequestHeader MultiValueMap<String, String> headerMap : 모든 HTTP 헤더를 MultiValueMap 형식으로 조회
MultiValueMap이란?
- Map과 유사하지만, 하나의 키에 여러 Value를 받을 수 있음
- HTTP 헤더, HTTP 쿼리 파라미터와 같이 하나의 키에 여러 값을 받을 때 사용
(ex) keyA=value1&keyA=value2)
요청 데이터 조회
다음과 같이 크게 3가지
1. GET - 쿼리 파라미터 : ?username=hello&age=20
2. POST - HTML Form : 메세지 바디에 쿼리 파라미터 형식으로 전달 username=hello&age=20
- content-type : application/x-www-form-urlencoded
3. HTTP message body에 직접 데이터를 담아서 요청 - API에서 주로 사용하며 주로 JSON
- POST, PUT, PATCH
요청 파라미터 조회법
1. request.getParameter() - HttpServletRequest가 제공하는 방식
2. @RequestParam("username") - 좀 더 편리하게 값을 꺼내올 수 있음, 파라미터 이름이 같으면 생략 가능
@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");
}
@ResponseBody
@RequestMapping("/request-param-v2")
public String requestParamV2(
@RequestParam("username") String memberName,
@RequestParam("age") int memberAge){
log.info("username={}, age={}", memberName, memberAge);
return "ok";
}
@ResponseBody
@RequestMapping("/request-param-v3")
public String requestParamV3(
@RequestParam String username,
@RequestParam int age){
log.info("username={}, age={}", username, age);
return "ok";
}
@ResponseBody
@RequestMapping("/request-param-v4")
public String requestParamV4(String username, int age){
log.info("username={}, age={}", username, age);
return "ok";
}
- @RequestParam(required = false)
required는 파라미터 필수 여부이다. 기본값은 true이다.
주의점은 기본형에 null 입력이 안되므로 @RequestParam(required = false) int age 같은 경우에는 예외 발생할 수 있음
@ResponseBody
@RequestMapping("/request-param-required")
public String requestParamRequired(
@RequestParam(required = true) String username,
@RequestParam(required = false) Integer age){
log.info("username={}, age={}", username, age);
return "ok";
}
@ResponseBody
@RequestMapping("/request-param-default")
public String requestParamDefault(
@RequestParam(required = true, defaultValue = "guest") String username,
@RequestParam(required = false, defaultValue = "-1") int age){
log.info("username={}, age={}", username, age);
return "ok";
}
3. Map으로 조회하기
- Map 또는 MultiValueMap으로 조회 가능
@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";
}
4. @ModelAttribute
객체를 받는 방법도 가능하다. @ModelAttribute는 다음 두가지 기능을 가진다.
1. 요청 파라미터 처리 : 객체를 생성하고 요청 파라미터값을 프로퍼티 접근법(setXX)로 입력해줌
2. Model 추가 : @ModelAtrribute 어노테이션이 달린 객체를 자동으로 모델에 넣어줌. 이때 이름을 바꿀 수도 있는 데 다음과 같이 하면 된다.
@ModelAttribute("hello") Item item : 이름을 hello로 지정하면
model.addAttribute("hello", item); 모델에 hello 이름으로 저장(이 코드가 자동으로 실행됨)
*이름을 생략하면 클래스이름의 제일 앞글자를 소문자로만 바꿔서 저장 ex) Item -> item
@ResponseBody
@RequestMapping("/model-attribute-v1")
public String modelAttributeV1(@ModelAttribute HelloData helloData) {
log.info("username={}, age={}", helloData.getUsername(), helloData.getAge());
return "ok";
}
//@ModelAttribute도 생략이 가능하나 명확성을 위해 권장하진 않는다고 한다.
@ResponseBody
@RequestMapping("/model-attribute-v2")
public String modelAttributeV2(HelloData helloData) {
log.info("username={}, age={}", helloData.getUsername(), helloData.getAge());
return "ok";
}
스프링은 해당 생략시 다음과 같은 규칙을 적용한다.
String , int , Integer 같은 단순 타입 = @RequestParam
나머지 = @ModelAttribute (argument resolver 로 지정해둔 타입 외)
메세지 바디 조회 - 단순 텍스트
v1. InputSream 사용을 통해 읽기 가능
@PostMapping("/request-body-string-v1")
public void requestBodyStringV1(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");
}
v2. InputStream을 파라미터로 바로 받아올 수 있음
@PostMapping("/request-body-string-v2")
public void requestBodyStringV2(InputStream inputStream, Writer responseWriter) throws IOException {
String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
log.info("messageBody={}", messageBody);
responseWriter.write("ok");
}
v3. HttpEntity 사용
- httpEntity.getBody(), httpEntity.getHeaders()로 바디, 헤더 정보를 편리하게 조회할 수 있음
- 응답에도 사용 가능 : 응답으로 HttpEntity를 바로 반환하면 됨
@PostMapping("/request-body-string-v3")
public HttpEntity<String> requestBodyStringV3(HttpEntity<String> httpEntity) throws IOException {
String messageBody = httpEntity.getBody();
log.info("messageBody={}", messageBody);
return new HttpEntity<>("ok");
}
v4. @RequestBody 사용
주의: 요청 파라미터를 조회하는 @RequestParam, @ModelAttribute와는 관련없음
@ResponseBody
@PostMapping("/request-body-string-v4")
public String requestBodyStringV4(@RequestBody String messageBody) throws IOException {
log.info("messageBody={}", messageBody);
return "ok";
}
* @ResponseBody : 이걸 달아주면 String으로 바로 응답 결과를 HTTP 메시지 바디에 담아서 전달할 수 있다.
메세지 바디 조회 - JSON
v1. ObjectMapper 사용 : objectMapper를 사용하여 객체로 변환 가능
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");
}
v2. @RequestBody 사용(사실상 단순 텍스트 복습)
@PostMapping("/request-body-json-v2")
public String requestBodyJsonV2(@RequestBody String messageBody) throws IOException {
log.info("messageBody={}", messageBody);
HelloData helloData = objectMapper.readValue(messageBody, HelloData.class);
log.info("username={}, age={}", helloData.getUsername(), helloData.getAge());
return "ok";
}
3. @RequestBody에 객체 파라미터를 바로 지정해줄 수 있다.
**@RequestBody는 생략불가: @ModelAttribute와 혼동될 수 있음
@ResponseBody
@PostMapping("/request-body-json-v3")
public String requestBodyJsonV3(@RequestBody HelloData helloData) {
log.info("username={}, age={}", helloData.getUsername(), helloData.getAge());
return "ok";
}
4. HttpEntity도 당연히 사용 가능
@ResponseBody
@PostMapping("/request-body-json-v4")
public String requestBodyJsonV4(HttpEntity<HelloData> httpEntity) {
HelloData data = httpEntity.getBody();
log.info("username={}, age={}", data.getUsername(), data.getAge());
return "ok";
}
5. @ResponseBody를 달아주면 해당 객체를 바로 HTTP 메시지 바디에 넣어서 전달해줄 수 있음
@ResponseBody
@PostMapping("/request-body-json-v5")
public HelloData requestBodyJsonV5(@RequestBody HelloData helloData) {
log.info("username={}, age={}", helloData.getUsername(), helloData.getAge());
return helloData;
}
작동 방식 정리
@RequestBody : JSON 요청 - (HTTP메시지 컨버터) -> 객체
@ResponseBody : 객체 - (HTTP메시지 컨버터) -> JSON 응답
---------------
참고: 인프런 김영한님 강의(스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술)
댓글