코딩블로그
[Spring]ErrorResponse & Exception 만들기 본문
728x90
밥메이트 프로젝트를 진행하면서 Exception다루는 클래스를 작성해보았습니다
BaseErrorCode
public interface BaseErrorCode {
public ErrorReason getErrorReason();
}
BaseException
@Getter
@AllArgsConstructor
public class BaseException extends RuntimeException {
private final BaseErrorCode errorCode;
public ErrorReason getErrorReason() {
return this.errorCode.getErrorReason();
}
}
Dto/ErrorReason
@Getter
public class ErrorReason {
private final int status;
private final String code;
private final String reason;
@Builder
private ErrorReason(int status, String code, String reason) {
this.status = status;
this.code = code;
this.reason = reason;
}
public static ErrorReason of(int status, String code, String reason) {
return ErrorReason.builder().status(status).code(code).reason(reason).build();
}
}
MeetingErrorCode
@Getter
@AllArgsConstructor
public enum MeetingErrorCode implements BaseErrorCode {
FULL_CAPACITY_ERROR(BAD_REQUEST,"MEETING_404","인원이 다 찼습니다"),
MEETING_NOT_FOUND(BAD_REQUEST,"MEETING_404","모임이 존재하지 않습니다"),
ALREADY_PARTICIPATED_ERROR(BAD_REQUEST,"MEETING_404","이미 참여한 모임입니다"),
NOT_ALLOWED_TO_PARTICIPATE_ERROR(BAD_REQUEST,"MEETING_404","생성한 모임에는 참여할 수 없습니다");
private final int status;
private final String code;
private final String reason;
@Override
public ErrorReason getErrorReason() {
return ErrorReason.of(status, code, reason);
}
}
MeetingNotFoundException
public class MeetingNotFoundException extends BaseException {
public MeetingNotFoundException() {
super(MeetingErrorCode.MEETING_NOT_FOUND);
}
}
마지막으로
GlobalExceptionHandler 클래스를 만들어서 위에 만든 코드들이 작동하도록 설정해주어야 합니다
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
//주로 HTTP 요청을 처리하는 도중에 발생한 예외를 처리합니다
protected ResponseEntity<Object> handleExceptionInternal(
Exception ex,
@Nullable Object body,
HttpHeaders headers,
HttpStatus statusCode,
WebRequest request) {
log.error("HandleInternalException", ex);
final HttpStatus status = (HttpStatus) statusCode;
final ErrorReason errorReason =
ErrorReason.of(status.value(), status.name(), ex.getMessage());
final ErrorResponse errorResponse = ErrorResponse.from(errorReason);
return super.handleExceptionInternal(ex, errorResponse, headers, status, request);
}
@Nullable
protected ResponseEntity<Object> handleMethodArgumentNotValid(
MethodArgumentNotValidException ex,
HttpHeaders headers,
HttpStatus status,
WebRequest request) {
final HttpStatus httpStatus = (HttpStatus) status;
final List<FieldError> errors = ex.getBindingResult().getFieldErrors();
final Map<String, Object> fieldAndErrorMessages =
errors.stream()
.collect(
Collectors.toMap(
FieldError::getField, FieldError::getDefaultMessage));
final String errorsToJsonString =
fieldAndErrorMessages.entrySet().stream()
.map(e -> e.getKey() + " : " + e.getValue())
.collect(Collectors.joining("|"));
final ErrorReason errorReason =
ErrorReason.of(status.value(), httpStatus.name(), errorsToJsonString);
final ErrorResponse errorResponse = ErrorResponse.from(errorReason);
return ResponseEntity.status(HttpStatus.valueOf(errorReason.getStatus()))
.body(errorResponse);
}
@Nullable
protected ResponseEntity<Object> handleHttpMessageNotReadable(
HttpMessageNotReadableException ex,
HttpHeaders headers,
HttpStatus status,
WebRequest request) {
log.error("HttpMessageNotReadableException", ex);
final GlobalErrorCode globalErrorCode = GlobalErrorCode.HTTP_MESSAGE_NOT_READABLE;
final ErrorReason errorReason = globalErrorCode.getErrorReason();
final ErrorResponse errorResponse = ErrorResponse.from(errorReason);
return ResponseEntity.status(INTERNAL_SERVER_ERROR).body(errorResponse);
}
// 비즈니스 로직(UseCase) 에러 처리
@ExceptionHandler(BaseErrorException.class)
public ResponseEntity<ErrorResponse> handleBaseErrorException(
BaseErrorException e, HttpServletRequest request) {
log.error("BaseErrorException", e);
final ErrorReason errorReason = e.getErrorCode().getErrorReason();
final ErrorResponse errorResponse = ErrorResponse.from(errorReason);
return ResponseEntity.status(HttpStatus.valueOf(errorReason.getStatus()))
.body(errorResponse);
}
//따로 Exception으로 빼서 처리하지 않은 에러를 모두 처리해줍니다.
@ExceptionHandler(Exception.class)
protected ResponseEntity<ErrorResponse> handleException(
Exception e, HttpServletRequest request) {
log.error("Exception", e);
final ContentCachingRequestWrapper cachedRequest =
new ContentCachingRequestWrapper(request);
final GlobalErrorCode globalErrorCode = GlobalErrorCode._INTERNAL_SERVER_ERROR;
final ErrorReason errorReason = globalErrorCode.getErrorReason();
final ErrorResponse errorResponse = ErrorResponse.from(errorReason);
return ResponseEntity.status(INTERNAL_SERVER_ERROR).body(errorResponse);
}
}
- @RestControllerAdvice
: @RestControllerAdvice는 @ControllerAdvice와 달리 @ResponseBody가 붙어 있어 응답을 Json으로 내려준다
결과
728x90
'Spring' 카테고리의 다른 글
spring boot이용해서 EmployeeManager 사이트 구현하기 (0) | 2023.04.29 |
---|