• 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).编写统一异常处理类
    package io.renren.app.exception;
    ​
    import io.renren.common.utils.R;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.validation.BindingResult;
    import org.springframework.web.bind.MethodArgumentNotValidException;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    ​
    import java.util.HashMap;
    import java.util.Map;
    ​
    /**
     * @Author zunhui
     * @Email Qiangzunhui@126.com
     * @Date 2020/8/5 13:45
     * @Description 统一异常处理
     */
    @RestControllerAdvice(basePackages = "io.renren.app.controller")
    @Slf4j
    public class AppManageControllerAdvices {
    ​
     @ExceptionHandler(value = MethodArgumentNotValidException.class)
     public R handleVaildException(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());
     });
     return R.error(400, "数据校验失败").put("data", errorMap);
     }
    ​
     @ExceptionHandler(value = Throwable.class)
     public R handleException(Throwable throwable) {
    ​
     log.error("错误:", throwable);
     return R.error(500, "系统未知异常");
     }
    }
    
    (2)出现异常将异常抛出

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

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

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

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

    //新增分组
    public interface AddGroup{
    ​
    }
    //修改分组
    public interface UpdateGroup{
    ​
    }
    

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

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

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

     //保存
     @RequestMapping("/save")
     //@RequiresPermissions("product:brand:save")
     public R save(@Validated({AddGroup.class}) @RequestBody BrandEntity brand){
     brandService.save(brand);
     return R.ok();
     }
    

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

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

    5.自定义校验

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

    导入依赖:

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

    编写自定义校验注解

    package com.zunhui.common.valid;
    ​
    import javax.validation.Constraint;
    import javax.validation.Payload;
    import java.lang.annotation.Documented;
    import java.lang.annotation.Retention;
    import java.lang.annotation.Target;
    ​
    import static java.lang.annotation.ElementType.*;
    import static java.lang.annotation.ElementType.TYPE_USE;
    import static 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 @interface ListValue {
     //配置默认的提示消息,新建配置文件ValidationMessages.properties在其中配置:
     //com.zunhui.common.valid.ListValue.message = 必须提交指定的值
     String message() default="{com.zunhui.common.valid.ListValue.message}";
    
     Class<?>[] groups() default { };
    ​
     Class<? extends Payload>[] payload() default { };
    ​
     int[] vals() default { };
    }
    

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

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

    package com.zunhui.common.valid;
    ​
    import javax.validation.ConstraintValidator;
    import javax.validation.ConstraintValidatorContext;
    import java.util.HashSet;
    import java.util.Set;
    ​
    public class ListValueConstraintValidator implements ConstraintValidator<ListValue,Integer> {
    ​
     private Set<Integer> set = new HashSet<Integer>();
     //初始化方法
     public void initialize(ListValue constraintAnnotation) {
     int[] vals = constraintAnnotation.vals();
     for (int val : vals) {
     set.add(val);
     }
     }
     //判断是否校验成功
     /**
     * @param value 需要校验的值
     * @param context
     * @return
     */
     public boolean isValid(Integer value, ConstraintValidatorContext context) {
     return set.contains(value);
     }
    }
    

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

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

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

    4.使用

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

    测试:

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

     
    image.png

    自定义校验注解生效。



    作者:稚友22
    链接:https://www.jianshu.com/p/d2ddd856cce2
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    QT5笔记:1.UI文件设计与运行机制
    QStringListModel的使用
    D pid(16916) tid(19140) 14:05:45 EdgeSnapFeature::PostExitSizeMove: WM_TWINVIEW_SHOW_GRIDLINES > off
    QT5笔记:3.手动撸界面和可视化托界面混合
    Qt QString的格式化与QString的拼接
    C# WinForm UDP 发送和接收消息
    关于Convert.ToUInt16(string? value, int fromBase);
    QT5笔记:2.可视化UI设计
    OpenCvSharp 打开rtsp视频并录制mp4文件
    C# List LinQ Lambda 表达式
  • 原文地址:https://www.cnblogs.com/suizhikuo/p/15325564.html
Copyright © 2020-2023  润新知