본문 바로가기

Backend/Spring & SpringBoot

[Spring] 스프링에서의 Restful web Service

728x90

Restful web service를 스프링에서 어떻게 구현할 수 있을까?


기존의 Spring 방식은 밑의 방식과 같다.

 

request를 받으면 Dispatcher Servlet이 받고, Handler Mapping을 통해 어떤 컨트롤러로 보낼지 결정해서 Service, DAO를 거쳐 View를 만들어 다시 Response로 Client로 보내주는 방식이였다.


Controller는 단순히 object(객체)를 return한다.

이 object data(객체데이터)가 json/xml 형태로 HTTP response 메시지에 담겨서 전달이 된다. 

 

@RestController, @RequestBody, ResponseEntity class, @PathVariable을 통해 REST API를 구현하게 된다.

 

1) @ResonseBody 어노테이션

@Controller
@RequestMapping("/rest/cart")
public class CartResources {

   @RequestMapping("/{cartId}")
   public @ResponseBody  Cart getCartById (@PathVariable(value = "cartId") int cartId) {
        return cartService.getCartById(cartId);
   }
}

 

- return되는 Cart가 ResponseBody에 담아서 넣어주게 된다. 

- spring 3 부터 지원이됨.

- return 하는 객체는 json 형태로 serialize해준다.

 

2) @RestController 어노테이션

@RestController
@RequestMapping("/rest/cart")
public class CartResources {

   @RequestMapping("/{cartId}")
   public Cart getCartById (@PathVariable(value = "cartId") int cartId) {
        return cartService.getCartById(cartId);
   }
}

- spring 4.0 에서 추가됨.

- @Controller + @ResponseBody 라고 보면된다. -> @ResponseBody안써두되고, @RestController만 달아주면 된다.

 

3) @PathVariable 어노테이션

@RestController
@RequestMapping("/rest/cart")
public class CartResources {

   @RequestMapping("/{cartId}")
   public Cart getCartById (@PathVariable(value = "cartId") int cartId) {
        return cartService.getCartById(cartId);
   }
}

- @RequestMapping("/{cartId}") 에 cartId에 넣어줌

 

4) ResponseEntity <T> class

- status code, headers, body 이렇게 3가지의 내용을 Response에 담아야하는데 그걸 담아주는 객체가 ResponseEntity 이다. 

- 밑의 표처럼 몇가지 생성자가 있다.

Constructor Description
ResponseEntity
(HttpStatus status)
Create a new ResponseEntity with the given status code, and no body nor headers.
ResponseEntity
(MultiValueMap<String,String> headers, HttpStatus status)
Create a new ResponseEntity with the given headers and status code, and no body.
ResponseEntity
(T body, 
HttpStatus status)
Create a new ResponseEntity with the given body and status code, and no headers.
ResponseEntity
(T body, 
MultiValueMap<String,String> headers, 
HttpStatus status)
Create a new ResponseEntity with the given body, headers, and status code.
@RestController
@RequestMapping("/api")
public class RestApiController {

  @Autowired
  private 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);
  }
}

5) @RequestBody 어노테이션

- client가 정보를 보낼때 json형태로 보내는데 이것을 받아서 Deserialization해서 필드에 넣어주기를 원함. 

=> 그렇게 스프링에게 하도록 해주는 것이 @RequestBody 어노테이션이라고 보면된다.

 

@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);
}

1) REST API 정의 

HTTP Method URI Operation
GET /api/users returns a list of users
GET /api/users/1 returns the user with ID 1
POST /api/users creates a new user
PUT /api/users/3 updates the user with ID 3
DELETE /api/users/4 deletes the user with ID 4
DELETE /api/users deletes all the users

 

2) Dependencies 추가

<!-- jackson-databind -->
<dependency>
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-databind</artifactId>
   <version>2.10.0</version>
</dependency>

 

3) Rest Client (Postman)

Rest Client

 

4) CRUD 과정

@RestController // @Controller + @ResponseBody
@RequestMapping("/api")
public class RestApiController {

	@Autowired
	UserService userService;
	
	//Retrieve All Users 
	@GetMapping(value ="/users")
	public ResponseEntity<List <User>> listAllUsers(){//status, header, body
		
		List<User> users = userService.findAllUsers();
		
		if(users.isEmpty()) {
			return new ResponseEntity<>(HttpStatus.NO_CONTENT);
		}
		return new ResponseEntity<List<User>>(users, HttpStatus.OK);
		//body(json), status
	}
	
	@GetMapping(value ="/users/{id}")
	public ResponseEntity<User> getUser(@PathVariable("id") long id){
		User user = userService.findById(id);
		if(user == null) {
			//to do list: custom exception
			throw new UserNotFoundException(id);
		}
		return new ResponseEntity<User>(user, HttpStatus.OK);
	}
	
	//Create a User
	@PostMapping(value="/users")
	public ResponseEntity<Void> createUser(@RequestBody User user, UriComponentsBuilder ucBuilder){
		
		//중복확인
		if(userService.doesUserExist(user)) {
			//to do list: exception
			throw new UserDuplicatedException(user.getName());
		}
		userService.saveUser(user);
		
		HttpHeaders headers = new HttpHeaders();
		headers.setLocation(ucBuilder.path("/api/users/{id}").buildAndExpand(user.getId()).toUri());
		//헤더에 location을 준다.
		return new ResponseEntity<>(headers, HttpStatus.CREATED);
	}
	
	//Update a User
	@PutMapping(value="/users/{id}")
	public ResponseEntity<User> updateUser(@PathVariable("id") long id, @RequestBody User user){
		User currentUser = userService.findById(id);
		
		if(currentUser == null) {
			//to do list: custom exception
			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);
	}
	
	@DeleteMapping(value="/users/{id}")
	public ResponseEntity<Void> deleteUser(@PathVariable("id") long id){
		User user = userService.findById(id);
		if(user == null) {
			//to do list: custom exception
			throw new UserNotFoundException(id);
		}
		userService.deleteUserById(id);
		return new ResponseEntity<>(HttpStatus.NO_CONTENT);
	}
	
	@DeleteMapping(value="/users")
	public ResponseEntity<Void> deleteAllUser(){
		userService.deleteAllUsers();
		return new ResponseEntity<>(HttpStatus.NO_CONTENT);
	}
}
728x90