User Service API 구현

뚜우웅이·2024년 8월 26일

User 도메인

Domain : Domain Knowledge, 즉 인간 활동 영역, 혹은 자율적인 컴퓨터 활동*과 같은 어떤 특정한 전문 분야에서 사용되어지는 업무 지식을 뜻함

  • 사용자 관리를 위한 Domain Knowledge(User)는 사용자 정보를 어떤 형태로 저장하고 어떤 데이터를 저장할 것인지에 대해서 나타낸 것. 사용자의 이름, id, 회원가입 날짜 같은 정보를 저장.

User
restful-api-service -> user 패키지 생성

@Data
@AllArgsConstructor
public class User {

    private Integer id;
    private String name;
    private Date joinDate;
}

사용자 목록 조회를 위한 API 구현

UserDaoService

  • Service : 비즈니스 로직을 작성하는 클래스
  • Dao : 데이터 베이스 관련 로직을 작성하는 클래스

restful-api-service -> user

@Service
public class UserDaoService {

    private static List<User> users = new ArrayList<>();

    private static int userCount = 3;

    // 데이터베이스에 3개의 데이터가 들어 있다고 가정
    static {
        users.add(new User(1, "roxy", new Date()));
        users.add(new User(2, "yujin", new Date()));
        users.add(new User(3, "kyj", new Date()));
    }

    // 모든 사용자 조회
    public List<User> findAll() {
        return users;
    }

    // 신규 사용자 추가
    public User save(User user) {
        if (user.getId() == null) {
            user.setId(++userCount);
        }

        users.add(user);
        return user;
    }

    // id값으로 사용자 조회
    public User findOne(int id) {
        for (User user : users) {
            if (user.getId() == id) {
                return user;
            }
        }
        return null;
    }
}

UserController
restful-api-service -> user

@RestController
@RequiredArgsConstructor
public class UserController {

    private final UserDaoService service;

    // 전체 사용자 목록 조회
    @GetMapping("/users")
    public List<User> retrieveAllUsers() {
        return service.findAll();
    }

    // 사용자 상세 조회
    @GetMapping("/user/{id}")
    public User retrieveUser(@PathVariable("id") int id) {
        return service.findOne(id);
    }
}

사용자 등록을 위한 API 구현

Post, Put등 클라이언트로부터 Form data 타입이 아닌 json, xml등 오브젝트 형태의 데이터를 받기 위해서 매개변수 타입에 @RequestBody 선언해줘야 한다.

UserController
restful-api-service -> user

    @PostMapping("/users")
    public void createUser(@RequestBody User user) {
        User savedUser = service.save(user);
    }

에러 발생

cannot deserialize from object value (no delegate- or property-based creator)

User 도메인에 빈 생성자를 추가해준다.

User

@NoArgsConstructor


HTTP Status Code 제어

응답코드 값을 제어하기 위해서 Servlet URI Component build 클래스 사용

