文首虽然已经给了一个使用示例,但是那毕竟只是局部。在实际生产使用中,比如上面理论更重要的是一些使用细节(细节往往是区分你是不是高手的地方),这里从我使用的经验中,总结如下几点供给大家参考(基本算是分享我躺过的坑):
使用@Validated去校验方法Method,不管从使用上还是原理上,都是非常简单和简约的,建议大家在企业应用中多多使用。
1、约束注解(如@NotNull)不能放在实体类上一般情况下,我们对于Service层验证(Controller层一般都不给接口),大都是面向接口编程和使用,那么这种@NotNull放置的位置应该怎么放置呢?
看这个例子:
public interface HelloService { Object hello(@NotNull @Min(10) Integer id, @NotNull String name); } @Validated(Default.class) @Slf4j @Service public class HelloServiceImpl implements HelloService { @Override public Object hello(Integer id, String name) { return null; } }约束条件都写在实现类上,按照我们所谓的经验,应该是不成问题的。但运行:
javax.validation.ConstraintDeclarationException: HV000151: A method overriding another method must not redefine the parameter constraint configuration, but method HelloServiceImpl#hello(Integer) redefines the configuration of HelloService#hello(Integer). at org.hibernate.validator.internal.metadata.aggregated.rule.OverridingMethodMustNotAlterParameterConstraints.apply(OverridingMethodMustNotAlterParameterConstraints.java:24) ...重说三:请务必注意请务必注意请务必注意这个异常是javax.validation.ConstraintDeclarationException,而不是错误校验错误异常javax.validation.ConstraintViolationException。请在做全局异常捕获的时候一定要区分开来~
异常信息是说parameter constraint configuration在校验方法入参的约束时,若是@Override父类/接口的方法,那么这个入参约束只能写在父类/接口上面~~~
至于为什么只能写在接口处,这个具体原因其实是和Bean Validation的实现产品有关的,比如使用的Hibernate校验,原因可参考它的此类:OverridingMethodMustNotAlterParameterConstraints
还需注意一点:若实现类写的约束和接口一模一样,那也是没问题的。比如上面若实现类这么写是没有问题能够完成正常校验的:
@Override public Object hello(@NotNull @Min(10) Integer id, @NotNull String name) { return null; }虽然能正常work完成校验,但需要深刻理解一模一样这四个字。简单的说把10改成9都会报ConstraintDeclarationException异常,更别谈移除某个注解了(不管多少字段多少注解,但凡只要写了一个就必须保证一模一样)。
关于@Override方法校验返回值方面:即使写在实现类里也不会抛ConstraintDeclarationException
另外@Validated注解它写在实现类/接口上均可~
最后你应该自己领悟到:若入参校验失败了,方法体是不会执行的。但倘若是返回值校验执行了(即使是失败了),方法体也肯定被执行了~~
2、@NotEmpty/@NotBlank只能哪些类型上?提出这个细节的目的是:约束注解并不是能用在所有类型上的。比如若你把@NotEmpty让它去验证Object类型,它会报错如下:
javax.validation.UnexpectedTypeException: HV000030: No validator could be found for constraint 'javax.validation.constraints.NotEmpty' validating type 'java.lang.Object'. Check configuration for 'hello.<return value>'需要强调的是:若标注在方法上是验证返回值的,这个时候方法体是已经执行了的,这个和ConstraintDeclarationException不一样~
对这两个注解依照官方文档做如下简要说明。@NotEmpty只能标注在如下类型
CharSequence
Collection
Map
Array
注意:""它是空的,但是" "就不是了
@NotBlank只能使用在CharSequence上,它是Bean Validation 2.0新增的注解~
3、接口和实现类上都有注解,以谁为准?这个问题有个隐含条件:只有校验方法返回值时才有这种可能性。
public interface HelloService { @NotEmpty String hello(@NotNull @Min(10) Integer id, @NotNull String name); } @Slf4j @Service @Validated(Default.class) public class HelloServiceImpl implements HelloService { @Override public @NotNull String hello(Integer id, String name) { return ""; } }运行案例,helloService.hello(18, "fsx");打印如下:
javax.validation.ConstraintViolationException: hello.<return value>: 不能为空 ...