Spring

[Spring]HTTP 요청을 Controller에서 받는 방법

마닐라 2022. 6. 6. 13:22

Spring은 편리하게 HTTP 요청을 받을 수 있도록 도와준다.

Servlet을 이용하는 방법과 Spring이 제공해주는 기능을 이용하는 버전을 차례대로 알아본다.

 

HTTP 요청 - 기본, 헤더 조회

HttpMethod - HTTP 메서드를 조회한다. 

Locale - Locale 정보를 조회한다.

@RequestHeader MultiValueMap<String, String> headerMap - 모든 HTTP 헤더를 MultiValueMap 형식으로 조회한다.

@RequestHeader("host") String host - 특정 HTTP 헤더를 조회한다.

@CookieValue(value = "myCookie") String cookie - 특정 쿠키를 조회한다.

 

HTTP 요청 파라미터 - 쿼리 파라미터, HTML Form

클라이언트에서 서버로 요청 데이터를 전달할 때는 주로 다음 3가지 방법을 사용한다.

GET - 쿼리 파라미터

POST - HTML Form (message body에 쿼리 파라미터)

HTTP message body (message body에 JSON, XML, TEXT을 담고 주로 JSON 사용)

 

1. HttpServletRequest가 제공하는 request.getParameter() 사용

HTTP 요청 파라미터는 무조건 문자열로 들어오므로 위의 방식은 불필요한 타입변환이 필요하다.

@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"));
}

 

2.1 @RequestParam 사용

불필요한 타입 변환이 사라진다. -> 스프링이 ConversionService을 이용하여 타입 변환을 해줌

@ResponseBody
@RequestMapping("/request-param-v2")
public String requestParamV2(
        @RequestParam("username") String memberName,
        @RequestParam("age") int memberAge) {

    log.info("username={}, age={}", memberName, memberAge);
    return "ok";
}

 

2.2 HTTP 파라미터 이름이 변수의 이름과 같으면 @RequestParam(name="xx") 생략 가능

@ResponseBody
@RequestMapping("/request-param-v3")
public String requestParamV3(
        @RequestParam String username,
        @RequestParam int age) {

    log.info("username={}, age={}", username, age);
    return "ok";
}

 

2.3 String, int, Integer 등의 단순 타입이면 @RequestParam도 생략 가능

아래 방식은 정상적으로 2.1의 코드와 동일한 동작을 하지만 다 생략해버렸기에 너무 과한 면도 있다.

@ResponseBody
@RequestMapping("/request-param-v4")
public String requestParamV4(String username, int age) {
    log.info("username={}, age={}", username, age);
    return "ok";
}

 

2.4 @RequestParam을 Map으로 조회

@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";
}

 

3.1 @ModelAttribute 사용

아래 방식은 요청 파라미터를 받아서 필요한 객체를 만들고 그 객체에 값을 자동으로 넣어준다.

@ResponseBody
@RequestMapping("/model-attribute-v1")
public String modelAttributeV1(@ModelAttribute HelloData helloData) {
    log.info("username={}, age={}", helloData.getUsername(), helloData.getAge());
    return "ok";
}

 

아래의 작업을 대신해주는 것과 같다.

@RequestParam String username;
@RequestParam int age;

HelloData data = new HelloData();
data.setUsername(username);
data.setAge(age);

 

3.2 @ModelAttribute는 생략할 수 있다.

@ResponseBody
@RequestMapping("/model-attribute-v2")
public String modelAttributeV2(HelloData helloData) {
    log.info("username={}, age={}", helloData.getUsername(), helloData.getAge());
    return "ok";
}


@RequestParam도 생략할 수 있으니 혼란이 발생할 수 있다.

따라서 어노테이션 정도는 붙여주자.

 

HTTP 요청 메세지 - 단순 텍스트

요청 파라미터와 다르게 HTTP 메세지 바디를 통해 데이터가 직접 넘어오는 경우 @RequestParam, @ModelAttribute를 사용할 수 없다. (물론 HTML Form 형식으로 메세지 바디로 전달되는 경우는 요청 파라미터로 인정된다.)

 

1.HttpServletRequest가 제공하는 request.getInputStream() 사용

@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");
}

 

2.HttpEntity<T> 사용

바로 읽을 수 있다. -> 스프링이 HttpMessageConverter을 이용하여 타입 변환을 해줌

@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");
}

 

3.@RequestBody 사용

@ResponseBody
@PostMapping("/request-body-string-v4")
public String requestBodyStringV4(@RequestBody String messageBody) {
    log.info("messageBody={}", messageBody);
    return "ok";
}

 

헤더 정보가 필요하다면 HttpEntity를 사용하거나 @RequestHeader를 사용하면 된다.

 

HTTP 요청 메세지 - JSON

1.HttpServletRequest가 제공하는 request.getInputStream() 사용후 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");
}

 

2.@RequestBody를 사용하고 ObjectMapper를 이용하여 객체 변환

@ResponseBody
@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에 객체를 직접 지정하여 바로 변환

@ResponseBody
@PostMapping("/request-body-json-v3")
public String requestBodyJsonV3(@RequestBody HelloData data) {
    log.info("username={}, age={}", data.getUsername(), data.getAge());
    return "ok";
}

 

4.HttpEntity<T> 사용

@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";
}

 

출처

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1