Spring Boot를 이용한 RESTful Web Services 개발
User Service API 구현
User 도메인 클래스 생성
- User.java 생성 (com.example.restfulwebservice)
@Data
@AllArgsConstructor
public class User {
private Integer id;
private String name;
//private Date joinDate; Date 클래스 미사용
private LocalDateTime joinDate;
}
강의에선 joinDate의 타입을 Date로 지정하였지만 나는 LocalDateTime으로 지정했다.
- UserDaoService.java 생성
- Dao는 DB와 관련된 코드, Service는 비즈니스 로직을 작성하는데 이 예제에선 딱히 구분이 필요 없으므로 합침.
먼저 클래스 맨 위에 @Service 어노테이션을 붙이고, 클래스에 static 변수 두 개를 생성한다.
@Service
public class UserDaoService {
private static List<User> users = new ArrayList<>();
private static int userCount = 0;
}
users는 말 그대로 user 정보를 담는 List이다. userCount는 user의 정보를 구별할 수 있는 id 값이다.
DB에 연동 안하고 간단하게 사용하기 위해 user를 생성해 static 블록으로 메모리에 올린다.
이러면 클래스가 로딩 된 후 static 블록 안에 있는 코드들이 실행되어 users에 3개의 user 정보가 담기게 된다.
static {
users.add(new User( ++userCount, "길동", LocalDateTime.now()));
users.add(new User(++userCount, "영미", LocalDateTime.now()));
users.add(new User(++userCount, "철수", LocalDateTime.now()));
}
그 외 전체 사용자 조회, 사용자 추가, 사용자 조회 비즈니스 로직을 작성한다.
// 전체 사용자 조회
public List<User> findAll() {
return users;
}
// 사용자 추가
public User save(User user) {
// user에 id 값이 없으면
if(user.getId() == null) {
user.setId(++userCount);
}
users.add(user);
return user;
}
// 사용자 조회
public User findOne(int id) {
for( User user : users ) {
if(user.getId() == id) return user;
}
// 없으면 null 반환
return null;
}
사용자 목록 조회를 위한 API 구현 - GET HTTP Method
- UserController.java 생성
REST를 이용하기 때문에 클래스 이름 위에 @RestController 어노테이션을 붙여준다.
@RestController
public class UserController {}
그리고 위에서 생성한 UserDaoService를 Controller에서 사용할 수 있도록 가져와야하는데 'new' 연산자를 사용해서 직접적으로 가져오는 것이 아니라, 스프링이 관리할 수 있는 인스턴스(Bean) 형태로 가져와야한다. 이를 의존성 주입이라고 하는데 왜 service 인스턴스를 스프링에서 관리하도록 해야할까? 이유는 스프링 컨테이너에 등록되어 있는 Bean은 프로그램 실행 도중 사용자나 개발자가 함부로 변경할 수 없기 때문에 일관성 있는 인스턴스를 사용할 수 있기 때문이다.
스프링 컨테이너에 등록되어 있는 Bean(인스턴스)을 사용하기 위해서는 컨테이너에 등록된 Bean의 참조값을 가져와서 사용하면 된다. 여러가지 방법이 있는데 이번에는 생성자를 통한 의존성 주입 방법을 사용한다.
private UserDaoService service;
// 생성자를 통한 의존성 주입
public UserController(UserDaoService service) {
this.service = service;
}
마지막으로 전체 사용자 조회, 사용자 조회를 위한 메서드를 생성한다.
사용자 조회의 경우 @PathVariable을 사용하였다. 원래 주소 창에 입력되는 id의 타입은 String이나 똑똑한 스프링이 매개변수 타입을 int라고 지정하면 알아서 형변환하여 들어온다.
// 사용자 전체 조회
@GetMapping("/users")
public List<User> retrieveAllUsers() {
return service.findAll();
}
// 주소에 입력된 id는 서버에 넘어올 때 String 타입으로 넘어오지만 PathVariable에 int로 선언 시 형변환 되어서 넘어온다.
@GetMapping("/users/{id}")
public User retrieveUser(@PathVariable int id) {
return service.findOne(id);
}
- 서버 실행 후 크롬에서 확인
전체 사용자 조회 및 사용자(id) 조회
- 추가
위 retrieveUser() 메서드에서 String으로 타입으로 입력된 값을 int로 자동 형변환 시켜준다고 말했다. 그럼 만약 주소 창에 숫자가 아닌 다른 값이 들어가면 어떻게 될까? 숫자 말고 한글을 넣어보자.
400 에러가 발생했다. 개발자가 아니더라도 이런 페이지를 반기는 사람은 없다. Exception 처리를 해보자.
위에 에러 내용을 보면 'NumberFormatException' 이라는 에러가 발생한 걸 확인할 수 있다.
컨트롤러에서 해당 에러를 처리해보자.
@ExceptionHandler(NumberFormatException.class)
public String castIdException() {
return "잘못된 id 값을 입력하였습니다. 숫자로만 입력해주세요.";
}
@ExceptionHandler 어노테이션이 붙은 컨트롤러 클래스가 존재하면 해당 에러 발생 시 이 메서드가 처리한다. @ExceptionHandler의 괄호 안에는 처리하고 싶은 Exception 클래스를 기재해주면 된다.
서버 재실행 후 잘못된 값을 입력해보자.
허접하지만 그래도 에러 메시지가 보이는 화면보단 100배 낫다!
사용자 등록을 위한 API 구현 - POST HTTP Method
- UserController.java 메서드 추가
// 사용자 추가
@PostMapping("/users")
public void createUser(@RequestBody User user) {
User savedUser = service.save(user);
}
@RequestBody 어노테이션을 사용하면 http에 담긴 데이터를 자바 객체로 전달받을 수 있다.
- 서버 재실행 후 포스트맨 실행
포스트맨에서 HTTP Method를 POST로 설정 후 Body에 JSON 데이터를 추가하고 send한다.
해당 메서드의 리턴 값이 void라 아무것도 표시되지 않지만 HTTP Status 코드는 200 OK가 떴다.
만약 이 과정에서 500 에러가 발생한다면 User 클래스에 @NoArgsConstructor를 추가해주면 된다.
더 확실하게 확인하기 위해 GET Method로 전체 사용자 조회를 해보자. (나는 여러 번 해보느라 New User가 많다.)
- 출처 : 인프런 Spring Boot를 이용한 RESTful Web Services 개발 강의