美文网首页
参数校验好,安全没烦恼

参数校验好,安全没烦恼

作者: 祥哥去哪里 | 来源:发表于2022-01-17 17:34 被阅读0次

    前言

    后端开发API的时候经常遇到要验证前端传过来的参数。一个一个的校验未免太不优雅了。那么使用springboot怎么优雅解决呢?

    传统的校验参数的方法

    传统的方式,会将前端传过来的参数一一校验,虽然也能达到效果,但是耗费了精力,代码也比较长

        @RequestMapping("add")
        public R<String> add( @RequestBody Banner banner){
            R<String> r =new R<>();
            if (StringUtils.isEmpty(banner.getName())) {
                return r.fail("名字不能为空");
            }
            if (StringUtils.isEmpty(banner.getUrl())) {
                return r.fail("url不能为空");
            }
            //假装有业务操作
            return r.success("ok");
        }
    

    更简洁的校验方式

    我们可以使用spring提供的validation组件

    <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
    

    首先需要设计一个入参的对象

    @Data
    public class Banner implements Serializable {
    
        /**
         * 名字
         */
        private String name;
    
        /**
         * 链接
         */
        private String url;
    }
    

    当我们需要对指定的入参进行校验的时候,使用注解就能指定校验规则(支持多个)
    下面是封装好的规则,找到需要的直接使用就可以了

    注解 规则
    @Null 被注释的元素必须为 null
    @NotNull 被注释的元素必须不为 null
    @AssertTrue 被注释的元素必须为 true
    @AssertFalse 被注释的元素必须为 false
    @Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
    @Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
    @DecimalMin(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最小值
    @DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
    @Size(max,min) 被注释的元素的大小必须在指定的范国内
    @Digits (integer, fraction) 被注释的元素必须是一个数宇,其值必须在可接受的范田内
    @Past 被注释的元素必须是一个过去的日期
    @Future 被注释的元素必须是一个将来的日期
    @Pattern (value) 被注释的元素必须符合指定的正则表达式

    当我们需要name、url这两个参数不能为空时,选择加上@NotNull注解就可以了
    然后再完善下controller,在入参的地方加上@Vaild,就代表需要做参数校验

    @RequestMapping("banner")
    @RestController
    public class BannerController {
    
        @RequestMapping("add")
        public R<String> add(@Valid @RequestBody Banner banner){
            R<String> r =new R<>();
            //假装有业务逻辑代码在这里调用
            return r.success("ok");
        }
    }
    

    参数校验效果

    当我们把参数设置为不能为空,就可以启动web服务试试效果了

    缺参数的时候
    完整参数的时候
    上面图片展示了,有参数校验通过的情况,和参数校验不通过的情况。我们能看到,在校验不通过的时候,响应的code 是400
    这样虽然参数校验到位了,但是报错也不够友好,不利于后续排查问题。所以我们希望当参数不合规时,把错误的的原因通过接口返回。

    优化返回参数

    我们在控制台发现刚刚出现参数校验不通过的时候,实际上是抛出了一个异常

    抛出异常
    我们可以试试将这个异常捕获,然后将错误信息抓出来返回给客户端
    首先来看下异常里面有哪些我们可以使用的信息
    1. 全局异常控制
    @ControllerAdvice
    @ResponseBody
    public class ExceptionHandle {
    
        @ExceptionHandler
        public R ParamExceptionHandle(MethodArgumentNotValidException e){
            System.out.println(e);//这里打断点,看看异常类里有什么东西
            return null;
        }
    }
    

    通过将异常捕获器,看看异常里面的内容

    错误信息
    从错误消息中我们可以看到有校验不通过的字段名默认的错误消息
    那我们把这两个字段组合一下,就变成了"url"+"字段"+"不能为null”
    2. 下面进行对全局异常捕获的改造
    @Slf4j
    @ControllerAdvice
    @ResponseBody
    public class ExceptionHandle {
    
        @ExceptionHandler
        public R ParamExceptionHandle(MethodArgumentNotValidException e){
            log.info("捕获参数校验异常",e);
            List<String> failError= new ArrayList<>();
            for (FieldError fieldError : e.getBindingResult().getFieldErrors()) {
                String field = fieldError.getField();//字段名
                String defaultMessage = fieldError.getDefaultMessage();
                StringBuilder sb=new StringBuilder();
                sb.append("参数:").append(field).append(",校验异常。").append("原因:").append(defaultMessage);
                failError.add(sb.toString());
            }
            R<List<String>> r=new R<>();
            return r.fail(failError.toString());
        }
    }
    

    3.重启服务看看效果

    单个参数校验不通过
    多个参数校验不通过 参数校验通过

    尾巴

    spring提供的validate工具结合全局异常管理,可以让控制器瘦身,减少代码量的同时,在设计入参字段的同时设计校验规则,更符合直觉,不容易出错。感谢阅读!如果觉得我内容还不错的话,记得关注和点赞

    相关文章

      网友评论

          本文标题:参数校验好,安全没烦恼

          本文链接:https://www.haomeiwen.com/subject/jmbbcrtx.html