본문 바로가기
공부/Spring

[Spring] Custom error 만들어서 공통 에러 처리하기

by 웅대 2023. 2. 2.
728x90
반응형

이전에 로그인과 회원가입에 성공하면 httpStatus와 함께 데이터를 반환하도록 만들었다.

https://growth-coder.tistory.com/99

 

[Spring] 로그인, 회원 가입 결과 반환 형식

클라이언트가 아이디와 비밀번호를 request body에 담아 POST 요청을 보내면 그에 따른 결과를 반환하려한다. 반환 형식은 아래와 같이 구현해보았다. @AllArgsConstructor @Getter public class LoginAndJoinResponse

growth-coder.tistory.com

 

이제 로그인과 회원가입에 실패하면 custom error를 만들어서 던지면 @RestControllerAdvice에서 에러를 처리하도록 만들어보려 한다.

 

이번에 만들 custom error는 다음과 같다.

 

  1. 회원 가입시 아이디 중복
  2. 로그인시 아이디 찾지 못함
  3. 로그인시 비밀번호 틀림

모두 RunTimeException을 확장하여 만들 것이다.

 

<DuplicatedUserIdException>

public class DuplicatedUserIdException extends RuntimeException{
    public DuplicatedUserIdException() {
        super("아이디가 이미 존재합니다.");
    }
}

<UserIdNotFoundException>

public class UserIdNotFoundException extends RuntimeException {
    public UserIdNotFoundException(){
        super("해당 아이디를 가진 유저가 없습니다.");
    }
}

<WrongUserPasswordException>

public class WrongUserPasswordException extends RuntimeException {
    public WrongUserPasswordException() {
        super("비밀번호가 일치하지 않습니다.");
    }
}

만든 커스텀 에러는 Service 계층에서 던지도록한다.

 

<UserService 안의 메소드>

public String join(String userId, String userPwd) {
    if (아이디가 이미 존재한다면){
        throw new DuplicatedUserIdException();
    }
    .
    .
    .

}

다른 에러들도 Service 계층에서 던진다.

 

이제 이 에러들을 받을 클래스를 생성한다.

 

이러한 커스텀 에러가 발생했을 때 반환 형식은 아래와 같은 LoginAndJoinResponse이다.

 

이전 포스팅에서는 생성자로 인스턴스를 생성했는데 빌더 패턴으로 변경하였다.

@Builder
@NoArgsConstructor
@AllArgsConstructor
@Getter
public class LoginAndJoinResponse {
    private int code;
    private HttpStatus httpStatus;
    private String message;
    private Object data;
}

ResponseEntity에 담아서 클라이언트에게 객체를 보내줘야하므로 @ControllerAdvice가 아닌 @RestControllerAdvice 에노테이션을 달아준다.

 

그리고 에러를 받으려면 @ExceptionalHandler 에노테이션 안에 받을 커스텀 에러 클래스를 넣어준다.

 

<CustomExceptionManager 최종 코드>

@RestControllerAdvice
public class CustomExceptionManager {
    @ExceptionHandler(DuplicatedUserIdException.class)
    public ResponseEntity<LoginAndJoinResponse> duplicatedUserIdException(DuplicatedUserIdException e) {
        LoginAndJoinResponse res = LoginAndJoinResponse.builder()
                .code(HttpStatus.CONFLICT.value())
                .httpStatus(HttpStatus.CONFLICT)
                .message(e.getMessage()).build();
        return new ResponseEntity<>(res, res.getHttpStatus());
    }

    @ExceptionHandler(WrongUserPasswordException.class)
    public ResponseEntity<LoginAndJoinResponse> wrongUserPasswordrException(WrongUserPasswordException e) {
        LoginAndJoinResponse res = LoginAndJoinResponse.builder()
                .code(HttpStatus.BAD_REQUEST.value())
                .httpStatus(HttpStatus.BAD_REQUEST)
                .message(e.getMessage()).build();
        return new ResponseEntity<>(res, res.getHttpStatus());
    }

    @ExceptionHandler(UserIdNotFoundException.class)
    public ResponseEntity<LoginAndJoinResponse> userIdNotFoundException(UserIdNotFoundException e) {
        LoginAndJoinResponse res = LoginAndJoinResponse.builder()
                .code(HttpStatus.NOT_FOUND.value())
                .httpStatus(HttpStatus.NOT_FOUND)
                .message(e.getMessage()).build();
        return new ResponseEntity<>(res, res.getHttpStatus());
    }
}

실패를 했을 때도 관련된 에러를 보기 편하게 반환하도록 구현을 했다.

 

728x90
반응형

댓글