어노테이션에 대해 배워서 기본적인 스프링의 어노테이션에 대해 정리해보려고 한다.
@Controller
의 경우 반환 값이 String이면 뷰 이름으로 인식한다. 그래서 뷰를 찾고 뷰가 랜더링된다.
반면에 @RestContoller
의 반환 값으로 뷰를 찾는게 아니라 Http 메시지 바디에 바로 입력한다.
@RestController
public class MappingController{
@RequestMapping("/mapping")
public String mappingMethod(){
return "ok"; // Http 메시지 바디에 입력
}
}
@RequestMapping
은 URL 매핑에 사용되는 어노테이션이다.
method 속성에 Http 메서드를 지정하지 않으면 GET, POST, PUT 등 모든 Http 메서드가 허용된다.(좋은 설계는 아님)
@RequestMapping("/mapping") // 모든 Http 메서드 허용
public String mappingMethod(){
return "ok";
}
@RequestMapping(value = "/mapping2", method = RequestMethod.GET) // GET 메서드만 허용
public String mappingMethod(){
return "ok";
}
REST API 설계를 위해서 스프링에서 다음과 같은 Http 메서드 매핑을 지원하고 있다.
사실 Http 메서드 어노테이션을 뜯어보면 다음과 같다.
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(method = RequestMethod.GET) // 쨘
public @interface GetMapping {
...
}
@GetMapping
에서 @RequestMapping(method = RequestMethod.GET)
을 찾아볼 수 있다!
@RequestMapping
은 URL 경로를 템플릿화할 수 있는데, @PathVariable
을 함께 사용하면 매칭되는 부분을 편리하게 조회할 수 있다.
만약 http://localhost:8080/mapping/users/userA/orders/10 이라면
@GetMapping("/mapping/users/{userId}/orders/{orderId}")
에서 userId: users, orderId: 10에 매핑된다.
여기에 @PathVariable
을 사용하면 변수에 매핑해서 사용할 수 있다.
@GetMapping("/mapping/users/{userId}/orders/{orderId}")
//public String mappingPath(@PathVariable("userId") String userId, @PathVariable("orderId") Long orderId)
// 변수명 같으면 생략가능
public String mappingPath(@PathVariable String userId, @PathVariable Long orderId) {
log.info("mappingPath userId={}, orderId={}", userId, orderId);
return "ok";
}
HTML 테스트용 Form은 다음과 같다.
<form action="/request-param" method="post">
username: <input type="text" name="username" />
age: <input type="text" name="age" />
<button type="submit">전송</button>
</form>
위의 HTML Form으로 http://localhost:8080/request-param?username=value1&age=value2 URL를 얻을 수 있다.
파라미터의 값을 @RequestParam
을 통해 변수에 매핑시킬 수 있다.
여기서도 변수명이랑 같으면 생략 가능하다.
@ResponseBody //@ResponseBody에 return 값을 바로 적어준다.(@RestController와 비슷)
@RequestMapping("/request-param")
public String requestParamV2(
// @RequestParam("username") String username,
// @RequestParam("age") int age) {
// 생략 가능
@RequestParam String username,
@RequestParam("age") int age) {
log.info("username={}, age={}", username, age);
return "ok";
}
여기서 @RequestParam
도 생략할 수 있는데, 가독성을 위해서 남겨두는 것도 좋다.
@RequestParam
은 required 속성은 기본값이 true
이다.
만약 required 속성을 false
로 준다면 기본형(primitive)에 null이 입력될 수 있기 때문에 주의해야한다.
이런 경우를 방지하기 위해서 Integer
같은 Wrapper 클래스를 사용하거나 defaultValue 속성을 제공해야한다.
@ResponseBody
@RequestMapping("/request-param-default")
public String requestParamDefault(
@RequestParam(required = true, defaultValue = "guest") String username,
@RequestParam(required = false, defaultValue = "-1") int age) {
log.info("username={}, age={}", username, age);
return "ok";
}
defaultValue 속성을 주면 required 속성은 의미가 없어지기 때문에 빼도 관계 없다.
파라미터를 Map, MultiValueMap으로 조회할 수도 있
@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";
}
파라미터의 값이 확실하면 Map을 사용해도 되지만, 그렇지 않다면 MultiValueMap을 사용하면 된다.
보통 Controller에서 파라미터로 받은 값을 객체를 생성한 후 그 객체에 값을 넣어주어 데이터를 다루게 된다.
예를 들어
@Data // Getter, Setter.. 생성해주는 Lombok 라이브러리
public class HelloData {
private String username;
private int age;
}
이렇게 파라미터의 값을 보관할 객체를 위한 클래스를 만들어주고
@ResponseBody
@RequestMapping("/model-attribute-v1")
public String modelAttributeV1(@requestParam String username, int age) {
HelloData data = new HelloData();
data.setUsername(username);
data.setAge(age);
log.info("username={}, age={}", helloData.getUsername(), helloData.getAge());
return "ok";
}
이렇게 객체를 생성하고 그 객체에 파라미터의 값을 보관한 후 사용한다.
하지만 @ModelAttribute
를 사용하면 이런 객체를 생성하고 set 메서드로 값을 저장하는 흐름을 자동으로 해준다.
*/
@ResponseBody
@RequestMapping("/model-attribute-v1")
public String modelAttributeV1(@ModelAttribute HelloData helloData) {
log.info("username={}, age={}", helloData.getUsername(), helloData.getAge());
return "ok";
}
@ModelAttribute
도 아예 생략 가능한데, 이렇게 하면 @requestParam
과 헷갈릴 수 있다.
스프링의 경우 String이나 int, Integer 같은 단순한 타입은 @requestParam
이 적용되고, 직접 만든 객체 타입의 경우 @ModelAttribute
이 적용된다.