/*
* 기본 컨트롤러 어드바이스, 하위 컨트롤러 어드바이스는 이 클래스를 상속 하여 사용해야 함.
* */
public class BaseControllerAdvice {
private String parseExceptionMessage(Exception exception) {
String message = "no detail message for %s".formatted(exception.getClass().getSimpleName());
if (StringUtil.isExist(exception.getMessage())) {
message = exception.getMessage();
}
return message;
}
public ProblemDetail exceptionResponse(HttpStatusCode status, String detail) {
ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(status, detail);
problemDetail.setTitle(status.toString());
return problemDetail;
}
public ProblemDetail exceptionResponse(HttpStatusCode status, Exception exception) {
ProblemDetail problemDetail = ProblemDetail.forStatus(status);
problemDetail.setDetail(parseExceptionMessage(exception));
problemDetail.setTitle(status.toString());
return problemDetail;
}
}
@RestControllerAdvice
@Slf4j
@Order(Ordered.LOWEST_PRECEDENCE)
public class ApiControllerAdvice extends BaseControllerAdvice {
@ExceptionHandler({AlreadyExistException.class})
public ProblemDetail handleAlreadyExistException(AlreadyExistException ex) {
return this.exceptionResponse(HttpStatus.BAD_REQUEST, ex);
}
@ExceptionHandler({BadRequestException.class})
public ProblemDetail handleBadRequestException(BadRequestException ex) {
return this.exceptionResponse(HttpStatus.BAD_REQUEST, ex);
}
@ExceptionHandler(Exception.class)
public ProblemDetail handlerException(Exception ex) {
return this.exceptionResponse(HttpStatus.INTERNAL_SERVER_ERROR, new Exception("unknown server error"));
}
}
@RestControllerAdvice
@Slf4j
@Order(Ordered.HIGHEST_PRECEDENCE)
public class LoginControllerAdvice extends BaseControllerAdvice{
// 로그인 예외 실패 수 있으면, 예외 응답에 실패 수 포함.
@ExceptionHandler({LoginException.class})
public ProblemDetail handleLoginFail(LoginException ex) {
ProblemDetail problemDetail = this.exceptionResponse(HttpStatus.UNAUTHORIZED, ex);
if (ex.getLoginFailCount() != null) {
problemDetail.setProperty("loginFailCount", ex.getLoginFailCount());
}
return problemDetail;
}
}
@Getter
public class LoginException extends RuntimeException{
private final Integer loginFailCount;
public LoginException(String message) {
super(message);
loginFailCount = null;
}
public LoginException(String message, Integer loginFailCount) {
super(message);
this.loginFailCount = loginFailCount;
}
// 없는 유저 로그인 시도
public static class NoUser extends LoginException {
public NoUser() { super("no user"); }
}
// 로그인 실패 횟수 초과
public static class TooManyFailedLogin extends LoginException {
public TooManyFailedLogin(Integer loginFailCount) {
super("too many failed login", loginFailCount);
}
}
// 비활성화 계정 로그인 시도
public static class DeactivatedUser extends LoginException {
public DeactivatedUser(Integer loginFailCount) {
super("deactivated user", loginFailCount);
}
}
// 비밀번호 틀림
public static class InvalidPassword extends LoginException {
public InvalidPassword(Integer loginFailCount) {
super("invalid password", loginFailCount);
}
}
}