데이터 request 방식을 완벽히 이해하지 못한 나는 계속해서 이 부분에서 문제가 생겼다.


코드에서는 이상이 없는데 Postman에서 반환하려고 하면 오류가 뜸.
해결 1. url을 코드에서 쓴 것처럼 ' /{id} '라고 하면 안되고 '/:id' 라고 해야한다.
해결2. 코드에서 변수를 @RequestBody가 아니라 @PathVariable라고 했기 때문에 Body영역이 아니라 Params 영역에서 Value에 작성해야한다.

그러면 정상적으로 반환이 되는 걸 확인할 수 있다.
선택한 일정 조회, 일정 수정, 삭제 시 id와 password를 받는데 그 때 PathVariable 방식을 썼던 걸 문제점을 파악하고 RequestBody로 변경해 바디값 안에 넣어주려고 했다.


그래서 처음엔 단순히 이렇게 @RequestBody로 변경하고 Postman으로 찍어봤는데


.w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type 'java.lang.Long' from Object value (token 'JsonToken.START_OBJECT')]
어떤 방법으로 해도 이런 에러가 찍혀서 내가 body 값에 넣는 방식이 문제인 줄 알고 많이 헤멨다.
그리고! RequestBody의 사용법을 다시 공부해본 결과
HTTP Body에 JSON 데이터를 담아 서버에 전달할 때 해당 Body 데이터를 Java의 객체로!!!! 전달 받는다는 것을 알게 됐다.



