Spring/SpringMVC

HTTP 요청 파라미터 - @ModelAttribute & 단순 텍스트

느리지만 꾸준하게 2022. 4. 29. 23:34

스프링은 요청 파라미터를 받아서 필요한 객체를 만들어주고 객체에 값을 넣어주는 @ModelAttribute 기능을 제공한다.

 

 

 

요청 파라미터를 바인딩 받을 객체를 만들어 보면

// HelloData

package hello.springmvc.basic;


import lombok.Data;

@Data
public class HelloData {
    private String username;
    private int age;
}

 

  • 롬복 @Data
    @Getter , @Setter , @ToString , @EqualsAndHashCode , @RequiredArgsConstructor 를
    자동으로 적용해준다.

 

 

 

request 패키지의 RequestParamController에서 아래와 같이 지정해주고 돌려주면 로그가 잘 찍히는 것을 볼 수 있다.

@ResponseBody
@RequestMapping("/model-attribute-v1")
public String modelAttrubuteV1(@RequestParam String username, @RequestParam int age) {
    HelloData helloData = new HelloData();
    helloData.setUsername(username);
    helloData.setAge(age);

    log.info("username={}, age={}", helloData.getUsername(), helloData.getAge());
    log.info("helloData={}", helloData);

    return "ok";
}
2022-04-29 22:36:28.575  INFO 33348 --- [nio-8080-exec-2] h.s.b.request.RequestParamController     : username=hello, age=20
2022-04-29 22:36:28.578  INFO 33348 --- [nio-8080-exec-2] h.s.b.request.RequestParamController     : helloData=HelloData(username=hello, age=20)

 

 

더 간단하게 나타내보자.

@ResponseBody
@RequestMapping("/model-attribute-v1")
public String modelAttrubuteV1(@ModelAttribute HelloData helloData) {
    log.info("username={}, age={}", helloData.getUsername(), helloData.getAge());
    return "ok";
}
2022-04-29 22:38:17.860  INFO 33378 --- [nio-8080-exec-1] h.s.b.request.RequestParamController     : username=hello, age=20

 

  • 스프링 MVC는 `@ModelAttrubute`가 있으면 아래를 실행하는데
  • `HelloData`객체를 생성하고
  • 요청 파라미터의 이름으로 `HelloData`객체의 프로퍼티를 찾는다. 해당 프로퍼티의 setter를 호출해서 파라미터의 값을 입력으로 한다.
  • 예) 파라미터 이름이 username 이면 setUsername() 메서드를 찾아서 호출하면서 값을 입력한다

 

프로퍼티

객체에 getUsername(), setUsername() 메서드가 있으면, 이 객체는 username이라는 프로퍼티를 가지고 있고

username 프로퍼티의 값을 변경하면 setUsername()이 호출이 되고, 조회하면 getUsername()이 호출이 된다.

class HelloData {
getUsername();
setUsername();
}

 

 

바인딩 오류

2022-04-29 22:45:26.209  WARN 33378 --- [nio-8080-exec-5] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.validation.BindException: org
  • age=abc 처럼 숫자가 들어가야 할 곳에 문자를 넣으면 BindException 이 발생한다.

 

 

 

 

@ModelAttribute을 생략 해보자.

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

2022-04-29 22:48:40.510  INFO 33516 --- [nio-8080-exec-2] h.s.b.request.RequestParamController     : username=hello, age=10

 

  • @ModelAttribute는 생략할 수 있다.
  • @RequestParam도 생략 가능하니 주의하자.

아래 규칙을 스프링에선 적용한다.

  • String , int , Integer 같은 단순 타입 = @RequestParam
  • 나머지 = @ModelAttribute (argument resolver 로 지정해둔 타입 외)

 

 

 

 

 

 

HTTP 요청 메시지 - 단순 텍스트에 대해서 알아보자.

 

  • 먼저 가장 단순한 텍스트 메시지를 HTTP 메시지 바디에 담아서 전송하고, 읽어보자.
  • HTTP 메시지 바디의 데이터를 InputStream 을 사용해서 직접 읽을 수 있다.

RequestBodyStringController을 만들어주고

 

Postman으로 test를 해보자.

// RequestBodyStringControllr Class

