Skip to content

Commit

Permalink
feat: ControllerAdvice 개편 (#950)
Browse files Browse the repository at this point in the history
* fix: jwtUtils getPayload 메서드 내부에 try catch 로직 넣기

zzimkkong exception 으로 wrapping 해서 401 나도록 수정

* feat: controller advice logging & error response 정리

* feat: RequestParam 에 잘못된 포맷으로 와서 TypeMismatch 날 때, 400 처리하도록 수정

* chore: token 만료시 나가는 메세지 변경
  • Loading branch information
sakjung authored Mar 15, 2023
1 parent dc940c2 commit b2e78ac
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
Expand All @@ -33,88 +34,79 @@
@Slf4j
@RestControllerAdvice
public class ControllerAdvice implements RequestRejectedHandler {
private static final String MESSAGE_FORMAT = "{} (traceId: {})";
private static final String MESSAGE_FORMAT = "%s (traceId: %s)";
private static final String TRACE_ID_KEY = "traceId";

@ExceptionHandler(NoSuchOAuthMemberException.class)
public ResponseEntity<OAuthLoginFailErrorResponse> oAuthLoginFailHandler(final NoSuchOAuthMemberException exception) {
logInfo(exception.getMessage());
logInfo(exception);
return ResponseEntity
.status(exception.getStatus())
.body(OAuthLoginFailErrorResponse.from(exception));
}

@ExceptionHandler(InputFieldException.class)
public ResponseEntity<InputFieldErrorResponse> inputFieldExceptionHandler(final InputFieldException exception) {
logInfo(exception.getMessage());
logInfo(exception);
return ResponseEntity
.status(exception.getStatus())
.body(InputFieldErrorResponse.from(exception));
}

@ExceptionHandler(InfrastructureMalfunctionException.class)
public ResponseEntity<ErrorResponse> wrongConfigurationOfInfrastructureException(final InfrastructureMalfunctionException exception) {
logWarn(exception.getMessage(), exception);
logWarn(exception);
return ResponseEntity
.status(exception.getStatus())
.body(ErrorResponse.from(exception));
}

@ExceptionHandler(ZzimkkongException.class)
public ResponseEntity<ErrorResponse> zzimkkongExceptionHandler(final ZzimkkongException exception) {
logInfo(exception.getMessage());
logInfo(exception);
return ResponseEntity
.status(exception.getStatus())
.body(ErrorResponse.from(exception));
}

@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<InputFieldErrorResponse> invalidArgumentHandler(final MethodArgumentNotValidException exception) {
logInfo(exception.getMessage());
logInfo(exception);
return ResponseEntity.badRequest().body(InputFieldErrorResponse.from(exception));
}

@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<ErrorResponse> invalidParamHandler(final ConstraintViolationException exception) {
logInfo(exception.getMessage());
logInfo(exception);
return ResponseEntity.badRequest().body(ErrorResponse.from(exception));
}

@ExceptionHandler({InvalidFormatException.class, HttpMessageNotReadableException.class})
public ResponseEntity<ErrorResponse> invalidFormatHandler() {
logInfo(FORMAT_MESSAGE);
@ExceptionHandler({InvalidFormatException.class, HttpMessageNotReadableException.class, MethodArgumentTypeMismatchException.class})
public ResponseEntity<ErrorResponse> invalidFormatHandler(final Exception exception) {
logInfo(exception);
return ResponseEntity.badRequest().body(ErrorResponse.invalidFormat());
}

@ExceptionHandler(DataAccessException.class)
public ResponseEntity<Void> invalidDataAccessHandler(final DataAccessException exception) {
logWarn(SERVER_ERROR_MESSAGE, exception);
return ResponseEntity.internalServerError().build();
public ResponseEntity<ErrorResponse> invalidDataAccessHandler(final DataAccessException exception) {
logWarn(exception);
return ResponseEntity.internalServerError().body(ErrorResponse.internalServerError());
}

@ExceptionHandler(Exception.class)
public ResponseEntity<Void> unhandledExceptionHandler(final Exception exception) {
logWarn(exception.getMessage(), exception);
return ResponseEntity.internalServerError().build();
public ResponseEntity<ErrorResponse> unhandledExceptionHandler(final Exception exception) {
logWarn(exception);
return ResponseEntity.internalServerError().body(ErrorResponse.internalServerError());
}

private void logInfo(String message) {
log.info(MESSAGE_FORMAT,
message,
value(TRACE_ID_KEY, getTraceId()));
private void logInfo(Exception exception) {
String logMessage = String.format(MESSAGE_FORMAT, exception.getMessage(), value(TRACE_ID_KEY, getTraceId()));
log.info(logMessage, exception);
}

private void logWarn(String message, Exception exception) {
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);

exception.printStackTrace(printWriter);
String stackTrace = stringWriter.toString();

log.warn(MESSAGE_FORMAT,
message,
value(TRACE_ID_KEY, getTraceId()),
value("stack_trace", stackTrace));
private void logWarn(Exception exception) {
String logMessage = String.format(MESSAGE_FORMAT, exception.getMessage(), value(TRACE_ID_KEY, getTraceId()));
log.warn(logMessage, exception);
}

private Object getTraceId() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import javax.validation.ConstraintViolationException;

import static com.woowacourse.zzimkkong.dto.ValidatorMessage.FORMAT_MESSAGE;
import static com.woowacourse.zzimkkong.dto.ValidatorMessage.SERVER_ERROR_MESSAGE;

@Getter
@NoArgsConstructor
Expand All @@ -28,4 +29,8 @@ public static ErrorResponse from(final ConstraintViolationException exception) {
public static ErrorResponse invalidFormat() {
return new ErrorResponse(FORMAT_MESSAGE);
}

public static ErrorResponse internalServerError() {
return new ErrorResponse(SERVER_ERROR_MESSAGE);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ private ValidatorMessage() {
public static final String NOTICE_MESSAGE = "공지사항은 100자 이내로 작성 가능합니다.";
public static final String FORMAT_MESSAGE = "날짜 및 시간 데이터 형식이 올바르지 않습니다.";
public static final String DAY_OF_WEEK_MESSAGE = "올바른 요일 형식이 아닙니다.";
public static final String SERVER_ERROR_MESSAGE = "예상치 못한 문제가 발생했습니다. 개발자에게 문의하세요.";
public static final String SERVER_ERROR_MESSAGE = "일시적으로 접속이 원활하지 않습니다. 잠시 후 다시 이용해 주시기 바랍니다.";
public static final String TIME_UNIT_MESSAGE = "시간 단위는 10, 30, 60, 120입니다.";
public static final String SETTING_COUNT_MESSAGE = "공간의 예약 조건이 최소 1개는 존재해야 합니다.";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import org.springframework.http.HttpStatus;

public class TokenExpiredException extends ZzimkkongException {
private static final String MESSAGE = "로그인이 필요한 서비스입니다.";
private static final String MESSAGE = "로그인 인증 유효기간이 만료되었습니다. 다시 로그인 해주세요.";

public TokenExpiredException() {
super(MESSAGE, HttpStatus.UNAUTHORIZED);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,13 @@ public void validateToken(String token) {
}

public String getPayload(String token) {
return jwtParser.parseClaimsJws(token).getBody().getSubject();
try {
return jwtParser.parseClaimsJws(token).getBody().getSubject();
} catch (ExpiredJwtException e) {
throw new TokenExpiredException();
} catch (JwtException e) {
throw new InvalidTokenException();
}
}

public static PayloadBuilder payloadBuilder() {
Expand Down

0 comments on commit b2e78ac

Please sign in to comment.