数据校验

数据校验

element前端自定义校验规则

  • image-20220601141746038

  • :rules="dataRule" 绑定数据校验规则方法

  •  
    firstLetter: [
              {
                validator: (rule, value, callback) => {
                    if (value == "") {
                      callback(new Error("首字母必须填写不能为空"));
                    } else if (!/^[a-zA-Z]$/.test(value)) {
                      callback(new Error("首字母必须a-z或者A-Z之间"));
                    } else {
                      callback();
                    }
                },
                trigger: 'blur'
              }
            ],
    
  • firstLetter是prop属性值 validator自定义校验规则 trigger 出发时间 rule 当前自定义校验规则对象 callback 回调函数

后端数据校验

使用JSR303规则进行校验
什么是jsr 303

image-20220601234823773

  • jsr303 常用注解

    image-20220601234917938

    以上是 bean validation自带的注解hibernate validation 在上面的基础上增加了一些注解

    image-20220601235120722

简单校验
  • 引入pom依赖

     <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-validation</artifactId>
            </dependency>
    
  • 在需要进行数据校验的类中添加注解,例如:

    package com.cui.gulimall.modules.product.dto;
    
    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.Data;
    
    import javax.validation.constraints.NotEmpty;
    import java.io.Serializable;
    import java.util.Date;
    
    
    /**
     * 品牌
     *
     * @author cui cui@gmail.com
     * @since 1.0.0 2022-05-25
     */
    @Data
    @ApiModel(value = "品牌")
    public class BrandDTO implements Serializable {
        private static final long serialVersionUID = 1L;
    
    	@ApiModelProperty(value = "品牌id")
    	private Long brandId;
    
    	@ApiModelProperty(value = "品牌名")
    	@NotEmpty
    	private String name;
    
    	@ApiModelProperty(value = "品牌logo地址")
    	private String logo;
    
    	@ApiModelProperty(value = "介绍")
    	private String descript;
    
    	@ApiModelProperty(value = "显示状态[0-不显示;1-显示]")
    	private Integer showStatus;
    
    	@ApiModelProperty(value = "检索首字母")
    	private String firstLetter;
    
    	@ApiModelProperty(value = "排序")
    	private Integer sort;
    
    
    }
    
  • 在controller层中添加 @Validated注解或者@Valid 开启数据校验

      @PostMapping("save")
        @ApiOperation("保存")
        @LogOperation("保存")
        public Result save(@Validated @RequestBody  BrandDTO dto,
                           BindingResult bindingResult) {
            System.out.println(ObjectUtils.isEmpty(bindingResult));
    
            if (bindingResult.hasErrors()) {
                List<FieldError> fieldErrors = bindingResult.getFieldErrors();
                System.out.println(fieldErrors.isEmpty());
    
                return new Result().error("数据校验失败");
            }
            //效验数据
            ValidatorUtils.validateEntity(dto, AddGroup.class, DefaultGroup.class);
    
            brandService.save(dto);
    
            return new Result();
        }
    
  • BindingResult 封装了数据校验结果等信息 hasErrors 获得数据校验结果 如果校验失败返回false

  • 在进行数据校验的时候一定要看清参数位置写的是哪个类不然就会像我这个虎比一样找半天没注意参数位置