UserController
createUser() 메서드 수정

    @PostMapping("/users")
    public ResponseEntity<User> createUser(@RequestBody User user) {
        User savedUser = service.save(user);

        URI location = ServletUriComponentsBuilder.fromCurrentRequest() // 현재 가지고 있는 Request 사용
                .path("/{id}") // 반환 시 URI 뒤에 /{id} 추가
                .buildAndExpand(savedUser.getId()) // {id}에 savedUser.getId() 값을 넣어줌
                .toUri();

        return ResponseEntity.created(location).build();

    


status coder가 201로 변경되었다.

HTTP Status Code 제어를 위한 Exception Handling


존재하지 않는 id 100의 사용자를 요청했는데 status code 200 ok가 발생했다.

UserController

retrieveUser() 메서드 수정


    @GetMapping("/user/{id}")
    public User retrieveUser(@PathVariable("id") int id) {
        User user = service.findOne(id);
        if (user == null) {
            throw new UserNotFoundException(String.format("ID[%s] not found", id));
        }
        return user;
    }

UserNotFoundException
restful-api-service -> user

@ResponseStatus(HttpStatus.NOT_FOUND)
public class UserNotFoundException extends RuntimeException{

    public UserNotFoundException(String message) { //실행시 발생하는 오류로 처리
        super(message); //생성자는 부모 클래스로부터 전달받은 메시지로 처리
    }
}


404번 오류 발생

Spring AOP를 이용한 Exception Handling

ExceptionResponse
restful-api-service -> exception 생성

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ExceptionResponse {

    private Date timestamp;
    private String message;
    private String details;
}

일반적인 예외*

  • ResponseEntityExceptionHandler 클래스를 상속받은 Handler 클래스 선언
  • ResponseEntityExceptionHandler 클래스 : 시스템에서 에러 발생시 에러를 핸들링하기 위해 스프링에서 제공하는 클래스
    * ControllerBean에서 예외 발생시 이 클래스가 발생하도록 설정
  • AOP : 스프링 프레임워크에서 로깅 정보, 로그인 정보, 메시지 추가 정보 등 모든 비즈니스 로직을 수행하는 Controller에서 항상 실행시켜줘야 하는 공통적인 로직
  • 스피링 부트 어플리케이션에서 공통적으로 처리 되어야 하는 로직, 메소드 등을 추가할 때 사용
  • @RestController 어노테이션 추가하여 웹 서비스에서 사용할 수 있도록 함
  • @ContollerAdvice 어노테이션 추가하여 모든 Controller가 실행될 때 반드시 이 어노테이션이 붙은 Bean이 실행되도록 함

CustomizedResponseEntityExceptionHandler
restful-api-service -> exception

@RestControllerAdvice
public class CustomizedResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {

    /**
     ResponseEntity는 사용자 객체 한명 추가했을 때 반환하는 형태의 값
     Exception ex는 메소드에서 발생했던 에러 객체
     WebRequest request는 어디서 발생했는지 알아보기 위한 request 정보
     @ExceptionHandler 어노테이션은 이 메소드가 ExceptionHandler로 사용될 수 있음을 지칭.
     */

    @ExceptionHandler(Exception.class)
    public final ResponseEntity<Object> handlerAllException(Exception ex, WebRequest request) {

        // 발생 날짜, 에러 메시지, request의 부가적인 내용
        ExceptionResponse exceptionResponse = new ExceptionResponse(
                new Date(), ex.getMessage(), request.getDescription(false)
        );

        return new ResponseEntity(exceptionResponse, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

서버에서 발생하는 일반화 된 에러이기 때문에 500번 에러 발생

존재하지 않는 사용자 요청 시 예외

CustomizedResponseEntityExceptionHandler
restful-api-service -> exception

    @ExceptionHandler(UserNotFoundException.class)
    public final ResponseEntity<Object> handleUserNotFound(Exception ex, WebRequest request) {

        // 발생 날짜, 에러 메시지, request의 부가적인 내용
        ExceptionResponse exceptionResponse = new ExceptionResponse(
                new Date(), ex.getMessage(), request.getDescription(false)
        );

        return new ResponseEntity(exceptionResponse, HttpStatus.NOT_FOUND);
    }


404 Not Found 발생

사용자 삭제

UserDaoService

    public User deleteUser(int id) {

        Iterator<User> iterator = users.iterator();

        while (iterator.hasNext()) {
            User user = iterator.next();

            if (user.getId() == id) {
                iterator.remove();
                return user;
            }
        }
        return null;
    }

UserController

    @DeleteMapping("/users/{id}")
    public void deleteUser(@PathVariable("id") int id) {
        User user = service.deleteUser(id);

        if (user == null) {
            throw new UserNotFoundException(String.format("ID[%s] not found", id));
        }
    }


사용자 수정

UserDaoService

    public User modifyUser(int id, String name) {
        Iterator<User> iterator = users.iterator();
        while (iterator.hasNext()) {
            User user = iterator.next();
            if (user.getId() == id) {
                user.setName(name);
                return user;
            }
        }
        return null;
    }

UserController

    @PutMapping("/users/modify")
    public User modifyUser(@RequestBody Map<String, String> param) {
        int id = Integer.parseInt(param.get("id"));
        String name = param.get("name");
        User user = service.modifyUser(id, name);
        return user;
    }


profile
공부하는 초보 개발자

0개의 댓글