코드 수정 후 일정 수정, 삭제가 잘 구현이 되는 것을 볼 수 있다.
그리고 코드 수정하면서 알게 된 것은 한 메서드에 여러개의 @RequestBody를 선언하는 것은 불가능하다. 이걸 모르고 두개를 사용해 Postman에 어떻게 두개를 작성해서 넣을지 고민했던 내가 너무 모자르다...
오케이! 문제는 해결했고!
데이터 받는 법 다시 공부한다!
크게 param, query, body 방식이 있다.
서버에 보내려는 데이터를 URL 경로에 추가할 수 있다.
/star/{name}/age/{age} 이처럼 URL 경로에서 데이터를 받고자 하는 위치의 경로에 {data} 중괄호를 사용.(@PathVariable String name, @PathVariable int age)// [Request sample]
// GET http://localhost:8080/hello/request/star/Robbie/age/95
@GetMapping("/star/{name}/age/{age}")
@ResponseBody
public String helloRequestPath(@PathVariable String name, @PathVariable int age)
{
return String.format("Hello, @PathVariable.<br> name = %s, age = %d", name, age);
}
@RequestParam 어노테이션을 활용하면, Request Header에 Parameter를 넣어서 전달해준다. 이로써 알 수 있는 것은 @RequestParam 어노테이션이 없어도 Spring에서 각 인자에 맞는 Object를 매핑해주어 전달해주는 것을 알 수 있다.
? 와 & 를 사용하여 추가할 수 있다.// [Request sample]
// GET http://localhost:8080/hello/request/form/param?name=Robbie&age=95
@GetMapping("/form/param")
@ResponseBody
public String helloGetRequestParam(@RequestParam String name, @RequestParam int age) {
return String.format("Hello, @RequestParam.<br> name = %s, age = %d", name, age);
}
param?name=Robbie&age=95
?name=Robbie&age=95 에서 key 부분에 선언한 name과 age를 사용하여 value에 선언된 Robbie, 95 데이터를 받아올 수 있다.(@RequestParam String name, @RequestParam int age)name=Robbie&age=95 형태로 담겨져서 서버로 전달된다. 해당 데이터를 받는 방법은 앞서 본 방법 처럼 @RequestParam 애너테이션을 사용하여 받아올 수 있다.// [Request sample]
// POST http://localhost:8080/hello/request/form/param
// Header
// Content type: application/x-www-form-urlencoded
// Body
// name=Robbie&age=95
@PostMapping("/form/param")
@ResponseBody
public String helloPostRequestParam(@RequestParam String name, @RequestParam int age) {
return String.format("Hello, @RequestParam.<br> name = %s, age = %d", name, age);
}
@RequestParam(required = false)
- 이렇게 required 옵션을 false로 설정하면 Client에서 전달받은 값들에서 해당 값이 포함되어있지 않아도 오류가 발생하지 않는다.
- @PathVariable(required = false) 도 해당 옵션이 동일하다.
- Client로 부터 값을 전달 받지 못한 해당 변수는 null로 초기화된다.
✔️ 우선 데이터를 Java의 객체로 받아올 때 주의할 점!
- 해당 객체의 필드에 데이터를 넣어주기 위해 set or get 메서드 또는 오버로딩된 생성자가 필요하다.
- 예를 들어 @ModelAttribute 사용하여 데이터를 받아올 때 해당 객체에 set 메서드 혹은 오버로딩된 생성자가 없다면 받아온 데이터를 해당 객체의 필드에 담을 수 없다.
- 이처럼 객체로 데이터를 받아올 때 데이터가 제대로 들어오지 않는다면 우선 해당 객체의 set or get 메서드 또는 오버로딩된 생성자의 유무를 확인하기!
name=Robbie&age=95 형태로 담겨져서 서버로 전달된다.Star star 받아올 객체를 선언한다.// [Request sample]
// POST http://localhost:8080/hello/request/form/model
// Header
// Content type: application/x-www-form-urlencoded
// Body
// name=Robbie&age=95
@PostMapping("/form/model")
@ResponseBody
public String helloRequestBodyForm(@ModelAttribute Star star) {
return String.format("Hello, @ModelAttribute.<br> (name = %s, age = %d) ", star.name, star.age);
}
?name=Robbie&age=95 처럼 데이터가 두 개만 있다면 괜찮지만 여러 개 있다면 @RequestParam 애너테이션으로 하나 씩 받아오기 힘들 수 있다.Star 객체가 생성되고, 오버로딩된 생성자 혹은 Setter 메서드를 통해 요청된 name & age 의 값이 담겨진다.// [Request sample]
// GET http://localhost:8080/hello/request/form/param/model?name=Robbie&age=95
@GetMapping("/form/param/model")
@ResponseBody
public String helloRequestParam(@ModelAttribute Star star) {
return String.format("Hello, @ModelAttribute.<br> (name = %s, age = %d) ", star.name, star.age);
}
✔️ @ModelAttribute는 생략이 가능!
이때, Spring에서는 @ModelAttribute뿐만 아니라 @RequestParam도 생략이 가능하다.
Spring이 이를 구분하는 방법은 간단하게 설명하면 Spring은 해당 파라미터(매개변수)가 SimpleValueType(예를 들어 원시타입(int), Wrapper타입(Integer), Date등의 타입)이라면 @RequestParam으로 간주하고 아니라면 @ModelAttribute가 생략되어있다 판단한다.
@RequestBody 어노테이션을 활용하면, Request Body에 Data를 넣어서 전달해준다.
HTTP Body에 JSON 데이터를 담아 서버에 전달할 때 해당 Body 데이터를 Java의 객체로 전달 받을 수 있다.
HTTP Body에 {"name":"Robbie","age":"95"} JSON 형태로 데이터가 서버에 전달되었을 때 @RequestBody 애너테이션을 사용해 데이터를 객체 형태로 받을 수 있다.
✔️ 민감한 정보는 이런 식으로 PathVariable 보다는 body 값안에 넣어주는 것이 좋다. url은 모든 사람이 쉽게 볼수 있고 기록이 다 남는데 비밀번호 아이디가 들어가면 누구나 쉽게 정보를 탈취할수 있기 때문이다.
// [Request sample]
// POST http://localhost:8080/hello/request/form/json
// Header
// Content type: application/json
// Body
// {"name":"Robbie","age":"95"}
@PostMapping("/form/json")
@ResponseBody
public String helloPostRequestJson(@RequestBody Star star) {
return String.format("Hello, @RequestBody.<br> (name = %s, age = %d) ", star.name, star.age);
}