애플리케이션을 개발할 때 예외 처리를 효과적으로 처리하는 것은 중요하다고 생각한다. 이를 통해 예외 상황에 대한 적절한 응답을 제공하고, 사용자 경험을 개선하며, 애플리케이션의 안정성을 높일 수 있다.
전역 예외 처리기를 통해 다양한 예외 상황을 처리하고, 사용자 정의 예외(Custom Exception)와 표준 예외에 대한 응답을 구성해보았다.
import lombok.Getter;
@Getter
public class CustomException extends RuntimeException {
private final ErrorMessage errorMessage;
public CustomException(ErrorMessage errorMessage) {
super(errorMessage.getMessage());
this.errorMessage = errorMessage;
}
public int getStatus() {
return errorMessage.getStatus();
}
public String getCode() {
return errorMessage.getCode();
}
public String getMessage() {
return errorMessage.getMessage();
}
}
위 코드에서 CustomException 클래스는 RuntimeException을 확장하며, ErrorMessage를 포함하여 사용자 정의 예외를 정의한다. 이를 통해 예외가 발생하면 사전에 정의된 상태 코드와 메시지를 반환할 수 있다.
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum ErrorMessage {
// 여기에 다양한 예외 유형과 메시지를 정의할 수 있다.
INVALID_REQUEST(400, "ERR001", "잘못된 요청 형식입니다."),
UNAUTHORIZED(401, "ERR002", "인가되지 않은 접근입니다."),
// ...
ORDER_NOT_FOUND(404, "ORDER001", "주문 정보를 찾을 수 없습니다."),
INVALID_PAYMENT_TYPE(400, "ORDER002", "유효하지 않은 결제 유형입니다.");
private final int status;
private final String code;
private final String message;
ErrorMessage(int status, String code, String message) {
this.status = status;
this.code = code;
this.message = message;
}
}
ErrorMessage는 예외의 상태 코드, 코드, 그리고 메시지를 정의한다. 각 열거 상수는 다양한 상황에 대한 예외를 포함한다.
import kr.co.kcp.backendcoding.work.common.response.ErrorResponse;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;
import java.nio.file.AccessDeniedException;
import java.util.stream.Collectors;
@RestControllerAdvice
public class GlobalExceptionHandler {
// CustomException 처리기
@ExceptionHandler(CustomException.class)
public ResponseEntity<ErrorResponse> handleCustomException(CustomException e) {
ErrorResponse errorResponse = ErrorResponse.builder()
.status(e.getStatus())
.code(e.getCode())
.message(e.getMessage())
.build();
return new ResponseEntity<>(errorResponse, HttpStatus.valueOf(e.getStatus()));
}
// 유효성 검사 예외 처리기
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidationExceptions(MethodArgumentNotValidException e) {
// 유효성 검사 실패에 대한 메시지 생성
String errorMessages = e.getBindingResult().getFieldErrors().stream()
.map(fieldError -> fieldError.getField() + ": " + fieldError.getDefaultMessage())
.collect(Collectors.joining(", "));
ErrorResponse errorResponse = ErrorResponse.builder()
.status(HttpStatus.BAD_REQUEST.value())
.code("ERR_VALIDATION")
.message("유효성 검사 오류: " + errorMessages)
.build();
return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST);
}
// ...
}
위의 GlobalExceptionHandler 클래스는 다양한 종류의 예외를 처리한다. @ExceptionHandler 어노테이션을 사용하여 각 예외 유형에 대한 처리기를 정의했다. 예를 들어, CustomException에 대한 처리기는 미리 정의된 상태 코드와 메시지를 반환한다.
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
@Getter
@AllArgsConstructor
@Builder
public class ErrorResponse {
private final int status;
private final String code;
private final String message;
}
ErrorResponse 클래스는 예외가 발생했을 때 반환되는 응답을 정의한다. 이 클래스는 상태 코드, 코드, 그리고 메시지를 포함한다.