public class OrderItemRequest {
@NotNull(message = "name is not null")
@Length(max=50)
private String name;
@Min(value = 0, message = "price is over zero")
private int unitPrice;
@Min(value = 1, message = "price is over zero")
private int unitCount;
}
@PostMapping("/test")
public ApiResult<OrderDto> test(
@RequestBody @NotEmpty @Valid List<OrderItemRequest> items
) {
// 생략
}
@Override
public final <T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups) {
Contracts.assertNotNull( object, MESSAGES.validatedObjectMustNotBeNull() );
sanityCheckGroups( groups );
@SuppressWarnings("unchecked")
Class<T> rootBeanClass = (Class<T>) object.getClass();
BeanMetaData<T> rootBeanMetaData = beanMetaDataManager.getBeanMetaData( rootBeanClass );
if ( !rootBeanMetaData.hasConstraints() ) {
return Collections.emptySet();
}
BaseBeanValidationContext<T> validationContext = getValidationContextBuilder().forValidate( rootBeanClass, rootBeanMetaData, object );
ValidationOrder validationOrder = determineGroupValidationOrder( groups );
BeanValueContext<?, Object> valueContext = ValueContexts.getLocalExecutionContextForBean(
validatorScopedContext.getParameterNameProvider(),
object,
validationContext.getRootBeanMetaData(),
PathImpl.createRootPath()
);
return validateInContext( validationContext, valueContext, validationOrder );
}
if ( !rootBeanMetaData.hasConstraints() )
제약 조건에 걸리면서 emptySet()을 반환하고 종료된다.@RestController
@Validated // 이 어노테이션을 클래스 레벨에 붙여 준다.
public class Apis {
// 메소드는 기존과 동일하다.
@PostMapping("/test")
public ApiResult<OrderDto> test(
@RequestBody @NotEmpty @Valid List<OrderItemRequest> items
) {
// 생략
}
}
@RestControllerAdvice
public class ControllerExceptionAdvice {
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity error(ConstraintViolationException e) {
return ResponseEntity.ok().body(ApiResult.failed(e.getMessage()));
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity error(MethodArgumentNotValidException e) {
return ResponseEntity.ok().body(ApiResult.failed(e.getBindingResult().getAllErrors().get(0).getDefaultMessage()));
}
}
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.SpringValidatorAdapter;
import org.springframework.web.bind.MethodArgumentNotValidException;
import javax.validation.Validation;
import java.util.Collection;
@Component
public class CustomCollectionValidator implements Validator {
private SpringValidatorAdapter validator;
public CustomCollectionValidator() {
this.validator = new SpringValidatorAdapter(
Validation.buildDefaultValidatorFactory().getValidator()
);
}
@Override
public boolean supports(Class clazz) {
return true;
}
@Override
public void validate(Object target, Errors errors) {
if(target instanceof Collection){
Collection collection = (Collection) target;
for (Object object : collection) {
validator.validate(object, errors);
}
} else {
validator.validate(target, errors);
}
}
}
위와 같이 CustomValidator를 만들어 준뒤 controller class에 DI 받아온다
private final CustomCollectionValidator customCollectionValidator;
// 생성자 코드 생략
@PostMapping("test")
public ApiResult<OrderDto> createOrder(
@RequestBody @Valid List<OrderItemRequest> items, BindingResult bindingResult
) {
customCollectionValidator.validate(items, bindingResult);
if(bindingResult.hasError()) {
//error 처리
}
//생략
}
더 깔끔한 방법은 뭘까... 정답을 아시면 알려주세요..
좋은 글 감사합니다 미즈님~_~