1. @Controller에서 헤더 정보 가져오기
헤더 정보가 필요한 경우가 많은데 스프링 @Controller에는 파라미터를 통해 헤더뿐만 아니라 많은 정보를 가져올 수 있다. 사실 자주 사용하는 것만 기억나고 가끔 쓰게 되는 건 찾아보게 된다. 아래 공식 매뉴얼 참고.
@RequestMapping("/headers")
public String headers(
HttpServletRequest reqeust,
HttpServletResponse response,
HttpMethod httpMethod, // method 정보
Locale locale, // 위치 정보
@RequestHeader MultiValueMap<String, String> headerMap, // 모든 헤더 정보
@RequestHeader("host") String host, // 개별 헤더 정보
@CookieValue(value = "myCookie", required = false) String cookie // 개별 쿠키 정보
) {
return "파라미터로 여러가지 헤더 정보를 받을 수 있습니다.";
}
* MultiValueMap : Map과 유사한데, 하나의 키에 여러 값을 받을 수 있다. 헤더에는 하나의 키로 여러 개의 값을 넣을 수 있기 때문에 받을 때도 MultiValueMap을 이용하는 게 좋다.
MultiValueMap<String, String> map = new LinkedMultiValueMap();
map.add("keyA", "value1");
map.add("keyA", "value2");
// [value1, value2]
List<String> values = map.get("keyA");
- @Conroller 의 사용 가능한 파라미터 목록 공식 메뉴얼
- @Conroller 의 사용 가능한 응답 값 목록 공식 메뉴얼
- Lombok의 @Slf4j 를 사용하면 아래 코드 자동 생성.
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(해당 클래스명.class);
2. 요청 파라미터
Get method로 쿼리 파라미터가 전달되거나, Post method로 HTML Form 형식의 데이터가 넘어올 때 파라미터를 조회하는 방법을 알아보자. 대충 봐도 이해가 될 정도로 쉽지만, 한참 지나면 사소한 부분이 헷갈리기도 한다.(내가..)
2-1. @RequestParam
- 파라미터 이름과 변수명을 다르게 쓰는 경우
public void foo(
@RequestParam("username") String memberName,
@RequestParam("age") int memberAge
) {}
- 파라미터 이름을 생략할 수 있지만, 파라미터 이름과 변수명이 같아야 함.
public void foo(
@RequestParam String username,
@RequestParam int age
) {}
- String, int, Integer 등 단순 타입이면 @RequestParam 애노테이션도 생략 가능.
- 하지만 스프링이 익숙하지 않은 팀원을 고려한다면 명시적으로 넣는 것을 추천.
public String foo(String memberName, int memberAge) {}
- 파라미터 필수 여부를 옵션으로 넣을 수 있음. 기본값은 true.
- '/request-param?username=' 처럼 파라미터 이름만 있고 값이 없는 경우엔 빈문자로 통과한다.
- 주의! 기본형(primitive) 타입에 null 이 들어가지 않도록 주의하고 필요하다면 wrapper 클래스를 사용하거나 defalutValue를 넣어준다.
public void foo(
@RequestParam(required = true) String username, // 생략하면 true
@RequestParam(required = false) Integer age // int 타입은 null이 오면 500에러
) {}
public void foo(
@RequestParam(defaultValue="guest") String username,
@RequestParam(defaultValue="-1") int age
) {}
- defaultValue가 있다면 값이 있든 없든 기본값이 들어가므로 required 조건이 의미없음.
- 참고로 username이 위에서 언급했던 것처럼 빈문자로 들어와도 defaultValue 설정값이 들어감.
2-2. @RequestParam을 Map으로 조회하기
public void foo(@RequestParam Map<String, Object> paramMap) {
paramMap.get("key1");
paramMap.get("key2");
}
- MultiValueMap으로도 조회할 수 있다. (이렇게 들어올 경우: '?userId=1&userId=2")
2-3. @ModelAttribute
- @RequestParam으로 받을 수 있지만, @ModelAttribute 애노테이션을 이용해 모델 클래스로 직접 바인딩 할 수 있다.
@Data
private class User {
private String name;
private int age;
}
// '/foo?name=keesun&age=20' 요청이 들어오면
public void foo(@ModelAttribute User user) {
// user.name, user.age 바인딩
}
- @ModelAttribute 도 생략 가능
// '/foo?name=keesun&age=20' 요청이 들어오면
public void foo(User user) {
// user.name, user.age 바인딩
}
- 스프링은 해당 생략시 다음과 같은 규칙을 적용한다.
- String, int, Integer 같은 단순 타입 = "@RequestParam"
- 나머지 = "@ModelAttribute" (HttpServeltRequest 등 argument resolver로 지정해둔 타입 제외)
3. HTTP 요청 메시지
요청 Body에 담긴 데이터를 조회할 때는 @RequestParam이나 @ModelAttribute로 하지 않는다. 바디를 직접 조회할 땐 HttpServletRequest.getInputStream()을 이용해서 스트림 데이터를 가져와 StreamUtils.copyToString() 등 변환을 직접 해서 사용할 수도 있다. 하지만 스프링은 이런 번거로운 과정을 HttpEntity<>나 @RequestBody 통해 쉽게 조회할 수 있도록 도와준다.
- InputStream을 직접 받는 경우
@PostMapping("/request-body-string-v2")
public void requestBodyString(InputStream inputStream, Writer responseWriter)
throws IOException {
String messageBody = StreamUtils.copyToString(inputStream,
StandardCharsets.UTF_8);
log.info("messageBody={}", messageBody);
responseWriter.write("ok");
}
- HttpEntity 로 받으면 자동으로 변환해 준다.(내부에서 HttpMessageConverter라는 컨버터 기능을 사용한다.)
- header, body 정보를 편리하게 조회할 수 있다.
- 메시지 바디 정보 직접 반환
- HttpEntity를 상속받은 RequestEntity, ResponseEntity 객체들도 같은 기능을 제공한다.
@PostMapping("/request-body-string-v3")
public HttpEntity<String> requestBodyString(HttpEntity<String> httpEntity) {
String messageBody = httpEntity.getBody();
log.info("messageBody={}", messageBody);
return new HttpEntity<>("ok");
}
- @RequestBody
- 참고로 헤더 정보가 필요하다면 HttpEntity 를 사용하거나 @RequestHeader 를 사용하면 된다.
- 이렇게 메시지 바디를 직접 조회하는 기능은 요청 파라미터를 조회하는 @RequestParam, @ModelAttribute 와는 전혀 관계가 없다.
- 직접 만든 객체를 지정할 수 있다. 문자 뿐만 아니라 JSON도 객체로 변환해준다.
- @RequestBody를 생략하면 @ModelAttribute로 동작하기 때문에 생략 불가능
@ResponseBody
@PostMapping("/request-body-string-v4")
public String requestBodyString(@RequestBody String messageBody) {
log.info("messageBody={}", messageBody);
return "ok";
}
요청 파라미터 vs HTTP 메시지 바디
- 요청 파라미터를 조회하는 기능: @RequestParam , @ModelAttribute
- HTTP 메시지 바디를 직접 조회하는 기능: @RequestBody
- @ResponseBody
@ResponseBody 를 사용하면 응답 결과를 HTTP 메시지 바디에 직접 담아서 전달할 수 있다. 물론 이 경우에도 view를 사용하지 않는다
[참고]
'개발 > Java|Spring' 카테고리의 다른 글
스프링 핵심원리 기본 - IoC, DI, ApplicationContext, 의존관계 주입 등 (0) | 2023.04.06 |
---|---|
좋은 객체 지향 설계의 5가지 원칙 SOLID (0) | 2023.03.29 |
Builder 패턴과 Lombok @Builder 사용 시 주의사항 (0) | 2023.02.20 |
대량 이미지 동일한 사이즈로 분할하기(JAVA) (0) | 2023.02.13 |
JWT 토큰 라이브러리 java-jwt와 jjwt 간단 비교 (0) | 2023.02.09 |