[REST] RESTful Service 구현방법 #2(SpringBoot와 RESTFUL Service)
RESTFul Service 구현방법 #1
RESTFul 서비스를 SpringBoot를 통해서 구현하기 때문에 기본적인 어노테이션에 대해서는 학습 필요
1장. SpringBoot 어노테이션 간단 설명
@RestController : 일반적인 Controller와 달리 response를 자동으로 JSON 타입으로 반환
@RestController //자동으로 JSON 타입으로 반환
public class HelloWorldController {
}
일반 Controller를 사용할 경우 아래처럼 @ResponseBody를 붙여주면 @RestController와 동일한 결과 발생
@Controller
public class HelloWorldController{
@GetMapping(path="/hello-world")
@ResponseBody
public String helloWorld(){
}
}
@GetMapping : Get호출이 들어오는 것을 처리하는 어노테이션
// GET(/hello-world)
// 옛날 방식 : @RequestMapping(method=RequestMethod.GET, path="/hello-world")
@GetMapping(path="/hello-world")
public String helloWorld(){
return "Hello World";
}
객체 타입 반환 방법 : 반환 타입에 객체(Object) 넣어주고 return을 해당 객체로 반환
@GetMapping(path="/hello-world-bean")
public HelloWorldBean helloWorldBean(){
return new HelloWorldBean("Hello World");
}
================================================================
@Data //Data만 해주면 모든 프로퍼티에 대한 세터, 게터, 투스트링 만들어진다
@AllArgsConstructor //모든 아규먼트를 가진 생성자를 만든다
@NoArgsConstructor //아규먼트가 없는 기본 생성자를 만든다
public class HelloWorldBean {
private String message;
}
================================================================
@PathVariable : URI에 변수가 들어가는 부분
@GetMapping(path="/hello-world-bean/path-variable/{name}")
//path-variable {name} 이름과 파라미터 name 일치. 만약 다를경우 value="name" 설정 필요
public HelloWorldBean helloWorldBean(@PathVariable String name){
return new HelloWorldBean(String.format("Hello World, %s", name));
}
/*
TEST URL : http://localhost:8088/hello-world-bean/path-variable/icehotchoco
=> RESULT : "message": "Hello World, giyeonPak"
*/
2장. UserDaoService 구현
SpringBoot에서 사용할 Service 간단 구현
@Service
public class UserDaoService {
//비즈니스 로직 = service
private static List<User> users = new ArrayList<>();
private static int usersCount = 3;
static {
users.add(new User(1, "Gildong", new Date()));
users.add(new User(2, "Gildong", new Date()));
users.add(new User(3, "Gildong", new Date()));
}
public List<User> findAll(){
return users;
}
public User save(User user){
if(user.getId() == null){
user.setId(++usersCount);
}
users.add(user);
return user;
}
public User findOne(int id){
for(User user : users){
if(user.getId() == id){
return user;
}
}
return null;
}
public User deleteById(int id){
Iterator<User> iterator = users.iterator();
while(iterator.hasNext()){
User user = iterator.next();
if(user.getId() == id){
iterator.remove();
return user;
}
}
return null;
}
}
3장. SpringBoot UserController 구현
생성자 주입 방식 : 위에서 만들었던 UserDaoService 주입
@RestController
public class UserController {
private UserDaoService service;
public UserController(UserDaoService service){
this.service = service;
}
}
RESTFul API 구현
@GetMapping(“/users”)
@GetMapping("/users")
public List<User> retriveAllUsers(){
return service.findAll();
}
@GetMapping(“/users/{id}”) - 기본방식
// GET /users/1 or /users/10
// 기본적으로 String 타입이 들어오지만 (아래와 같이 int id)를 해주면 자동으로 int로 변환
@GetMapping("/users/{id}")
public User retrieveUser_temp(@PathVariable int id){
return service.findOne(id);
}
@GetMapping(“/users/{id}”) - 에러처리 추가
@GetMapping("/users/{id}")
public User retrieveUser(@PathVariable int id){
User user = service.findOne(id);
if(user == null){
throw new UserNotFoundException(String.format("[ID[%s] not found]", id));
//이렇게만 하면 500번 에러로 message에 첨부되서 넘어간다.
}
return user;
}
================================================================
//새로운 예외클래스 생성
@ResponseStatus(HttpStatus.NOT_FOUND) //400번대 에러 -> 사용자가 찾는 ID가 없다는 에러(클라이언트)
public class UserNotFoundException extends RuntimeException {
public UserNotFoundException(String message) {
super(message);
}
}
================================================================
@PostMapping(“/users”) - 기본 방식
@PostMapping("/users")
public void createUser(@RequestBody User user){
//Post, PUT Method에서 클라이언트에서 Form과 같은 데이터를 XML, JSON
//같은 데이터를 받기 위해서는 RequestBody 필요(자동으로 매핑)
User savedUser = service.save(user);
}
[주의사항] : 포스트맨으로 사용시 POST방식에 Body는 raw 선택 후 JSON 타입으로 전송
Content type ‘text/plain;charset=UTF-8’ not supported] 에러발생시 type을 text 아니라 json으로 전송해야 한다
@PostMapping(“/users”) - 에러처리 추가 + ResponseEntity 사용방법
@PostMapping("/users")
public ResponseEntity<User> createUser(@RequestBody User user){
User savedUser = service.save(user);
//이렇게 상태값을 전송해주는 방법이 REST API에서는 굉장히 중요하다
URI location = ServletUriComponentsBuilder.fromCurrentRequest()
.path("/{id}")
.buildAndExpand(savedUser.getId())
.toUri();
return ResponseEntity.created(location).build();
/**
* Response Entity 사용이유
* 이렇게 사용해주면 POSTMAN에서 요청후에 Header 정보에 클라이언트에서는 알 수 없었던
* 서버에서 생성한 id값을 넘겨주게 되는데
* id 값을 받았으니, 클라이언트는 id값을 알기위해 새로 서버에 요청할 필요가 없어지니까
* 네트워크 트래픽 감소와 효율성을 높일 수 있다
*/
//안좋은 REST API 케이스 : 클라이언트의 모든 요청을 POST로 사용하면서 응답코드는 200번만 받는 경우.
//REST는 용도별로 나눠서 GET, POST, PUT, DELETE 사용하며 응답코드도 꼭 같이 리턴해주면서 상태값을
//확인 할 수 있게 해주자(200번 X , 201번 O)
}
@DeleteMapping(“/users/{id}”) - 예외처리 추가
@DeleteMapping("/users/{id}")
public void deleteUser(@PathVariable int id){
User user = service.deleteById(id);
if(user == null){
throw new UserNotFoundException(String.format("[ID[%s] not found]", id));
}
}
4장. 예외처리 구현
ExceptionResponse 객체 구현 : 앞으로 발생하는 예외는 이 객체에 데이터를 담아서 반환(에러 확인이 편함)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ExceptionResponse { //모든 예외처리는 이걸로 사용 + AOP 적용
private Date timestamp;
private String message;
private String details;
}
Handler 구현 : ControllerAdvice 사용해서 모든 수행과정을 Handler를 통해서 예외처리 할 수 있게
@RestController //1. 웹서비스 사용
@ControllerAdvice //2. 모든 컨트롤러가 실행될때 자동으로 사용되게 되며 에러가 발생할 경우 Handler를 사용
public class CustomizedResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(Exception.class) //모든 예외가 발생하면 아래 메소드 수행
public final ResponseEntity<Object> handleAllExceptions(Exception ex, WebRequest request){
ExceptionResponse exceptionResponse = new ExceptionResponse(new Date(), ex.getMessage(), request.getDescription(false));
return new ResponseEntity(exceptionResponse, HttpStatus.INTERNAL_SERVER_ERROR);
//INTERNAL_SERVER_ERROR = 500번 에러
//(서버에서 발생할 수 있는 가장 일반적인 에러)
}
//에러 발생시 아래처럼 에러정보 표시(훨씬 간단하며 모든 에러처리 가능)
/*
{
"timestamp": "2023-01-28T02:04:39.889+00:00",
"message": "[ID[100] not found]",
"details": "uri=/users/100"
}
*/
@ExceptionHandler(UserNotFoundException.class) //특정 에러가 발생하면 아래 메소드 수행
public final ResponseEntity<Object> handleUserNotFoundException(Exception ex, WebRequest request){
ExceptionResponse exceptionResponse = new ExceptionResponse(new Date(), ex.getMessage(), request.getDescription(false));
return new ResponseEntity(exceptionResponse, HttpStatus.NOT_FOUND); //NOT_FOUND = 400번 에러(사용자가 찾는 ID가 없다는 에러)
}
}
참고
댓글남기기