分组校验
  • 列入:当我们添加数据时不需要上传用户id但是当我们修改数据时需要根据用户id修改,所以需要有两组不同的校验规则

  • 每一个校验注解都含有这三个属性

    String message() default "{javax.validation.constraints.NotEmpty.message}";
    
    	Class<?>[] groups() default { };
    
    	Class<? extends Payload>[] payload() default { };
    

    其中groups为分组的属性, 类型为Class<?>[]没有什么特殊意义所以只需要定义几个接口来区分不同分组的校验规则

  • 数据接收类代码

    package com.cui.gulimall.modules.product.dto;
    
    import com.cui.gulimall.modules.product.check.AddCheck;
    import com.cui.gulimall.modules.product.check.ModifyCheck;
    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.Data;
    import org.hibernate.validator.constraints.URL;
    
    import javax.validation.constraints.*;
    import java.io.Serializable;
    import java.util.Date;
    
    
    /**
     * 品牌
     *
     * @author cui cui@gmail.com
     * @since 1.0.0 2022-05-25
     */
    @Data
    @ApiModel(value = "品牌")
    public class BrandDTO implements Serializable {
        private static final long serialVersionUID = 1L;
    
    	@ApiModelProperty(value = "品牌id")
    	@NotNull(message = "id不能为空",groups = {ModifyCheck.class})
    	@Null(message = "新增品牌id不能指定",groups = {AddCheck.class})
    	private Long brandId;
    
    	@ApiModelProperty(value = "品牌名")
    	@NotEmpty(message = "品牌名称不能为空",groups = {AddCheck.class,ModifyCheck.class})
    	private String name;
    
    	@ApiModelProperty(value = "品牌logo地址")
    	@URL(message = "logo地址不能为空" ,groups = {AddCheck.class,ModifyCheck.class})
    	private String logo;
    
    	@ApiModelProperty(value = "介绍")
    	private String descript;
    
    	@ApiModelProperty(value = "显示状态[0-不显示;1-显示]")
    	@NotNull(groups = {AddCheck.class},message = "显示状态不能为空")
    	@Min(value = 0,groups = {AddCheck.class,ModifyCheck.class},message = "该数据只能为0或1")
    	@Max(value = 1,groups = {AddCheck.class,ModifyCheck.class},message = "该数据只能为0或1")
    	private Integer showStatus;
    
    	@ApiModelProperty(value = "检索首字母")
    	@Pattern(regexp = "^[a-zA-Z]$",message = "必须是一个字母",groups = {AddCheck.class, ModifyCheck.class})
    	private String firstLetter;
    
    	@ApiModelProperty(value = "排序")
    	@Min(value = 0,message = "排序数字必须大于0",groups = {AddCheck.class, ModifyCheck.class})
    	private Integer sort;
    
    
    }
    
  • 控制层代码

     @PostMapping("save")
        @ApiOperation("保存")
        @LogOperation("保存")
        public Result save(@Validated(AddCheck.class) @RequestBody BrandDTO dto,
                           BindingResult bindingResult) {
            System.out.println(ObjectUtils.isEmpty(bindingResult));
    
            if (bindingResult.hasErrors()) {
                List<FieldError> fieldErrors = bindingResult.getFieldErrors();
    
                Map<String, Object> map = new HashMap<>();
    
                fieldErrors.forEach(fieldError -> {
                    map.put(fieldError.getField(), fieldError.getDefaultMessage());
                });
                return new Result().error(map);
            }
            //效验数据
            ValidatorUtils.validateEntity(dto, AddGroup.class, DefaultGroup.class);
    
            brandService.save(dto);
    
            return new Result();
        }
    
  • 嵌套校验:就是在一个类中需要包含另一个类,而另一个类也需要校验. 需要在那个类的属性也需要校验 只需在那个嵌套的类属性上添加@Valid 如果不添加则不会校验

  • 全局异常处理

    package com.cui.gulimall.modules.product.ex;
    
    import com.cui.gulimall.common.utils.Result;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.http.HttpStatus;
    import org.springframework.validation.BindException;
    import org.springframework.validation.ObjectError;
    import org.springframework.web.bind.MethodArgumentNotValidException;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.RestControllerAdvice;
    
    import javax.validation.ConstraintViolation;
    import javax.validation.ConstraintViolationException;
    import java.util.stream.Collectors;
    
    /**
     * @author 崔令雨
     * @date 2022/6/2 11:07
     * @Version 1.0
     */
    @RestControllerAdvice
    @Slf4j
    public class GlobalExceptionHandl {
    
    
        @ExceptionHandler({MethodArgumentNotValidException.class,
                BindException.class,
                ConstraintViolationException.class})
        public Result abnormalDataValidation(Exception e) {
    
            log.info("进入全局异常处理");
    
            if (e instanceof MethodArgumentNotValidException) {
                MethodArgumentNotValidException exception = (MethodArgumentNotValidException) e;
    
                return new Result().error(HttpStatus.BAD_REQUEST.value(),
                        exception
                                .getBindingResult()
                                .getAllErrors()
                                .stream()
                                .map(ObjectError::getDefaultMessage)
                                .collect(Collectors.joining(";")));
            }
            if (e instanceof ConstraintViolationException) {
                ConstraintViolationException exception = (ConstraintViolationException) e;
                return new Result().error(HttpStatus.BAD_REQUEST.value(),
                        exception.getConstraintViolations()
                                .stream()
                                .map(ConstraintViolation::getMessage)
                                .collect(Collectors.joining(";")));
            }
            if (e instanceof BindException) {
                BindException bindException = (BindException) e;
    
                return new Result().error(HttpStatus.BAD_REQUEST.value(),
                        bindException.getAllErrors()
                                .stream()
                                .map(ObjectError::getDefaultMessage)
                                .collect(Collectors.joining(";")));
            }
    
            return new Result();
        }
    
        @ExceptionHandler(RuntimeException.class)
        public Result exceptionHandler(Exception e) {
            return new Result().error(e.getMessage());
        }
    
    }
    
    
