본문 바로가기
Spring/이론

Restful Web Service with Spring

by 모스키토끼 2020. 4. 20.

기존의 MVC controller

- 지금까지의 Controller는 스트링(view로지컬 네임)을 리턴

기존 MVC 구조

RESTful Web Service Controller

- 객체를 리턴

-> 객체는 JSON/XML포멧으로 Http Response의 Body부분에 담겨서 리턴된다.
-> Spring에서 REST API 구현을 위해 알아야 할 것들

  • @RestController, @RequestBody, @PathVariable, ResponseEntity(자료구조)

RESTful Web Service, @ResponseBody

※ 이제 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를 사용한다.
  • 예시코드
@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. 대 부터 지원 

@Controller + @ResponseBody

  • 예시 코드
@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 Framework: @RestController vs @Controller - Genuitec

In the Spring framework, a key difference between a traditional MVC and the RESTful web service controller is the way the HTTP response body is created.

www.genuitec.com

https://docs.spring.io/spring/docs/3.0.5.RELEASE/javadoc-api/org/springframework/http/ResponseEntity.html

 

ResponseEntity

 

docs.spring.io

 

'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

댓글