springboot+vue+element-ui实现前后端的全部校验

1、前端校验

el-form的表单校验


  
    
  
  
    
  
  
    
  
  
    提交
    重置
  

自定义校验器



data() {
      return {
        visible: false,
        dataForm: {
          brandId: 0,
          name: "",
          logo: "",
          descript: "",
          showStatus: "",
          firstLetter: "",
          sort: "",
        },
        dataRule: {
          name: [{required: true, message: "品牌名不能为空", trigger: "blur"}],
          logo: [
            {required: true, message: "品牌logo地址不能为空", trigger: "blur"},
          ],
          descript: [
            {required: true, message: "介绍不能为空", trigger: "blur"},
          ],
          showStatus: [
            {
              required: true,
              message: "显示状态[0-不显示;1-显示]不能为空",
              trigger: "blur",
            },
          ],
          firstLetter: [
            {
              validator: (rule, value, callback) => {
                if (value == "") {
                  callback(new Error("请输入首字母"));
                } else if (!(/^[a-zA-Z]$/).test(value)) {
                  callback(new Error("请输入英文字母"));
                } else {
                  callback();
                }

              }, trigger: "blur"
            },
          ],
          sort: [{
            validator: (rule, value, callback) => {
              if (value == '') {
                callback(new Error("请输入排序字段"));
              } else if (!Number.isInteger(value) || value < 0) {
                callback(new Error('排序字段必须是一个整数并且大于0'))
              } else {
                callback();
              }
            }, trigger: "blur"
          }],
        },
      };
    },

 

2、JSR303后端校验

后端的校验注解:

springboot+vue+element-ui实现前后端的全部校验_第1张图片

代码:

package com.atguigu.gulimall.product.entity;

import com.atguigu.common.valid.AddGroup;
import com.atguigu.common.valid.ListValue;
import com.atguigu.common.valid.UpdateGroup;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;

import java.io.Serializable;
import java.util.Date;

//import com.sun.istack.internal.NotNull;
import lombok.Data;
import org.hibernate.validator.constraints.URL;

import javax.validation.constraints.*;

/**
 * 品牌
 * 
 * @author pansd
 * @email [email protected]
 * @date 2022-02-23 16:02:02
 */
@Data
@TableName("pms_brand")
public class PmsBrandEntity implements Serializable {
	private static final long serialVersionUID = 1L;

	/**
	 * 品牌id
	 */
	@TableId
	@Null(message = "新增时不能填写品牌id",groups = {AddGroup.class}) //实现分组检验;
	@NotNull(message = "修改时必须填写品牌id",groups = {UpdateGroup.class})
	private Long brandId;
	/**
	 * 品牌名
	 */
	@NotBlank(message = "品牌名不能为空",groups = {AddGroup.class,UpdateGroup.class}) //不能是一个空格,至少是一个非空字符;如果仅仅在此处标准,默认是不起作用的。得在controller@Valid//响应状态码为400,是校验不通过的。
	private String name;
	/**
	 * 品牌logo地址
	 */
	@URL  //如果没有增加分组的校验,那么它的注解是不起作用的。@Validated({AddGroup.class})
	private String logo;
	/**
	 * 介绍
	 */
	private String descript;
	/**
	 * 显示状态[0-不显示;1-显示]
	 */
	@ListValue(vals = {0,1})
	private Integer showStatus;
	/**
	 * 检索首字母
	 */
	@Pattern(regexp = "^[a-zA-Z]$",message = "检索首字母必须是一个字母")
	private String firstLetter;
	/**
	 * 排序
	 */
	@Min(value = 0)
	@NotNull //sort字段是一个Integer字段,不能使用notEmpty来标注
	private Integer sort;

}

 注意:此时在实体类中增加的校验是不起作用的。需要在controller中配置@Valid才能使用

代码如下:

@RequestMapping("/save2")
    public R save2(@Valid @RequestBody PmsBrandEntity brandEntity){
        pmsBrandService.save(brandEntity);
        return R.ok();
    }

 此时,返回的错误信息较为杂乱,为了方便处理,需要返回统一的异常处理。

3、校验的统一异常处理

针对于某个接口进行特定的处理方式:

    @RequestMapping("/save")
    public R save(@Valid @RequestBody PmsBrandEntity pmsBrand, BindingResult bindingResult){  //获取校验结果的信息,从而对错误信息进行封装
        //在json后边,紧跟着一个校验的结果。BindingResult bindingResult,拿到校验的结果,就可以封装。
        boolean b = bindingResult.hasErrors(); //是否有错误
        if(b){
            Map map = new HashMap<>();
            //获取校验数据的结果
            bindingResult.getFieldErrors().forEach((item)->{
                //获取校验字段的名字
                String field = item.getField();
                //获取校验信息
                String defaultMessage = item.getDefaultMessage();
                map.put(field,defaultMessage);
            });
            return R.error(400,"提交的数据不合法!").put("data",map);
        }
        pmsBrandService.save(pmsBrand);
        return R.ok();
    }

