问题阐述:
当前关于controller层的request的参数校验,经常会使用到javax.validation包下的@Valid注解,在对应的javabean中使用各种javax.validation.constraints下的各种注解完成校验。
但是当传输参数为list或者其他非object的collection时,会发现校验并不生效。
原因是这种方式是通过
org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor调用的org.hibernate.validator.internal.engine.ValidatorImpl中的validate方法进行校验,但仅仅只会校验object的各个属性,并不会校验list中的各个elements。
解决方案:配合@Validated使用@Valid
将@Validated放置在controller类上,同时继续使用@Valid和@requestBody在请求参数前,此时这种方式会通过
org.springframework.validation.beanvalidation.MethodValidationInterceptor调用org.hibernate.validator.internal.engine.ValidatorImpl中的validateParameters方法,该方法会校验list中的各个element。
区别:
传统的第一种方式会直接抛出400。第二种方式是经由controller类抛出ConstraintViolationException,第二种方式是更加普适的可以用于所有的类中方法的参数校验,并不专用于controller层,如果想获得类似第一种方式的exception,需要在@RestControllerAdvice的globalhandler做一下异常处理。
其他方案:
1⃣️可以尝试将传输的参数变为object,继而将list作为object的一个field,但是这种方式会要求调用方做相应的改动。
2⃣️将list变为一个javabean,实现类似如下:
@Data
public class ValidList<E> implements List<E> {
@Valid
@Delegate
private List<E> list = new ArrayList<>();
}