오늘은 PostMapping에 대해 알아보자.
PostMapping을 알아보기 전에, 아래 링크를 타고 들어가서 GetMapping을 먼저 공부하고 오는 것을 추천한다. GetMapping에서 설명한 내용과 중복한 내용들이 꽤 있기 때문이다!
@RestController
@RequestMapping("/api/post")
public class PostController { }
시작하기 앞서, 다음과 같이 Controller를 만들고 경로를 지정해주자.
// http://localhost:8080/api/post/path-variable/{name}
@PostMapping("/path-variable/{name}")
public String pathVariable(@PathVariable String name) {
return name;
}
GET에서 했던 것과 작동 방식은 완전히 동일하다.
마찬가지로 @PathVariable 어노테이션을 사용하면,
name에 파라미터로 넣은 값 "John"이 그대로 전달된다.
근데... POST 방식에서 이렇게 쓸일이 있을까? POST의 핵심은 JSON 형식의 메시지 바디를 서버에 전달하는 것이다. 만약 PathVariable을 사용하더라도 밑에서 배우는 RequestBody와 사용하지, POST에서 PathVariable을 단독으로 사용하는 경우는 흔치 않다. PathVariable이 가능하다는 사실만 알고 넘어가자.
// http://localhost:8080/api/post/request-body
@PostMapping("/request-body")
public String requestBody(@RequestBody String json) {
return json;
}
위에서 말했듯, POST의 핵심은 JSON 형식으로 서버에 데이터를 전달하는 것이다. 따라서, GET처럼 쿼리 스트링으로 파라미터를 전달하는 것이 아닌, HTTP Body 부분에 JSON 형식으로 데이터를 담아주어야 한다. 이 때, 메서드에서 JSON 데이터를 받을 때 반드시 @RequestBody 어노테이션을 사용한다.
위 코드에서는 JSON 형식으로 넘어온 데이터를,
문자열 자료형으로 선언된 메서드 매개변수 json이 받아서 이를 화면에 출력한다.
쓰읍... 문자열로 받기는 조금 애매하니 다른 방법을 고려해보자.
// http://localhost:8080/api/post/request-body/map
@PostMapping("/request-body/map")
public String postMap(@RequestBody Map<String, Object> map) {
StringBuilder sb = new StringBuilder();
map.forEach((key, value) -> sb.append(key).append(": ").append(value).append("\n"));
return sb.toString();
}
GET에서도 사용했던 방법이다. Map Collection으로 JSON 데이터를 받는 것이다. GetMapping 게시글에서도 언급했지만, Map 컬렉션을 사용하는 경우 어떤 파라미터가 넘어오는지 명확하게 알 수 없는 단점이 있다.
역시 최고의 방법은...
public class PostRequest {
private String account;
private String email;
private String address;
private String password;
@JsonProperty("phone_number")
private String phoneNumber;
... (코드 중략) ...
(대충 모든 멤버변수에 getter/setter 만들어져 있는 내용)
}
// http://localhost:8080/api/post/request-body/dto
@PostMapping("/request-body/dto")
public PostRequest post(@RequestBody PostRequest requestData) {
return requestData;
}
String Boot는 정말 현명해서, 특별한 코드를 만들지 않아도 JSON 형식의 데이터와 DTO 객체의 멤버 변수를 매핑해서 대입해준다. 단, 마찬가지로 DTO의 모든 멤버 변수에 getter/setter가 생성되어 있어야 한다.
GET에서는 DTO를 사용하면 메서드 파라미터 앞에 @RequestParam 어노테이션을 붙이지 않아도 되었지만, POST에서는 메서드 파라미터 앞에 @RequestBody 어노테이션이 꼭 붙어있어야 한다.
자 근데, DTO의 phoneNumber 멤버 변수 위에 처음 보는 어노테이션이 붙어 있다?
JSON 데이터의 'Key Value'의 이름과, DTO 객체의 멤버 변수명이 같아야 매핑이 되는데, 전자는 snake_case로, 후자는 CamelCase로 명명이 되어있다. 따라서 case 충돌이 일어나는 DTO 멤버 변수 위에 @JsonProperty 어노테이션을 붙이고, "phone_number"와 같이 매핑할 Key Value의 이름을 적어주면 된다!
변수명 case를 동일하게 맞추는 방법이 또 하나 있는데,
그 방법은 PutMapping 게시글에서 소개하도록 하겠다.
지금 다 설명해버리면... PutMapping에서 할 말이 없어진다😠
참고로, DTO 객체를 그대로 return 해주면,
HTML Body에서 자연스럽게 JSON 형식으로 화면에 출력을 해준다!
이 또한 Spring Boot의 위엄이다...