Custom Exception을 만드는건 까다롭고 귀찮지만 도움이 됩니다.
전체 범위에서 처리할 BAD Request 사항을 처리하기 위해서는 상당히 많은 코드가 필요한데요
예로 들어온 값을 검증하여 (Validation) 처리하는 부분에서나
내부 비지니스로직을 타다 발생되는 예외를 처리하기 위해
컨트롤러에서 많게는 10개이상씩 예외처리문을 처리하고
이를 중복해서 사용하는 경우가 많다보니
코드의 가독성과 코드 수 자체도 많아져 방법을 찾게 되었습니다.
이번에는 Enum을 대상으로 처리해볼건데
저는 일반적으로 Enum을 DB에 들어갈 데이터중 값이 포맷에 맞아야하는경우를
대상으로 주로 활용하고 있습니다.
Enum을 선언
public enum EventLevelEnum {
danger ,
attention,
check
}
간단하게 3개의 정의된 정보가 있다고 가정해보겠습니다.
Spring Validtion으로 검증값 만들기
@NotBlank(message = "이벤트 코드(eventCode)는 필수 입력 값입니다.")
@Size(max = 50, message = "이벤트 코드(eventCode)는 최대 50자까지 가능합니다.")
@Pattern(regexp = "^[a-zA-Z0-9_-]+$", message = "이벤트 코드(eventCode)는 영문, 숫자, '-', '_'만 포함할 수 있습니다.")
private String eventCode;
예를들어 이런식으로 DB구조와 사용자가 정의한 - 개발자가 의도한 결과 데이터가 들어오는지를 검출합니다.
만약 Enum 값을 검증한다면
@NotBlank(message = "이벤트 레벨(eventLevel)은 필수 입력 값입니다.")
@ValidEventCodeEnum(enumClass = EventLevelEnum.class, message = "이벤트 레벨(eventLevel)은 'danger', 'attention', 'check' 중 하나여야 합니다.")
private String eventLevel;
이렇게 이넘을 정의해볼 수 있습니다.
정의된 Enum을 발리데이션의 인터페이스를 정의
@Documented
@Constraint(validatedBy = EnumValidator.class)
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidEventCodeEnum {
Class<? extends Enum<?>> enumClass();
String message() default "올바른 값이 아닙니다.";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
예로 이런식으로 정의할 수 있는데 관련된 어노테이션은 따로 정리해둔 문서를 확인해보십시오
실제 로직을 수행할 class파일 정의하기
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import java.util.Arrays;
public class EnumValidator implements ConstraintValidator<ValidEventCodeEnum, String> {
private Class<? extends Enum<?>> enumClass;
@Override
public void initialize(ValidEventCodeEnum annotation) {
this.enumClass = annotation.enumClass();
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (value == null || value.isBlank()) {
return false;
}
return Arrays.stream(enumClass.getEnumConstants())
.map(Enum::name)
.anyMatch(enumValue -> enumValue.equalsIgnoreCase(value));
}
}
간단하게 해당 값이 Enum에 포함되어 있는지를 체크하는 로직을 만들어서 처리하였습니다.
Global Exception에 추가하기
@Slf4j
@RestControllerAdvice
@Hidden
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) {
Map<String, String> errors = new HashMap<>();
for (FieldError error : ex.getBindingResult().getFieldErrors()) {
errors.put(error.getField(), error.getDefaultMessage());
}
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errors);
}
}
이렇게 해서 처리할 수 있습니다. 관련되서 Swagger와 관련된 에러가 존재하는데
처리하는 과정중 해당 Handler가 먼저 적용되어 Swagger API 형식을 막아버리는
저는 일단 @Hidden 옵션으로 해결했는데 방법은 여러가지 있습니다.
트러블 슈팅쪽에서 확인해보세요
이렇게 하면 의도한 대로 동작하게됩니다.
간단한 테스트


결과값은 다음 처럼 의도한 결과가 발생한 것을 알 수 있습니다.
이러면 프론트에서도 처리하기 더욱 쉬워져서 협업이 용의한 소스를 매우 간단하면서도, 효율적으로 만들어
볼 수 있습니다.
'Spring - Spring Boot' 카테고리의 다른 글
| AOP 활용 방법 - Spring Boot (0) | 2025.04.03 |
|---|---|
| 스프링 초기 데이터 세팅하는 방법 정리 (0) | 2025.03.07 |
| Spring 과 톰캣 (1) | 2025.01.08 |
| @PrePersist에 대하여 (0) | 2025.01.07 |
| Spring - Spring Boot - Swagger 설정하기 (0) | 2024.12.12 |