(Spring) Controller에서 사용하는 애너테이션
@ModelAttribute / @RequestBody 애너테이션은 웬만하면 붙여주는 편이 명확하다.
- @ModelAttribute를 명시하지 않아도 자동으로 URL 파라미터를 객체로 매핑해주고, GET은 관례적으로 URL 파라미터로 데이터를 전달하기 때문에, 굳이 @ModelAttribute를 사용해야 하느냐 라고 생각할 수 있는데
Controller에서 GetMapping 메서드는 사실 (URL 파라미터/HTTP 바디) 양 쪽 모두 데이터를 받을 수 있다.
- https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Summary_table
- 보면, GET의 경우 Request has Body가 No가 아니라 Optional로 되어 있다.
- POST, PUT도 마찬가지. 관례적으로 Body를 통해서 받지만 URL 파라미터/Body 모두를 사용할 수도 있다.
- 따라서 항상
@ModelAttribute / @RequestBody
를 명시해 주는 편이 좋다.
@RequestParam
queryString이나 form 요청에서 파라미터를 하나 하나 받을 때 사용한다.
1
2
3
4
5
6
7
8
@RequestParam("name")
@RequestParam(value="name", defaultValue="unknown")
// ?name이 없어도 4\*\* 뜨지 않음
@RequestParam(value="name", required=false)
- 파라미터 하나 하나 마다 애너테이션을 적어줘야 하니 여러개를 받을 때는 지저분해져서 부적합하다.
- 여러개를 한번에 받기 위해 아래 처럼 Map으로 받는 방식은 쓰지 않는 것이 좋다.
- 대신 커맨드 객체(+@ModelAttribute)를 사용하자.
1
2
// 아래 방식은 별로다. 커맨드 객체를 쓰자
@RequestParam HashMap<string,string> paramMap
@RequestParam VS @PathVariable
자원 자체를 나타낼 때는 @PathVariable orderBy나, filter 같은 조건을 명시하는 것에는 @RequestParam 근데 깔끔하게 설계가 잘 안되는 경우도 있으니까. 상황에 따라 맞춰서 사용하는 경우도 있음. 포함 관계가 아닐 때가 애매한데, 이는 검색 조건으로 보고 @RequestParam으로 처리하는 것이 매끄러운 것 같기도 함.
@RequestParam이나 @PathVariable이나 파라미터가 너무 많은 경우 Map이나 command 객체 사용 가능
@ModelAttribute
1
2
3
public List<User> getUserList(@ModelAttribute UserSearch userSearch) {
return userService.getUserList(userSearch);
}
- URL 파라미터 또는 POST Form Data 형태의 파라미터를 UserSearch 클래스의 필드들로 매핑해준다.
- 이렇게 자동으로 매핑되어 반환되는 객체를
커맨드 객체 라고 부른다.
- 매핑 rule? ( 여기서 constructor는 @ConstructorProperties와 무관 )
- NoArgsConstructor & AllArgsConstructor 둘 다 있는 경우
- NoArgsConstructor 호출
- setter 호출해서 param 초기화
- AllArgsConstructor만 있는 경우
- AllArgsConstructor 호출해서 param 초기화
- setter 호출해서 param 초기화 (덮어써짐)
- 즉, constructor에도 없고 setter도 없는 필드는 초기화되지 않는다.
- NoArgsConstructor & AllArgsConstructor 둘 다 있는 경우
- Spring 5.2.4 기준 위와 같이 동작한다.
- Spring 4.3.4 기준 반드시 NoArgsConstructor와 Setter가 존재해야만 한다. (No default constructor found;라고 에러 발생.)
- 이런 관점에서도 presentationdto를 반드시 도메인 모델과 분리하는 것이 좋다. ***
@ModelAttribute("query")
와 같이 쓰면 jsp에서query
로 데이터에 접근하도록 지정할 수 있음.
- 이런 관점에서도 presentationdto를 반드시 도메인 모델과 분리하는 것이 좋다. ***
@RequestBody
- 바디를 통해 받은 json 형태의 데이터 를, jackson ObjectMapper 사용해서 바로 객체로 매핑해준다.
- json 형태의 데이터를 받는 용도이기 때문에, form 요청 (application/x-www-form-urlencoded 형태)은 받을 수 없다.
- content-type이 form인데 @RequestBody로 받는 경우 415 Unsupported Media Type 발생
- 매핑 룰은 여기에[Java] Jackson Serialization
@Valid와 Errors
@Valid
를 사용할 때, Errors errors
를 파라미터로 받으면 어떤 항목에서 에러가 발생했는지 메서드 내에서 처리할 수 있다. Valid는 ModelAttribute, RequestBody 모두 동작한다.
DTO 생성 시점에 validation
별도 annotation 도움 없이 생성자나 init block 활용한다.
@RequestAttribute and @SessionAttribute Annotations
https://www.baeldung.com/whats-new-in-spring-4-3#SessionAttribute
기타 Controller와 관련된 애너테이션
@ControllerAdvice
This post is licensed under CC BY 4.0 by the author.