기존의 MVC controller
- 지금까지의 Controller는 스트링(view로지컬 네임)을 리턴
RESTful Web Service Controller
- 객체를 리턴
-> 객체는 JSON/XML포멧으로 Http Response의 Body부분에 담겨서 리턴된다.
-> Spring에서 REST API 구현을 위해 알아야 할 것들
- @RestController, @RequestBody, @PathVariable, ResponseEntity(자료구조)
※ 이제 JSON형태로 파싱하고 넘겨주고 해야 하기 때문에 프런트 엔드 부분도 개발할 필요가 있다.
※ Http response의 구성요소
- Status Line : status Code
- header
- Body
1. @ResponseBody Annotation
- @ResponseBody를 사용하면 Controller는 View를 거치지않고 바로 Client에게 객체(HTTP responseBody에 Json포맷 형태로 넣어서)를 넘겨준다.
-> 따라서 프론트엔드부분은 이 Json포맷을 파싱 할 수 있도록 해주어야 한다. - @ResponseBody가 있다면 Spring은 리턴되는 값을 HTTP response body에 담는다.
- serialization : 자바 시스템 내부에서 사용되는 객체 또는 data를 외부 시스테에서 이용할 수 있도록 byte 형태로 데이터를 변환하는 기술 (객체의 내용들이 줄 서서 보내는 방법 )
- 객체의 내용들을 Responsebody에 담는 것
->반대는 Deserialization - 객체의 내용들을 Responsebody에 담기 위해서 Message Converter를 사용한다.
- 객체의 내용들을 Responsebody에 담는 것
- 예시코드
@Controller
@RequestMapping("/rest/user")
public class UserResources {
@RequestMapping("/{userId}")
public @ResponseBody User getUserById (@PathVariable(value = "userId") int userId) {
return userService.getUserById(userId);
}
}
- @ResponseBody -> Spring 3. 대 부터 지원
- 리턴하는 정보(User 정보)를 ResponseBody부분에 Json포맷으로 넣어준다.
2. @RestController Annotation
- @Controller와 @ReponseBody 두 어노테이션을 안다면 이 두 어노테이션을 합친 어노테이션
- 편의성을 위해 - 이 어노테이션을 달면 이제 @ResponseBody를 메서드에 안 달아도 된다.
-> Spring 4. 대 부터 지원
- 예시 코드
@RestController
@RequestMapping("/rest/cart")
public class UserResources {
@RequestMapping("/{userId}")
public User getUserById (@PathVariable(value = "userId") int userId) {
return userService.getUserById(userId);
}
}
- @RequestMapping 안에 {}으로 되어 있는 변수를 template variable이라고 한다.
- @RequestMapping("/{userId}") ----------------↓같은 것을 찾고 @PathVariable 어노테이션이 달린 변수(int userId)에 값을 넣어준다.
3. ResponseEntity <T> class
- ResponseEntity 클래스를 이용하면 http response 구성요소 3가지를 전부 다룰 수가 있다.
-> 이 클래스의 생성자(Constructor)를 사용하여 다루면 됨.
Constructor | Description |
ResponseEntity(HttpStatus statusCode) | 상태 코드만 사용 |
ResponseEntity(MultiValueMap<String,String> headers, HttpStatus statusCode) | 헤더와 상태코드만 사용 |
ResponseEntity(T body, HttpStatus statusCode) | 바디와 상태코드만 사용 |
ResponseEntity(T body, MultiValueMap<String,String> headers, HttpStatus statusCode) | 바디, 헤더, 상태코드 전부 사용 |
- 예시 코드
@RestController
@RequestMapping("/api")
public class RestApiController {
@Autowired
UserService userService;
@RequestMapping(value = "/users", method = RequestMethod.GET)
public ResponseEntity<List<User>> listAllUsers() {
List<User> users = userService.findAllUsers();
if (users.isEmpty()) {
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<List<User>>(users, HttpStatus.OK);
}
}
- 리턴으로 new를 사용하여 생성자를 만든 다음 인자로 적절할 값들을 넣어주면 어려 생성자들을 이용할 수 있다. 여기서는 유저가 존재하는 경우 받아온 유저들과 상태 값 두 가지를 넣어 생성자를 만들어 리턴해 주었다.
4. @RequestBody Annotation
- Spring은 Http request를 @RequestBody가 달린 이름이 같은 객체에다가 바인딩해준다.
-> deserialization - 예시 코드
@RequestMapping(value = "/users", method = RequestMethod.POST)
public ResponseEntity<Void> createUser(@RequestBody User user,
UriComponentsBuilder ucBuilder) {
if (userService.isUserExist(user)) {
throw new UserDuplicateException(user);
}
userService.saveUser(user);
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ucBuilder.path("/api/users/{id}").
buildAndExpand(user.getId()).toUri());
return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
}
- Spring, Hibernate가 만든 예외처리도 있지만 위와 같이 내가 예외처리를 만들 수도 있다.
(Custom exception)
-> if (userService.isUserExist(user)) {
throw new UserDuplicateException(user);
}
Spring MVC 4 RESTFul Web Service
- 필요한 의존성: jackson-databind -> 이 라이브러리가 messageConverter를 제공해준다.
<!-- jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.5</version>
</dependency>
- 예시 코드
@RestController
@Requestmapping("/api")
public class RestApiController {
@Autowired
UserService userService;
//Retrieve All Users
@RequestMapping(value = "/users", method = RequestMethod.GET)
public ResponseEntity<List<User>> listAllUsers(){
List<User> users = userSerivce.findAllUser();
if(users.isEmpty()){
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<List<User>> (users, Httpstatus.OK);
}
//Update a User
@RequestMapping(value= "/users/{id}", method = RequestMethod.PUT)
public ResponseEntity<User> updateUser(@PathVariable("id") long id, @RequestBody User user) {
User currentUser = userService.findById(id);
if(currentUser == null) {
throw new UserNotFoundException(id);
}
currentUser.setName(user.getName());
currentUser.setAge(user.getAge());
currentUser.setSalary(user.getSalary());
userService.updateUser(currentUser);
return new ResponseEntity<User>(currentUser, HttpStatus.OK);
}
}
References
https://www.genuitec.com/spring-frameworkrestcontroller-vs-controller/
'Spring > 이론' 카테고리의 다른 글
JPQL (0) | 2020.05.17 |
---|---|
SpringBoot (0) | 2020.04.22 |
Restful Web Service (0) | 2020.04.19 |
Hibernate with Spring (0) | 2020.04.19 |
Entity Relationships (0) | 2020.04.17 |
댓글