실제 개발을 하면 요청 파라미터를 받아서 필요한 객체를 만들고 그 객체에 값을 넣어 주어야 한다.
보통은 아래 코드 처럼 작성할 것이다
@RequestParam String username;
@RequestParam int age;
HelloData data = new HelloData();
data.setUsername(username);
data.setAge(age);
스프링은 이 과정을 완전히 자동화해주는 @ModelAttribute
기능을 제공한다.
먼저 요청 파라미터를 바인딩 받을 객체를 만들자
경로 : hello.springmvc.basic
package hello.springmvc1.basic;
import lombok.Data;
@Data
public class HelloData {
private String username;
private int age;
}
롬복 @Data
@Getter
, @Setter
, @ToString
, @EqualsAndHashCode
,@RequiredArgsConstructor
를 자동으로 적용해준다./**
* @ModelAttribute 사용
* 참고 : model.addAttribute(helloData) 코드도 함께 자동 적용됨, 뒤에 model을 설명할 때 자세히 설명
*/
@ResponseBody
@RequestMapping("/model-attribute-v1")
public String modelAttributeV1(@ModelAttribute HelloData helloData){
log.info("username={},age={}", helloData.getUsername(), helloData.getAge());
return "ok";
}
마치 마법처럼 HelloData
객체가 생성되고, 요청 파라미터의 값도 모두 들어가 있다.
스프링 MVC는 @ModelAttribute
가 있으면 다음을 실행한다.
HelloData
객체를 생성한다.HelloData
객체의 프로퍼티를 찾는다. 그리고 해당 프로퍼티의 setter를 호출해서 파라미터의 값을 입력(바인딩)한다.username
이면 setUsername()
메서드를 찾아서 호출하면서 값을 입력한다.객체에 getUsename()
, setUsername()
메서드가 있으면, 이 객체는 username
이라는 프로퍼티를 가지고 있다.
username
프로퍼티의 값을 변경하면 setUsername()
이 호출되고, 조회하면 getUsername()
이 호출 된다.
class HelloData{
getUsername();
setUsername();
}
age=abc
처럼 숫자가 들어가야 할 곳에 문자를 넣으면 BindException
이 발생한다. 이런 바인딩 오류를 처리하는 방법은 검증 부분에서 다룬다.
/**
* @ModelAttribute 생략 가능
* String, int 같은 단순 타입 = @RequestParam
* argument resolver 로 지정해둔 타입 외 = @ModelAttribute
*/
@ReponseBody
@RequestMapping("/model-attribute-v2")
public Stirng modelAttributeV2(HelloData helloData){
log.info("username={}, age={}",helloData.getUsernaem(),helloData.getAge());
return "ok";
}
@ModelAttribute
는 생략할 수 있다.
그런데 @RequestParam
도 생략할 수 있으니 혼란이 발생할 수 있다.
스프링은 해당 생략시 다음과 같은 규칙을 적용한다.
String
,int
,Integer
같은 단순 타입 = @RequestParam
@ModelAttribute
(argument resolver 로 지정해둔 타입 외)🤞 참고 )
argument resolver는 뒤에서 학습한다.
서블릿에서 학습한 내용을 떠올려 보자.
HTTP message body에 데이터를 직접 담아서 요청
요청 파라미터와 다르게, HTTP 메세지 바디를 통해 데이터가 직접 넘어오는 경우는 @RequestParam
,@ModelAttribute
를 사용할 수 없다. (물론 HTML Form 형식으로 전달되는 경우는 요청 파라미터로 인정된다.)
먼저 가장 단순한 텍스트 메세지를 HTTP 메세지 바디에 담아서 전송하고 읽어보자
HTTP 메세지 바디의 데이터를 InputStream
을 사용해서 직접 읽을 수 있다.
@Slf4j
@Controller
public class RequestBodyStringController{
@PostMapping("/request-body-string-v1")
public void requestBodyString(HttpServletRequest request, HttpServletResponse response) throws IOException{
ServletInputStream inputSteam = request.getInputStream();
String messageBody = StreamUtils.coptToString(inputStream, StandardCharsets.UTF_8);
log.info("messageBody={}",messageBody);
response.getWriter().write("ok");
}
}
Postman을 사용해서 테스트 해보자
POST http://locahost:8080/request-body-string-v1
Body -> row,Text 선택
/**
* InputStream(Reader) : HTTP 요청 메시지 바디의 내용을 직접 조회
* OoutputStream(Writer) : HTTP 응답 메시지 바디에 직접 결과 출력
*/
@PostMapping("/request-body-string-v2")
public void requestBodyStringV2(InputStream inputSteam , Writer responseWriter) throws IOException{
String messageBody = StreamUtils.copyToString(imputSteam, StandardCharsets.UTF_8);
log.info("messageBody={}",messageBody);
responseWriter.write("ok");
}
스프링 MVC는 다음 파라미터를 지원한다.
/**
* HttpEntity : HTTP header, body 정보를 편리하게 조회
* - 메시비 바디 정보를 직접 조회(@RequestParam X, @ModelAttribute X)
* - HttpMessageConverter 사용 -> StringHttpMessageConverter 적용
*
* 응답에서도 HttpEntity 사용 가능
* - 메세지 바디 정보 직접 반환 (view 조회 x)
* - HttpMessageConverter 사용 -> StringHttpMessageConverter 적용
*
*/
@PostMapping("/request-body-string-v3")
public HttpEntity<String> requestBodyStringV3(HttpEntity<String> httpEntity){
String messageBody = httpEntity.getBody();
log.info("messageBody ={}",messageBody);
return new HttpEntity<>("ok");
}
HttpEntity : Http header,body 정보를 편리하게 조회
@RequestParam
X, @ModelAttribute
XHttpEntity
를 상속받은 다음 객체들도 같은 기능을 제공한다.
RequestREntity
ResponseEntity
return new ResponseEntity<String>("Hello World",responseHeaders,HttpStatus.CREATED)
🤞참고 )
스프링 MVC 내부에서 HTTP 메세지 바디를 읽어서 문자나 객체로 변환해서 전달해주는데, 이때 HTTP 메세지 컨버터(HttpMessageConverter
)라는 기능을 사용한다. 이것은 조금 뒤에 HTTP 메세지 컨버터에서 자세히 설명
/**
*@RequestBody
* - 메세지 바디 정보를 직접 조회 (@RequestParam X, @ModelAttribute X)
* - HttpMessageConverter 사용 -> StringHttpMessageConverter 적용
*
*@ResponseBody
*- 메세지 바디 정보 직접 반환(view 조회 X)
*- HttpMessageConverter 사용 -> StringHttpMessageConverter 적용
*/
@ResponseBody
@PostMapping("/request-body-sting-v4")
public String requestBodyStringV4(@RequestBody String messageBody){
log.info("messageBody={},messageBody);
return "ok";
}
@RequestBody
@RequestBody
를 사용하면 HTTP 메세지 바디 정보를 편리하게 조회할 수 있다.
참고로 헤더 정보가 필요하다면 @RequestHeader
를 사용하면 된다.
이렇게 메세지 바디를 직접 조회하는 기능은 요청 파라미터를 조회하는 @RequestParam
. @ModelAttribute
와는 전혀 관계 없다.
요청 파라미터를 조회하는 기능 : @RequestParam
, @ModelAttribute
Http 메세지 바디를 직접 조회하는 기능 : @RequestParam
@ResponseBody
@ResponseBody
를 사용하면 응답 결과를 HTTP 바디에 직접 담아서 전달할 수 있다.
물론 이 경우에도 view를 사용하지 않는다.