Spring方法级别数据校验:@Validated + MethodValidationPostProcessor (3)

文首虽然已经给了一个使用示例,但是那毕竟只是局部。在实际生产使用中,比如上面理论更重要的是一些使用细节(细节往往是区分你是不是高手的地方),这里从我使用的经验中,总结如下几点供给大家参考(基本算是分享我躺过的坑)

使用@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>: 不能为空 ...

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpdwfp.html