自定义校验
  • 创建自定义注解

    package com.cui.gulimall.modules.product.validator;
    
    import javax.validation.Constraint;
    import javax.validation.Payload;
    import java.lang.annotation.Documented;
    import java.lang.annotation.Repeatable;
    import java.lang.annotation.Retention;
    import java.lang.annotation.Target;
    
    import static java.lang.annotation.ElementType.*;
    import static java.lang.annotation.RetentionPolicy.RUNTIME;
    
    /**
     * @author 崔令雨
     * @date 2022/6/2 11:33
     * @Version 1.0
     */
    @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
    @Retention(RUNTIME)
    @Repeatable(EnumString.List.class)
    @Documented
    @Constraint(validatedBy = EnumStringValidator.class)//标明由哪个类执行校验逻辑
    public @interface EnumString {
        String message() default "value not in enum values.";
    
        Class<?>[] groups() default {};
    
        Class<? extends Payload>[] payload() default {};
    
        /**
         * @return date must in this value array
         */
        String[] value();
    
        /**
         * Defines several {@link EnumString} annotations on the same element.
         *
         * @see EnumString
         */
        @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
        @Retention(RUNTIME)
        @Documented
        @interface List {
            EnumString[] value();
        }
    }
    
    
  • 创建自定义校验类

    package com.cui.gulimall.modules.product.validator;
    
    import javax.validation.ConstraintValidator;
    import javax.validation.ConstraintValidatorContext;
    import java.util.Arrays;
    import java.util.List;
    
    /**
     * @author 崔令雨
     * @date 2022/6/2 11:35
     * @Version 1.0
     */
    public class EnumStringValidator implements ConstraintValidator<EnumString, String> {
    
        private List<String> list;
    
        @Override
        public void initialize(EnumString constraintAnnotation) {
            list = Arrays.asList(constraintAnnotation.value());
        }
    
        @Override
        public boolean isValid(String value, ConstraintValidatorContext context) {
    
            if (value == null) {
                return false;
            }
            return list.contains(value);
        }
    }
    
    
  • 在属性上添加校验属性

    @ApiModelProperty(value = "显示状态[0-不显示;1-显示]")
    @EnumString(value = {"1", "0"}, message = "显示状态只能为0或1", groups = AddCheck.class)
    private Integer showStatus;
    
posted @ 2022-06-02 12:04  01cui  阅读(122)  评论(0编辑  收藏  举报