zoukankan      html  css  js  c++  java
  • 前后端校验小结

    前端

    基于vue和elementUI。

    1. el-form标签加属性:rules="dataRule"
    <el-form :model="dataForm" :rules="dataRule"></el-form>
    
    1. data里加校验规则,比如我现在要对name进行校验
    <el-form
          :model="dataForm"
          :rules="dataRule"
          ref="dataForm"
          @keyup.enter.native="dataFormSubmit()"
          label-width="140px"
        >
          <el-form-item label="品牌名" prop="name">
            <el-input v-model="dataForm.name" placeholder="品牌名"></el-input>
          </el-form-item>
    </el-form>
    
    data() {
        return {
          dataForm: {
            brandId: 0,
            name: "",
            logo: "",
            descript: "",
            showStatus: 1,
            firstLetter: "",
            sort: 0,
          },
          dataRule: {
            name: [{ required: true, message: "品牌名不能为空", trigger: "blur" }]
        };
    }
    

    还可以自定义校验规则。比如我想对firstLetter字段进行检验,规则是:只允许包含一个字母

    <el-form
          :model="dataForm"
          :rules="dataRule"
          ref="dataForm"
          @keyup.enter.native="dataFormSubmit()"
          label-width="140px"
        >
          <el-form-item label="品牌名" prop="name">
            <el-input v-model="dataForm.name" placeholder="品牌名"></el-input>
          </el-form-item>
          <el-form-item label="检索首字母" prop="firstLetter">
            <el-input
              v-model="dataForm.firstLetter"
              placeholder="检索首字母"
            ></el-input>
          </el-form-item>
    </el-form>
    
    data() {
        return {
          dataForm: {
            brandId: 0,
            name: "",
            logo: "",
            descript: "",
            showStatus: 1,
            firstLetter: "",
            sort: 0,
          },
          dataRule: {
            name: [{ required: true, message: "品牌名不能为空", 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",
              },
            ],
        };
    }
    

    针对数字类型,除了可以使用正则校验外,还可以在双向绑定的时候告诉vue这是一个数字。

    <el-form-item label="排序" prop="sort">
    	<el-input v-model.number="dataForm.sort" placeholder="排序"></el-input>
    </el-form-item>
    

    校验部分

    sort: [
        {
            validator: (rule, value, callback) => {
                if (!Number.isInteger(value) || value < 0) {
                    callback(new Error("排序必须为大于等于0的整数"));
                } else {
                    callback();
                }
            },
            trigger: "blur",
        },
    ]
    

    后端

    基于JSR303校验。

    1. 引入依赖
    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
        <version>2.0.1.Final</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate.validator</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>6.1.0.Final</version>
    </dependency>
    
    1. 在bean中添加各种注解
    /**
     * 品牌
     *
     * @author liuzhulin
     * @email 1392673190@qq.com
     * @date 2021-03-02 11:00:29
     */
    @Data
    @TableName("pms_brand")
    public class BrandEntity implements Serializable {
        private static final long serialVersionUID = 1L;
    
        /**
         * 品牌id
         */
        @TableId
        private Long brandId;
        /**
         * 品牌名
         */
        @NotBlank(message = "品牌名不能为空")
        private String name;
        /**
         * 品牌logo地址
         */
        @NotBlank
        @URL(message = "品牌logo地址必须是合法url地址")
        private String logo;
        /**
         * 介绍
         */
        private String descript;
        /**
         * 显示状态[0-不显示;1-显示]
         */
        @NotNull
        @Min(value = 0, message = "显示状态必须为0或1")
        @Max(value = 1, message = "显示状态必须为0或1")
        private Integer showStatus;
        /**
         * 检索首字母
         */
        @NotBlank
        @Pattern(regexp = "^[a-zA-Z]$", message = "检索首字母必须为一个字母")
        private String firstLetter;
        /**
         * 排序
         */
        @NotNull
        @Min(value = 0)
        private Integer sort;
    
    }
    
    1. 在controller中添加@Valid注解就完成了。但是返回给前端的信息不够友好,为了统一前端的返回格式,可以在该参数后紧跟着BindingResult注意:必须紧跟着,该对象封装了校验不通过的字段和消息,可以将它们封装成map返回给前端。这里有个坑:如果不传某个字段,并且不设置不为空,那么就不会对其进行校验。
    /**
     * 品牌
     *
     * @author liuzhulin
     * @email 1392673190@qq.com
     * @date 2021-03-02 11:58:02
     */
    @RestController
    @RequestMapping("product/brand")
    public class BrandController {
        @Autowired
        private BrandService brandService;
        /**
         * 保存
         */
        @RequestMapping("/save")
        public R save(@Valid @RequestBody BrandEntity brand, BindingResult result){
            Map<String, String> map = new HashMap<>();
            if (result.hasErrors()) {
                result.getFieldErrors().forEach(p -> {
                    String field = p.getField();
                    String message = p.getDefaultMessage();
                    map.put(field, message);
                });
                return R.error(400, "提交数据不合法").put("data", map);
            }
    		brandService.save(brand);
            return R.ok();
        }
    }
    

    验证不通过返回的格式是这样的,这样就比较友好了。

    {
        "msg": "提交数据不合法",
        "code": 400,
        "data": {
            "name": "品牌名不能为空",
            "logo": "品牌logo地址必须是合法url地址",
            "showStatus": "显示状态必须为0或1",
            "sort": "不能为null",
            "firstLetter": "不能为空"
        }
    }
    

    改进:统一异常处理

    现在基本功能已经完成了,不过有一个问题:写多了controller就发现,关于校验这部分代码都是一个模板。我们其实可以继续优化,做成统一的异常处理。做法就是controller层出现异常不捕获,让Spring感知到异常后交给自己写的统一异常处理类来处理。

    改进代码,让异常处理代码和业务代码解耦

    /**
     * 品牌
     *
     * @author liuzhulin
     * @email 1392673190@qq.com
     * @date 2021-03-02 11:58:02
     */
    @RestController
    @RequestMapping("product/brand")
    public class BrandController {
        @Autowired
        private BrandService brandService;
        /**
         * 保存
         */
        @RequestMapping("/save")
        public R save(@Valid @RequestBody BrandEntity brand, BindingResult result){
    		brandService.save(brand);
            return R.ok();
        }
    }
    

    编写一个exception包,其下新增类

    @Slf4j
    //@RestControllerAdvice = ResponseBody + ControllerAdvice
    @RestControllerAdvice(basePackages = "com.atguigu.gulimall.product.controller")
    //在测试过程中发现校验不通过后没有进这个类,最后是设置一个注解解决的。网上也有人用@Priority,但是我试过没有作用
    @Order(1)
    public class GulimallExceptionControllerAdvice {
    
        //表示出现MethodArgumentNotValidException后执行该方法
        @ExceptionHandler(value = MethodArgumentNotValidException.class)
        public R handleValidException(MethodArgumentNotValidException e) {
            log.error("异常类型:{},异常消息:{}", e.getClass(), e.getMessage());
            //该方法可以获得具体信息
            BindingResult result = e.getBindingResult();
            Map<String, String> map = new HashMap<>();
            result.getFieldErrors().forEach(p -> {
                map.put(p.getField(), p.getDefaultMessage());
            });
            return R.error().put("data", map);
        }
        
        // 如果能精确匹配异常,就走精确的异常,否则就走最大的异常
        @ExceptionHandler(value = Throwable.class)
        public R handleException(Throwable e) {
            return R.error();
        }
    }
    
  • 相关阅读:
    北风设计模式课程---11、策略模式
    北风设计模式课程---9、原型模式的作用和意义
    linux下lamp.sh一键配置lamp环境流程
    linux日常---1、linux下安装、查看、卸载包常用命令
    常见协议端口号,功能
    尚学linux课程---12、vim操作命令2
    搞笑视频分析---3、爱做饭的芋头:佛跳墙
    黑马day11 脏读数据&amp;解
    hdu 1150 Machine Schedule(最小顶点覆盖)
    Ubuntu在构建Robotframework+Selenium周围环境
  • 原文地址:https://www.cnblogs.com/liuzhulin/p/14542910.html
Copyright © 2011-2022 走看看