컨트롤러 클래스를 지정함으로써, 요청과 관련된 메서드를 처리할 수 있게된다.
메서드의 반환 값이 String일 경우, view 이름으로 인식하여 view가 렌더링 된다.
@Controller
public class MappingController {
@RequestMapping("/hello-basic")
public String helloBasic() {
//hello-basic 이라는 이름의 view를 찾아 반환한다.
return "hello-basic";
}
@Controller
와 같은 기능을 제공한다. 다만, 차이점이 존재한다.
반환 값이 String일 경우, view를 찾는 것이 아닌 HTTP message body에 바로 입력된다.
@RestController
public class MappingController {
@RequestMapping("/hello-basic")
public String helloBasic() {
return "ok";
}
특정 URL로 요청이 들어왔을 때, 처리할 메서드를 지정한다.
@RequestMapping
은 두 가지 방식으로 지정할 수 있다.
@RestController
@RequestMapping("/mapping/users")
public class MappingClassController
@RequestMapping("/hello-basic")
public String helloBasic() {
return "ok";
}
기본적으로
@RequestMapping
은 모든 HTTP 메서드가 허용된다.
(GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE)
@RequestMapping(value = "/users", method = RequestMethod.GET)
위와 같이 method 속성을 통해 특정 HTTP 메서드를 지정할 수 있으나,
Spring은 아래와 같은 축약 annotation을 지원한다.
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
이들 또한 @RequestMapping
과 동일한 방식으로 URL 경로를 지정하여 사용한다.
만일 localhost:8080/users/{userId}
localhost:8080/orders/{orderId}
와 같이 URL 경로에 변수를 사용하고 싶다면 어떻게 해야할까?
@PathVariable
을 통해 URL의 일부를 메서드의 파라미터로 전달한다.
즉, URL 경로에 있는 변수 값을 메서드에서 활용할 수 있다.
@GetMapping("/{userId}")
public String findUser(@PathVariable("userId") String userId) {
return "get userId = " + userId;
}
이때, @PathVariable
의 이름과 parameter의 이름이 같으면 생략 가능하다.
@GetMapping("/{userId}")
public String findUser(String userId) {
return "get userId = " + userId;
}
클라이언트에서 서버로 데이터를 전달하는 방식은 주로 다음 3가지 방법을 사용한다.
GET
쿼리 파라미터 형식/url?username=kdh&age=8
POST
HTML form 형식POST /html-form ...
Content-Type : application/x-www-form-urlencoded
username=kdh&age=8
POST /body-json ...
Content-Type : application/json
{
"username" : "kdh",
"age" : "20"
}
GET 쿼리 파라미터와 POST HTML form은 데이터의 형식이 같으므로, 구분없이 조회할 수 있다.
이를 요청 파라미터(request param) 조회라고 한다.
요청 파라미터 조회 방식은 상황에 따라
@RequestParam
@ModelAttribute
중 하나를 사용한다.
HTTP message body를 통해 데이터가 직접 넘어오는 경우는 요청 메시지라고 한다.
요청 메시지 조회 방식은 @RequestBody
를 사용한다.
세 가지 annotation을 하나씩 알아보자.
단일 요청 파라미터의 값을 메서드의 변수에 바인딩 할 때 사용한다.
이때 기본 타입은 int
Long
String
LocalDateTime
List<>
등을 포함한다.
@ResponseBody
@RequestMapping("/request-param-v2")
public String requestParamV2(@RequestParam("username") String username,
@RequestParam("age") Integer age) {
log.info("username={}, age={}", username, age);
return "ok";
}
이때, 파라미터의 이름과 메서드 변수의 이름이 동일하면,
아래와 같이 파라미터의 이름은 생략 가능하다.
@ResponseBody
@RequestMapping("/request-param-v2")
public String requestParamV2(@RequestParam String username,
@RequestParam Integer age) {
log.info("username={}, age={}", username, age);
return "ok";
}
이때, 변수의 type이 int
Long
String
LocalDateTime
List<>
등의
기본 타입인 경우 @RequestParam
또한 생략 가능하다.
다만, 명료성이 떨어지는 이유로 추천하지 않는 방법이다.
우리는 개발을 할 때, 요청 파라미터의 값을 어떠한 객체에 바인딩 해야한다.
앞선 @RequestParam
을 통해 다음과 같이 작성할 수 있다.
@ResponseBody
@RequestMapping("/model-attribute-v1")
public String modelAttributeV1(@RequestParam String username,
@RequestParam Integer age) {
HelloData data = new HelloData();
data.setUsername(username);
data.setAge(age);
return "ok";
}
그러나, 이 과정을 완전히 자동화해주는 괴물이 있다.
@ModelAttribute
는 객체를 생성하고, 요청 파라미터 값을 객체의 필드에 바인딩할 때 사용한다.
@ResponseBody
@RequestMapping("/model-attribute-v2")
public String modelAttributeV1(@ModelAttribute HelloData data) {
log.info("data={}", data);
return "ok";
}
이때, 변수의 type이 기본 타입이나 argument resolver로 지정해둔 타입이 아닌 경우, @ModelAttribute
또한 생략 가능하다.
그러나 @RequestParam
과 같은 이유로 추천하지 않는다.
HTTP message body를 직접 조회하여 객체를 생성하고, 요청 메시지를 객체의 필드에 바인딩할 때 사용한다.
@ResponseBody
@PostMapping("request-body-json-v5")
public HelloData requestBodyJsonV5(@RequestBody HelloData data) {
log.info("username={}, age={}", data.getUsername(), data.getAge());
return data;
}
앞서 살펴본 @ModelAttribute
와 다루는 데이터의 형식이 다를 뿐,
매우 유사하게 동작한다는 것을 알 수 있다.
앞선 예시 코드에서 계속 등장한 @ResponseBody
의 역할은 무엇일까?
해당 메서드의 반환값을 HTTP message body에 넣는다.
위에서 살펴본 @RestController
가 클래스 수준에서 사용되었다면,
@ResponseBody
는 메서드 수준에 적용된다는 차이를 지닌다.
우와아