개발/Java|Spring

스프링 HTTP 헤더와 요청 파라미터 조회하는 방법

달리초이 2023. 4. 10. 15:10

 

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 의 사용 가능한 파라미터 목록 공식 메뉴얼

 

Web on Servlet Stack

Spring Web MVC is the original web framework built on the Servlet API and has been included in the Spring Framework from the very beginning. The formal name, "Spring Web MVC," comes from the name of its source module (spring-webmvc), but it is more commonl

docs.spring.io

 

- @Conroller 의 사용 가능한 응답 값 목록 공식 메뉴얼

 

Web on Servlet Stack

Spring Web MVC is the original web framework built on the Servlet API and has been included in the Spring Framework from the very beginning. The formal name, "Spring Web MVC," comes from the name of its source module (spring-webmvc), but it is more commonl

docs.spring.io

 

- 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를 사용하지 않는다

 

 

 

 

[참고]

스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 - 김영한

728x90
반응형