티스토리 뷰

728x90
반응형

스프링부트에서 exception을 처리하는 방법을 알아보자


순서
  1. 에러코드 정리를 enum 클래스로 작성하여 간결하게 만듭니다.
  2. Exception 발생시 응답하는 에러 정보 클래스 작성
  3. 사용자 정의 Exception 클래스 작성
  4. Exception 발생시 전역으로 처리할 Exception Handler 작성
  5. 로그인 시 아이디 및 패스워드 불일치 Exception 발생
  6. 결과 확인

 

에러코드 정리 Enum 클래스 작성


public enum ErrorType {

    UsernameOrPasswordNotFoundException (400, "아이디 또는 비밀번호가 일치하지 않습니다.", HttpStatus.BAD_REQUEST),
    UNAUTHORIZEDException (401, "로그인 후 이용가능합니다.", HttpStatus.UNAUTHORIZED),
    ExpiredJwtException(444, "기존 토큰이 만료되었습니다. 해당 토큰을 가지고 get-newtoken링크로 이동해주세요.", HttpStatus.UNAUTHORIZED),
    ReLogin(445, "모든 토큰이 만료되었습니다. 다시 로그인해주세요.", HttpStatus.UNAUTHORIZED),
    ;

    @Getter
    private int code;

    @Getter
    private String description;

    @Getter
    private HttpStatus httpStatus;

    ErrorType(int code, String description, HttpStatus httpStatus) {
        this.code = code;
        this.description = description;
        this.httpStatus = httpStatus;
    }
}

 

Exception 발생시 응답하는 에러 정보 클래스 작성


@Getter
@AllArgsConstructor
public class ErrorResponse {

    private int code = HttpStatus.BAD_REQUEST.value();
    private Object error;
}

 

 

사용자 정의 Exception 클래스 작성


  • RuntimeException을 상속받는 사용자 정의 Exception 클래스를 작성합니다.
  • 매개 변수가 있는 생성자를 만들어 Enum 클래스를 매개변수로 전달하여 생성자 주입을 받습니다.
@Getter
public class AuthenticationException extends RuntimeException{

    private final ErrorType errorType;

    public AuthenticationException(ErrorType errorType) {
        this.errorType = errorType;
    }
}

 

Exception 발생시 전역으로 처리할 Exception Handler 작성


  • @RestControllerAdvice 또는 @ControllerAdvice, @ExceptionHandler 어노테이션을 이용하여 Exception 발생시 적절한 에러 응답을 생성하여 반환합니다.
@ControllerAdvice
public class ExceptionController {

    /**
     **** 로그인시 아이디 또는 비밀번호가 일치하지 않는 예외가 발생했을 때
     **/
    @ExceptionHandler(AuthenticationException.class)
    @ResponseBody
    public ResponseEntity<ErrorResponse> handleAuthenticationException(AuthenticationException ex){
        ErrorResponse errorResponse = new ErrorResponse(ex.getErrorCode().getCode(), ex.getErrorCode().getMessage());
        return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

 

로그인 시 아이디 및 패스워드 불일치 Exception 예외 처리


로그인 컨트롤러 클래스
@RequestMapping("/auth")
@RestController
@RequiredArgsConstructor
public class AuthController {

    private final AuthService authService;

    @PostMapping("/login")
    public ApiResponse login(@RequestBody @Valid AuthDto authDto) {
        return authService.login(authDto);
    }
}

 

AuthDto 클래스
@Data
public class AuthDto {

    @NotBlank
    @ApiModelProperty(value = "아이디", example = "test", required = true)
    private String userId;

    @NotBlank
    @ApiModelProperty(value = "비밀번호", example = "1234", required = true)
    private String userPwd;
}

 

AuthService 클래스
@Service
@RequiredArgsConstructor
public class AuthService {

    private final JwtProvider jwtProvider;
    private final AuthenticationManager authenticationManager;
    private final AuthRefreshTokenMapper authRefreshTokenMapper;

    public ApiResponse login(AuthDto authDto) {
        ResponseMap result = new ResponseMap();

        try {
            authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(authDto.getUserId(), authDto.getUserPwd())
            );

            String accessToken = jwtProvider.createJwtToken(authDto.getUserId());
            String refreshToken = jwtProvider.createRefreshToken(authDto.getUserId());
            authRefreshTokenMapper.insertRefreshToken(authDto.getUserId(), accessToken, refreshToken);

            result.setResponseData("accessToken", accessToken);
        } catch (Exception e) {
            throw new AuthenticationException(ErrorType.UsernameOrPasswordNotFoundException);
        }

        return result;
    }
}

 

결과 확인


정상적으로 로그인이 된 경우

 

아이디 또는 패스워드가 일치하지 않는 경우

728x90
반응형