package hello.springmvc.basic.request;


import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.PostMapping;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

@Slf4j
@Controller
public class RequestBodyStringController {

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

2022-04-29 23:03:52.289  INFO 33770 --- [nio-8080-exec-3] h.s.b.r.RequestBodyStringController      : messageBody=hello

 

 

 

 

 

Input, Output 스트림, Reader - requestBodyStringV2로 더 간단하게 나타내면

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

2022-04-29 23:07:43.062  INFO 33826 --- [nio-8080-exec-2] h.s.b.r.RequestBodyStringController      : messageBody=hello

 

  • 스프링 MVC는 다음 파라미터를 지원한다.
  • InputStream(Reader): HTTP 요청 메시지 바디의 내용을 직접 조회
  • OutputStream(Writer): HTTP 응답 메시지의 바디에 직접 결과 출력

 

 

 

 

 

 

 

 

 

 

 

 

HttpEntity - requestBodyStringV3로 코드를 더욱더 간단하게 해보자.

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

2022-04-29 23:14:21.034  INFO 33921 --- [nio-8080-exec-1] h.s.b.r.RequestBodyStringController      : messageBody=hello

 

스프링 MVC는 다음 파라미터를 지원한다.

  • HttpEntity: HTTP header, body 정보를 편리하게 조호;
  • 메시지 바디 정보를 직접 조회
  • 요청 파라미터를 조회하는 기능과 관계 없음 @RequestParam x, @ModelAttribute X

 

  • HttpEntity는 응답에도 사용 가능
  • 메시지 바디 정보 직접 반환
  • 헤더 정보 포함 가능
  • view 조회 x

 

HttpEntity 를 상속받은 다음 객체들도 같은 기능을 제공한다.

  • RequestEntity
  • HttpMethod, url 정보가 추가, 요청에서 사용

 

  • ResponseEntity
  • HTTP 상태 코드 설정 가능, 응답에서 사용
  • return new ResponseEntity<String>("Hello World", responseHeaders,
    HttpStatus.CREATED)

 

 

이렇게 ResponseEntity로 나타내면 상태코드가 201로 postman에서 결과를 확인할 수 있다.

@PostMapping("/request-body-string-v3")
public HttpEntity<String> requestBodyStringV3(HttpEntity<String> httpEntity) throws IOException {

    String messageBody = httpEntity.getBody();
    log.info("messageBody={}", messageBody);

    return new ResponseEntity<>("ok", HttpStatus.CREATED);
}

 

 

 

 

@RequestBody - requestBodyStringV4로 더욱 더 간단하게 나타낼 수가 있다.

@ResponseBody
@PostMapping("/request-body-string-v4")
public String requestBodyStringV4 (@RequestBody String messageBody) {

    log.info("messageBody={}", messageBody);

    // @ResponseBody가 있으면 http 응답코드에 딱 넣는다.
    return "ok";
}

2022-04-29 23:28:24.209  INFO 34129 --- [nio-8080-exec-1] h.s.b.r.RequestBodyStringController      : messageBody=hello

 

@RequestBody

  • @RequestBody를 사용하면 HTTP 메시지 바디 정보를 편리하게 조회할 수 있다. 참고로 헤더 정보가 필요하면 HttpEntity를 사용하거나 @RequestHeader를 사용하면 된다.
  • 이렇게 메시지 바디를 직접 조회하는 기능은 요청 파라미터를 조회하는 @RequestParam, @ModelAttrubute와 전혀 관계가 없다.

 

요청 파라미터 vs HTTP 메시지 바디

  • 요청 파라미터를 조회하는 기능: @RequestParam , @ModelAttribute
  • HTTP 메시지 바디를 직접 조회하는 기능: @RequestBody

 

 

@ResponseBody

  • ResponseBody를 사용하면 응답 결과를 HTTP 메시지 바디에 직접 담아서 전달할 수 있다.
  • 이 경우에 view를 사용하지 않는다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

<출처 김영한: 스프링 MVC 1편 - 벡앤드 웹 개발 핵심 기술>

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

 

스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 - 인프런 | 강의

웹 애플리케이션을 개발할 때 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. 스프링 MVC의 핵심 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니다., -

www.inflearn.com