JSR303数据校验Bean Validation
后端校验技术
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
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。