선언적으로 불변식을 간단하게 검증할 수 있다.
각 계층 사이 파라미터에 대한 유효성 검사를 실시할 수 있다.
1. 어노테이션들
|
어노테이션
|
설명 | 적용 가능 타입 |
| @NotNull | 해당 필드가 null이면 안되며 필수 입력 값 | 모든 참조 타입 (객체) |
| @NotEmpty | 문자열이나 컬렉션이 비어 있으면 안된다.. (null과 빈 값을 모두 허용하지 않음) | String, Collection, Map, Array |
| @NotBlank | 문자열이 공백을 포함한 빈 문자열이면 안된다. (공백만 있는 경우도 허용하지 않음) | String |
| @Size | 문자열, 컬렉션, 배열 등의 크기나 길이를 제한한다. | String, Collection, Map, Array |
| @Min | 숫자의 최소값을 제한한다. | int, long, short, byte, BigDecimal, BigInteger |
| @Max | 숫자의 최대값을 제한한다. | int, long, short, byte, BigDecimal, BigInteger |
| @Pattern | 정규 표현식으로 문자열 패턴을 제한한다. | String |
| 이메일 형식인지 검증한다. | String | |
| @Digits | 숫자의 정수부와 소수부의 자릿수를 제한한다. | String, BigDecimal, BigInteger |
| @Positive | 양수(0보다 큰 값)인지 검증한다. | int, long, short, byte, BigDecimal, BigInteger |
| @PositiveOrZero | 양수 또는 0인지 검증한다. | int, long, short, byte, BigDecimal, BigInteger |
| @Negative | 음수(0보다 작은 값)인지 검증한다. | int, long, short, byte, BigDecimal, BigInteger |
| @NegativeOrZero | 음수 또는 0인지 검증한다. | int, long, short, byte, BigDecimal, BigInteger |
| @Future | 해당 날짜가 미래인지 검증한다. | Date, Calendar, LocalDate, LocalDateTime, ZonedDateTime |
| @Past | 해당 날짜가 과거인지 검증한다. | Date, Calendar, LocalDate, LocalDateTime, ZonedDateTime |
| @FutureOrPresent | 해당 날짜가 미래이거나 현재인지 검증한다. | Date, Calendar, LocalDate, LocalDateTime, ZonedDateTime |
| @PastOrPresent | 해당 날짜가 과거이거나 현재인지 검증한다. | Date, Calendar, LocalDate, LocalDateTime, ZonedDateTime |
| @AssertTrue | 필드 값이 true인지 검증한다. | boolean, Boolean |
| @AssertFalse | 필드 값이 false인지 검증한다. | boolean, Boolean |
| @CreditCardNumber | 신용카드 번호 형식이 유효한지 검증한다. | String |
| @Length | 문자열의 길이를 제한한다. @Size와 유사하지만, 주로 Hibernate Validator에서 사용된다. | String |
| @Range | 숫자의 범위를 제한한다. @Min과 @Max의 대체로 사용된다. | int, long, short, byte, BigDecimal, BigInteger |
| @URL | 유효한 URL 형식인지 검증한다. | String |
| @Valid | 해당 필드가 포함된 객체가 유효한지 검증한다. 객체 필드 내의 어노테이션을 적용할 때 사용한다. | 모든 참조 타입 (객체) |
| @Null | 해당 필드가 null이어야 함을 검증한다. | 모든 참조 타입 (객체) |
| @DecimalMin | BigDecimal이나 BigInteger 타입의 최소값을 설정한다. @Min보다 정밀도를 지원한다. | BigDecimal, BigInteger, String, byte, short, int, long |
| @DecimalMax | BigDecimal이나 BigInteger 타입의 최대값을 설정한다. @Max보다 정밀도를 지원한다. | BigDecimal, BigInteger, String, byte, short, int, long |
| @PastOrPresent | 날짜가 과거 또는 현재인지 검증한다. | Date, Calendar, LocalDate, LocalDateTime, ZonedDateTime |
<출처: https://jh4dev.tistory.com/44>
2. @Valid 동작 과정
요청이 들어오면, DispatcherServlet -> HandlerMapping -> HandlerAdapter 순으로 동작하게 되고,
여기서 실제로 컨트롤러 메서드는 RequestMappingHandlerAdapter가 호출한다.
이때, @RequestBody는 RequestResponseBodyMethodProcessor가 객체 변환,DataBinder 생성, 유효성 검사 등을 수행한다.
2-1. RequestMappingHandlerAdapter(컨트롤러 매핑)
HTTP 요청
↓
DispatcherServlet
↓
HandlerMapping
↓
HandlerAdapter
↓
Controller 메서드 실행
Spring MVC의 요청은 위와 같은 객체를 거친다.
이 중 컨트롤러 처리를위한 HandlerAdapter는 RequestMappingHandlerAdapter이다.
2-2. HandlerMethodArgumentResolver(컨트롤러의 파라미터 매핑)
RequestMappingHandlerAdapter에서는 각 컨트롤러 메서드의 파라미터에 대해 resolve를 수행한다.
즉, 객체 바인딩, 검증 등을 한다는 말이다.
public interface HandlerMethodArgumentResolver {
boolean supportsParameter(MethodParameter parameter);
@Nullable Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
}
이 두 가지 메서드로 커스텀을 진행할 수 있겠다.
다시 돌아와,
@PostMapping
public void save(@Valid @RequestBody UserRequest request) {
}
이러한 코드가 있을 때, RequestResponseBodyMethodProcessor 라는 객체가 해당 UserRequest를 처리하기 위해 선택된다.
중요한 점은 각각 파라미터 별 수행이다.
2-3. RequestResponseBodyMethodProcessor
Json -> 객체 바인딩, 검증 등을 담당한다.
@Override
public @Nullable Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
parameter = parameter.nestedIfOptional();
Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
if (binderFactory != null) {
String name = Conventions.getVariableNameForParameter(parameter);
ResolvableType type = ResolvableType.forMethodParameter(parameter);
WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name, type);
if (arg != null) {
validateIfApplicable(binder, parameter); //여기서 수행
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
}
}
if (mavContainer != null) {
mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
}
}
return adaptArgumentIfNecessary(arg, parameter);
}
validateIfApplicable()에서
1. @Valid, @Validated 등 검증 트리거 어노테이션이 있는지 찾는다.
2. 해당 파라미터 내부에서 검증 유형 어노테이션을 찾아 검사한다.(리플렉션 사용)
다시 정리하자면, @Valid는 컨트롤러에서 Json, form등 요청이 객체로 바인딩 되는 어노테이션이 있는 파라미터(@RequestBody, @ModelAttribute, @RequestParam 등)에 선언할 수 있는 어노테이션이다.
3. @Validated 동작 과정
@Validated 또한 동일한 검증 어노테이션들을 사용한다.
다만, 트리거가 다르다.
@Validated
@Service
public class UserService {
public void save(@Valid UserRequest request) {
}
}
위와 같은 클래스가 빈으로 등록 시 프록시를 생성한다.
프록시를 통해 파라미터들을 검증한다.
3-1. 그룹 검증
@Validated가 붙은 검증은 그룹 검증을 사용할 수 있다.
//그룹 정의
public interface Create {}
public interface Update {}
==========================================
//검증 정의
public class UserRequest {
@NotBlank(groups = Create.class)
private String name;
@NotNull(groups = Update.class)
private Long id;
}
==========================================
// 검증
@Validated(Create.class)
@Service
public class UserService {
public void create(@Valid UserRequest request) {
}
}
이렇게 하면, 특정 그룹만 검증할 수 있다.
'스프링 프레임 워크' 카테고리의 다른 글
| [JAVA + SpringBoot] 어노테이션과 리플렉션 (0) | 2025.12.06 |
|---|---|
| 클래스 로더와 파일 읽어오기 (0) | 2025.11.28 |
| 스프링 빈 (0) | 2025.11.23 |
| 스프링 빈 관리 프로젝트 (0) | 2025.11.23 |
| 빈과 빈 컨텍스트 그리고 @Transactional에 대하여 (0) | 2025.03.18 |