当前位置: 首页 > 后端技术 > Java

SpringBoot自定义校验注解

时间:2023-04-01 19:07:29 Java

校验注解的作用系统在执行业务逻辑之前,会对输入的数据进行校验,检查数据是否有效合法。因此,我们可能会写很多ifelse之类的判断逻辑,尤其是同一条数据出现在不同的方法中时,验证逻辑代码会重复出现,造成代码冗余,可读性和可维护性差。自定义验证注解的引入依赖于Hibernate框架。有一个组件叫做hibernate-validator,专门用于数据校验。在普通的Spring项目中,虽然数据层没有使用Hibernate作为ORM框架,但是数据往往会集成hibernate-validator。查看。org.hibernate.validatorhibernate-validator6.1.7.Final下面写一个用于URL验证的注解来实现一个简单的网站信息管理的URL验证,我们也是使用现成的apache工具包中提供的验证工具来做验证。commons-validatorcommons-validator1.7实现注解验证annotations/***将注解信息包含在javadoc中*/@Documented/***1.RetentionPolicy.SOURCE:注解只保留在源文件中。当Java文件被编译成class文件时,注解被丢弃;*2.RetentionPolicy.CLASS:该注解保留在class文件中,但在jvm加载class文件时放弃,*这是默认的生命周期;*3、RetentionPolicy.RUNTIME:该注解不仅保存在class文件中,jvm加载class文件后仍然存在;**一般情况下,如果需要在运行时动态获取注解信息,只能使用RUNTIME注解,比如@Deprecated使用RUNTIME注解*如果想在编译时进行一些预处理操作,比如生成一些辅助代码(比如作为ButterKnife),使用CLASS注释;*Ifonly使用SOURCE注解做一些检查操作,比如@Override和@Deprecated。*/@Retention(RetentionPolicy.RUNTIME)/***作用于字段*TYPE-作用于类*FILED-作用于属性*METHOD-作用于方法*CONSTRUCTION-作用于构造函数*PARAM-作用于方法参数*,允许多种情况:@Target({ElementType.FIELD,ElementType.METHOD})*/@Target(ElementType.FIELD)/***对应验证类*/@Constraint(validatedBy=IsUrlValidator.class)public@interfaceIsUrl{/***验证是否强*@return*/booleanrequired()defaulttrue;/***验证失败返回信息*@return*/Stringmessage()default"PleaseenterCorrecturl";/***所属组,即如果有组,则只检查该组的参数*@return*/Class[]groups()default{};/***主要针对bean,很少用到**@returnpayload*/Class[]payload()default{};}验证类验证类需要实现ConstraintValidator接口,第一个泛型是注解,第二个是验证的数据类型。要实现此接口,必须重写isValid()方法以实现主要验证逻辑。公共类IsUrlValidator实现ConstraintValidator{privatebooleanisRequired;/***初始化,是否获取强验证*@paramconstraintAnnotation*/@Overridepublicvoidinitialize(IsUrlconstraintAnnotation){isRequired=constraintAnnotation.required();}@OverridepublicbooleanisValid(Strings,ConstraintValidatorContextcontext){if(!isRequired){返回真;}else{UrlValidator验证器=UrlValidator.getInstance();返回validator.isValid(s);}}}使用自定义注解创建Insert和Update组来区分和启用验证。用于分组的类需要继承javax.validation.groups.Default接口publicinterfaceUpdateextendsDefault{}publicinterfaceInsertextendsDefault{}创建一个WebSite类,对其进行url、alternateUrl验证,字段验证时进行该字段分别属于Insert组和Update组。publicclassWebSite{/***id*/privateIntegerid;/***网站名称*/privateStringname;/***URL*/@IsUrl(groups=Insert.class)privateStringurl;/***AlternateURL*/@IsUrl(groups=Update.class)privateStringalternateUrl;}具体校验方式如下,insert接口校验Insert组,即校验url属性,以及Update组在updateAlternate接口验证Verify,即验证alternateUrl字段。@RestController@RequestMapping("/website")publicclassWebSiteController{@RequestMapping("/insert")publicvoidinsert(@RequestBody@Validated(Insert.class)WebSitesite){System.out.println(site);RequestMapping("/updateAlternate")publicvoidupdateAlternateUrl(@RequestBody@Validated(Update.class)WebSitesite){System.out.println(site);}}如果验证失败,代码会抛出MethodArgumentNotValidException异常,我们实现了一个统一的异常处理类,用于处理异常错误并返回验证提示信息。@ControllerAdvice@Slf4jpublicclassGlobalExceptionHandler{//处理接口参数数据格式错误异常@ExceptionHandler(value=MethodArgumentNotValidException.class)@ResponseBodypublicObjecterrorHandler(HttpServletRequestrequest,MethodArgumentNotValidExceptionerror){ListeResults(getAllErrors();Stringmessage=allErrors.stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining(";"));log.error("{}请求,出现参数校验异常:{}",request.getServletPath(),message);returnmessage;}}使用http工具调用接口并返回相关信息,首先使用错误的url参数调用insert接口,验证失败,但是调用updateAlternate接口可以通过。POSThttp://localhost:8080/website/insertContent-Type:application/json{"id":1,"name":"百度","url":"https://www.baidu.com/","alternateUrl":"https://www.baidu.com/"}###POSThttp://localhost:8080/website/updateAlternateContent-Type:application/json{"id":1,"name":"Baidu","url":"https://www.baidu.com/","alternateUrl":"https://www.baidu.com/"}调用insert接口的返回和日志打印如下HTTP/1.1200Content-Type:text/plain;charset=UTF-8Content-Length:21Date:Wed,02Mar202215:30:23GMTKeep-Alive:timeout=60Connection:keep-alivePleaseenterthecorrecturl----------------------------------xxx.GlobalExceptionHandler:/website/insert请求,出现参数校验异常:请输入正确的url常用验证Annotation注解定义@Null被注解的元素必须为null@NotNull被注解的元素不能为null@AssertTrue被注解的元素必须为true@AssertFalse被注解的元素必须为false@Min(value)的带注释的元素必须是一个数字,其值必须大于或等于指定的最小值@Max(value)带注释的元素必须是一个数字,其值必须小于或等于指定的最大值@DecimalMin(value)被注解的元素必须是一个数字,其值必须大于或等于指定的最小值@DecimalMax(value)被注解的元素必须是一个数字,其值必须小于等于指定值最大值@Size(max,min)被注解的元素的大小必须在指定范围内,元素必须是集合,代表集合的个数@Digits(integer,fraction)被注解的元素必须是数字,它的值必须在可接受的范围内@Past被注解的元素必须是过去的日期@Future被注解的元素必须是未来的日期@Length(min=,max=)被注解的字符串的大小必须在指定的范围内,必须是数组或字符串。如果微阵列表示为阵列的长度,则字符串表示为字符串的长度。@NotEmpty被注解的字符串必须为非空@Range(min=,max=)被注解的元素必须在合适的范围内@NotBlank被注解的字符串必须为非空@Pattern(regexp=)正则表达式验证@Valid对象级联验证,即验证对象中对象的属性