JSR303数据校验Bean Validation

2021-09-23  本文已影响0人  万事俱备就差一个程序员了

后端校验技术

JSR303技术,JSR-303 是JAVA EE 6 中的一项子规范,叫做Bean Validation,Hibernate Validator 是 Bean Validation 的参考实现 . Hibernate Validator 提供了 JSR 303 规范中所有内置 constraint 的实现,除此之外还有一些附加的 constraint,在springboot中使用也比较简便。

1.给需要校验的字段添加校验注解

javax.validation.constraints包下有许多的注解:

img

常用的校验注解补充:

@NotBlank检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.@NotEmpty检查约束元素是否为NULL或者是EMPTY.@Length被检查的字符串长度是否在指定的范围内@CreditCardNumber信用卡验证@Email验证是否是邮件地址,如果为null,不进行验证,算通过验证。@URL验证是否是一个url地址

注意:一个字段可以标注多个校验注解。

2.给需要检验的方法标准@Valid

image.png

如果只标注了注解字段,不启用@valid的是不生效的。

3.捕捉校验异常,返回提示信息

对于程序可能有很多的校验注解,可能会出现多个校验错误,我们可以定义一个统一的异常处理类,帮我们捕捉校验错误并返回提示信息,这里可以利用Spring的ControllerAdvice技术。

(1).编写统一异常处理类

packageio.renren.app.exception;importio.renren.common.utils.R;importlombok.extern.slf4j.Slf4j;importorg.springframework.validation.BindingResult;importorg.springframework.web.bind.MethodArgumentNotValidException;importorg.springframework.web.bind.annotation.ControllerAdvice;importorg.springframework.web.bind.annotation.ExceptionHandler;importjava.util.HashMap;importjava.util.Map;/**

* @Author zunhui

* @Email Qiangzunhui@126.com

* @Date 2020/8/5 13:45

* @Description 统一异常处理

*/@RestControllerAdvice(basePackages="io.renren.app.controller")@Slf4jpublicclassAppManageControllerAdvices{@ExceptionHandler(value=MethodArgumentNotValidException.class)publicRhandleVaildException(MethodArgumentNotValidException e){log.error("数据校验出现问题{},异常类型:{}",e.getMessage(),e.getClass());BindingResult bindingResult=e.getBindingResult(); Map<String,String>errorMap=new HashMap<>();bindingResult.getFieldErrors().forEach((fieldError)->{errorMap.put(fieldError.getField(),fieldError.getDefaultMessage());});returnR.error(400,"数据校验失败").put("data",errorMap);}@ExceptionHandler(value=Throwable.class)publicRhandleException(Throwable throwable){ log.error("错误:",throwable);returnR.error(500,"系统未知异常");}}

(2)出现异常将异常抛出

对于校验可能会出现的异常,我们将其抛出,不予捕捉感知,都交给我们的统一异常处理类处理,返回提示信息。

image.png

4.分组校验(多场景的复杂校验)

对于不同的操作,字段校验的规则和数量可能是不同的,所以我们将校验规则分组,对于不同的操作进行不同的校验组,使用groups属性。

1.想要使用分组校验功能,根据文档我们首先编写不同的校验组接口,只编写空接口,用来表示就可以了:

//新增分组publicinterfaceAddGroup{}//修改分组publicinterfaceUpdateGroup{}

2.编写好分组接口,对于不同的检验规则,标注不同的分组标识:

@NotNull(message ="修改必须指定id",groups ={UpdateGroup.class})@Null(message ="新增不能指定id",groups ={AddGroup.class})@TableIdprivate Long Id;@NotBlank(message="名称必须提交",groups={AddGroup.class,UpdateGroup.class})private String name;

3.在controller方法上标注不同的分组校验,使用@Validated注解:

//保存@RequestMapping("/save")//@RequiresPermissions("product:brand:save")publicRsave(@Validated({AddGroup.class})@RequestBodyBrandEntity brand){brandService.save(brand);returnR.ok();}

@Validated({AddGroup.class}):启用不同的分组校验规则。

注意:在使用分组校验的情况下,对于没有标注分组的校验规则,默认是不生效的,只有标注了分组的校验规则才会生效。

5.自定义校验

1.编写一个自定义的校验注解

导入依赖:

<dependency><groupId>javax.validation</groupId><artifactId>validation-api</artifactId><version>2.0.1.Final</version></dependency>

编写自定义校验注解

packagecom.zunhui.common.valid;importjavax.validation.Constraint;importjavax.validation.Payload;importjava.lang.annotation.Documented;importjava.lang.annotation.Retention;importjava.lang.annotation.Target;importstatic java.lang.annotation.ElementType.*;importstatic java.lang.annotation.ElementType.TYPE_USE;importstatic java.lang.annotation.RetentionPolicy.RUNTIME;@Documented//指定校验器@Constraint(validatedBy={com.zunhui.common.valid.ListValueConstraintValidator.class})@Target({METHOD,FIELD,ANNOTATION_TYPE,CONSTRUCTOR,PARAMETER,TYPE_USE})@Retention(RUNTIME)public@interfaceListValue{//配置默认的提示消息,新建配置文件ValidationMessages.properties在其中配置://com.zunhui.common.valid.ListValue.message = 必须提交指定的值Stringmessage()default="{com.zunhui.common.valid.ListValue.message}";Class<?>[]groups()default{}; Class<?extends Payload>[]payload()default{}; int[]vals()default{};}

用来验证自定义的字段值,非0即1。

2.编写一个自定义的校验器

packagecom.zunhui.common.valid;importjavax.validation.ConstraintValidator;importjavax.validation.ConstraintValidatorContext;importjava.util.HashSet;importjava.util.Set;publicclassListValueConstraintValidatorimplementsConstraintValidator<ListValue,Integer>{privateSet<Integer>set=newHashSet<Integer>();//初始化方法publicvoidinitialize(ListValueconstraintAnnotation){int[]vals=constraintAnnotation.vals();for(intval:vals){set.add(val);}}//判断是否校验成功/**

* @param value 需要校验的值

* @param context

* @return

*/publicbooleanisValid(Integervalue,ConstraintValidatorContextcontext){returnset.contains(value);}}

3.关联自定义的校验器和自定义的校验注解

@Constraint(validatedBy ={com.zunhui.common.valid.ListValueConstraintValidator.class})

在自定义的校验注解中添加自己的校验器,就关联好了,一个校验注解可以指定多个不同类型的校验器,适配不同类型的校验。关联完成就可以使用了。

4.使用

//校验指定字段非0即1@ListValue(valus={0,1},message="提示消息,不指定则默认读取配置文件中的")privateInteger showStatus;

测试:

save方法传参: showStatus: 3 返回:

image.png

自定义校验注解生效。

作者:稚友22

链接:https://www.jianshu.com/p/d2ddd856cce2

来源:简书

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

上一篇下一篇

猜你喜欢

热点阅读