全局进行处理,代码如下:

  @RequestMapping("/save2")
    public R save2(@Valid @RequestBody PmsBrandEntity brandEntity){
        pmsBrandService.save(brandEntity);
        return R.ok();
    }

package com.atguigu.gulimall.product.exception;

import com.atguigu.common.exception.BizCodeEnum;
import com.atguigu.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 org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.HashMap;
import java.util.Map;

/**
 * @author pshdhx
 * @date 2022-03-04 11:12
 * @Des 统一标准来处理异常的
 */
@Slf4j
//@ControllerAdvice
//@ResponseBody
@RestControllerAdvice(basePackages = "com.atguigu.gulimall.product.controller")
public class PshdhxGuliControllerAdvice {

    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public R handleValidException(MethodArgumentNotValidException e){
        BindingResult bindingResult = e.getBindingResult();
        Map map = new HashMap<>();
        bindingResult.getFieldErrors().forEach(item->{
            //...

            //获取校验字段的名字
            String field = item.getField();
            //获取校验信息
            String defaultMessage = item.getDefaultMessage();
            map.put(field,defaultMessage);
        });
        log.error("数据校验出现问题{},异常类型{}",e.getMessage(),e.getClass());
        return R.error(BizCodeEnum.VAILD_EXCEPTION.getCode(),BizCodeEnum.VAILD_EXCEPTION.getMsg()).put("data",map);
        //return R.error(BizCodeEnum.VAILD_EXCEPTION.getCode(),BizCodeEnum.VAILD_EXCEPTION.getMsg()).put("data",map);

    }
    
    @ExceptionHandler(value = Throwable.class)
    public R handleException(Throwable throwable){
        log.error("错误:",throwable);
        return R.error(BizCodeEnum.UNKNOW_EXCEPTION.getCode(),BizCodeEnum.UNKNOW_EXCEPTION.getMsg());
    }
}

为了统一自定义异常编码,指定了枚举类型。

package com.atguigu.common.exception;

/**
 * @author pshdhx
 * @date 2022-03-04 11:25
 */
public enum  BizCodeEnum {
    UNKNOW_EXCEPTION(10000,"系统未知异常"),
    VAILD_EXCEPTION(10001,"参数格式校验失败");

    private int code;
    private String msg;
    BizCodeEnum(int code,String msg){
        this.code = code;
        this.msg = msg;
    }

    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
}

 

结果如下: 

 springboot+vue+element-ui实现前后端的全部校验_第2张图片

4、JSR303后端分组检验

比如说id这个字段,在新增时,不需要它;在修改时,必须要它,那么就需要对其进行分组处理

@Data
@TableName("pms_brand")
public class PmsBrandEntity implements Serializable {
	private static final long serialVersionUID = 1L;

	/**
	 * 品牌id
	 */
	@TableId
	@Null(message = "新增时不能填写品牌id",groups = {AddGroup.class}) //实现分组检验;
	@NotNull(message = "修改时必须填写品牌id",groups = {UpdateGroup.class})
	private Long brandId;
package com.atguigu.common.valid;

public interface AddGroup {
}

 

package com.atguigu.common.valid;

public interface UpdateGroup {
}

定义俩空接口即可。但是,要想使其生效,则必须在控制器中使用注解@Validated

    //实现分组校验,这是添加是要校验的内容
    @RequestMapping("/save4")
    public R save4(@Validated({AddGroup.class}) @RequestBody PmsBrandEntity brandEntity){
        pmsBrandService.save(brandEntity);
        return R.ok();
    }

 但是,如果其他字段没有增加上相关的分组,则字段上的注释会失效。

5、JSR303自定义校验规则

我想让某个字段只输入0和1,需要自定义注解

	@ListValue(vals = {0,1})
	private Integer showStatus;

1、自定义校验规则 

package com.atguigu.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 = { ListValueConstraintValidator.class }) //关联
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface ListValue {
    String message() default "{com.atguigu.common.valid.ListValue.message}";

    Class[] groups() default { };

    Class[] payload() default { };

    int[] vals() default { };
}

2、自定义校验器

package com.atguigu.common.valid;
/**
 * 自定义校验器
 */

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.HashSet;
import java.util.Set;

public class ListValueConstraintValidator implements ConstraintValidator {

    private Set set = new HashSet<>();
    //初始化方法
    @Override
    public void initialize(ListValue constraintAnnotation) {

        int[] vals = constraintAnnotation.vals();
        for (int val : vals) {
            set.add(val);
        }

    }

    //判断是否校验成功

    /**
     *
     * @param value 需要校验的值
     * @param context
     * @return
     */
    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext context) {

        return set.contains(value);
    }
}

3、关联校验规则和校验器

@Documented
@Constraint(validatedBy = { ListValueConstraintValidator.class }) //关联
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface ListValue {

4、校验信息定义

ValidationMessages.properties

com.atguigu.common.valid.ListValue.message=必须提交指定的值

你可能感兴趣的:(java,vue.js,spring,boot,java)