diff --git a/src/main/java/com/acquirex/exception/GlobalExceptionHandler.java b/src/main/java/com/acquirex/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..d25d1b1 --- /dev/null +++ b/src/main/java/com/acquirex/exception/GlobalExceptionHandler.java @@ -0,0 +1,74 @@ +package com.acquirex.exception; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; + +/** + * 전역 예외 처리 핸들러 - Spring Boot 3 (jakarta.validation) + */ +@RestControllerAdvice +@Slf4j +public class GlobalExceptionHandler { + + @ExceptionHandler(AcquisitionNotFoundException.class) + public ResponseEntity> handleAcquisitionNotFound(AcquisitionNotFoundException ex) { + log.error("매입 정보 없음: {}", ex.getMessage()); + return buildErrorResponse(HttpStatus.NOT_FOUND, ex.getMessage()); + } + + @ExceptionHandler(InvalidAcquisitionStateException.class) + public ResponseEntity> handleInvalidAcquisitionState(InvalidAcquisitionStateException ex) { + log.error("유효하지 않은 매입 상태: {}", ex.getMessage()); + return buildErrorResponse(HttpStatus.BAD_REQUEST, ex.getMessage()); + } + + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity> handleValidationErrors(MethodArgumentNotValidException ex) { + Map errors = new HashMap<>(); + ex.getBindingResult().getAllErrors().forEach(error -> { + String fieldName = ((FieldError) error).getField(); + errors.put(fieldName, error.getDefaultMessage()); + }); + log.error("검증 오류: {}", errors); + Map response = new HashMap<>(); + response.put("timestamp", LocalDateTime.now()); + response.put("status", HttpStatus.BAD_REQUEST.value()); + response.put("error", "Validation Failed"); + response.put("errors", errors); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity> handleGenericException(Exception ex) { + log.error("예상치 못한 오류 발생", ex); + return buildErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, "예상치 못한 오류가 발생했습니다"); + } + + private ResponseEntity> buildErrorResponse(HttpStatus status, String message) { + Map response = new HashMap<>(); + response.put("timestamp", LocalDateTime.now()); + response.put("status", status.value()); + response.put("error", status.getReasonPhrase()); + response.put("message", message); + return ResponseEntity.status(status).body(response); + } +} + +/** 매입 정보를 찾을 수 없을 때 발생하는 예외 */ +class AcquisitionNotFoundException extends RuntimeException { + public AcquisitionNotFoundException(String message) { super(message); } +} + +/** 매입 상태가 유효하지 않을 때 발생하는 예외 */ +class InvalidAcquisitionStateException extends RuntimeException { + public InvalidAcquisitionStateException(String message) { super(message); } +} \ No newline at end of file