SpringBoot校验请求Json参数

spring boot 校验请求json参数

在后端开发中,通过接口和参数传输来进行与前端交互,才可以让一个项目成型。

由于全后端隔离的方式,所以有时候需要不那么信任前端,也就是在验证当前操作是否有权限同时,校验前端传来的参数的合理性也是必不可少的。

这里只记录post json数据时候的校验方法。


以下代码中使用到的依赖,以及工具类,在结果的git链接中可以找到


  1. 一般的校验方法

    代码:

    // 测试接口
    @RestController
    @RequestMapping("/simple")
    public class SimpleController {
    
        // 开发中建议另外定义一个类来接受=收
        // 可以使用内部类, 不过不要写太多
        @Data
        private static class TestParam {
            private int num;
            private String str;
        }
    
        @PostMapping("/test")
        public R<?> test(@RequestBody(required = false) TestParam param) {
    
            if (StringUtils.isNull(param)
                    || StringUtils.isEmpty(param.getStr()) || param.getNum() <= 0) {
               return R.paramErr();
            }
    
            // TODO 逻辑处理
    
            return R.ok(new JSONObject());
        }
    }
    

    测试参数:

    {
        
    }
    or
    {
        "str": 1
    }
    or
    {
        "num": 2
    }
    

    结果:

    {
        "code": "1001",
        "msg": "参数格式错误",
        "data": null
    }
    

    结果以及分析:

    • 表述不清楚,不管是缺少,还是不符合格式,全部返回格式错误(单独判断很冗余)。
    • 在str传输数字时候可以通过(给数字类型传纯字符串的处理方法在2.2第第二个处理器
  2. 接下来记录springboot提供的参数校验注解

      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-validation</artifactId>
          <version>2.5.6</version>
      </dependency>
    
    1. 参数注解

      @Data
      private static class TestParam {
          @Min(value = 1L, message = "数字参数最小值不能小于1")
          @NotNull(message = "缺少数字参数")
          private int num;
      
          @NotNull(message = "缺少字符串参数")
          private String str;
      
          @NotNull(message = "对象参数不能为空")
          @Valid
          private TestObjParam obj;
      }
      
      @Data
      public static class TestObjParam {
          @NotNull(message = "对象参数内,参数不能为空")
          // 若还有内部对象,继续使用 @Valid 注解即可
          private String param;
      
          @NotEmpty(message = "数组不能为空")
          private List<String> stringList;
      
          @Size(max = 2, min = 0, message = "性别参数必须在0-2之间")
          private int gender;
      }
      
      @PostMapping(value = "/test")
      Object test(@RequestBody @Validated TestParam param) {
          return "通过测试";
      }
      
    2. 与之配套使用的

      @RestControllerAdvice
      public class ControllerAdvice {
      
          /**
           * 拦截JSON参数校验
           */
          @ResponseStatus(HttpStatus.OK)
          @ExceptionHandler(MethodArgumentNotValidException.class)
          public Map<String, String> bindException(MethodArgumentNotValidException e) {
      
              BindingResult bindingResult = e.getBindingResult();
      
              String msg = Objects.requireNonNull(
                  bindingResult.getFieldError()).getDefaultMessage();
      
              Map<String, String> result = new HashMap<>();
      
              result.put("code", "1001");
              result.put("msg", msg);
              result.put("data", null);
      
              return result;
          }
          
          /**
           * 拦截类型不匹配。也即需要字段传对象,数字传字符串和对象的情况
           */
          @ResponseStatus(HttpStatus.OK)
          @ExceptionHandler(HttpMessageNotReadableException.class)
          public R<?> bindException(HttpMessageNotReadableException e) {
      
              return R.paramErr("参数中有不符合目标格式的");
          }
      }
      
    3. 结果分析

      • 大大减少了在进行逻辑开发前的手动参数校验
      • 同时前端在对接口时候也可以准确地清楚参数缺少和不符合要求的情况。
  3. 常用的参数,完整版可以在包javax.validation.constraints

    注解 解释 所修饰类型
    @NotNull 被注解的元素不能为null 修饰所有类型参数
    @NotEmpty 不能为空 数组
    @Min(value) 被注解元素的最小值等于value 数字类型
    @Max(value) 被注解的元素的最大值等于value 数字类型
    @Size(max, min) 大小注解 数组
    @Pattern(value) 正则表达式做鉴定
  4. git地址: springboot-param-validate

  5. 补充:

    • @Range校验数字范围
    • @Length校验字符串长度
    • @Size校验String和数组长度
    • @Digits(integer = 6, fraction = 0, message = "") 修饰数字(整数位数和小数位数)
    • @BigDecimalMax和min可配合Digits
  6. 参考资料:


2022-11-17 补充分组


@Validated@Validate的简要区别:

  1. @Validated校验的对象中如果有对象类型的属性, 该属性上需要用@Validate, 可进行校验传递
  2. @Validated可进行分组校验, @Validate无分组校验.
    分组:

import javax.validation.GroupSequence;

/**
 * 至于interface与@interface在此处的区别, 并未得知
 * 参考:
 * <a href="https://blog.csdn.net/weixin_45941064/article/details/124192836">Java @interface和interface的区别</a>
 * <a href=" https://reflectoring.io/bean-validation-with-spring-boot">Validation with Spring Boot - the Complete Guide</a>
 * <a href="https://nullbeans.com/how-to-use-java-bean-validation-in-spring-boot/">How to use Java Bean Validation in Spring Boot</a>
 * <a href="https://gitee.com/bootx/bootx-platform">bootx-platform, @cn.bootx.common.core.validation</a>
 *
 * @author wangXiaoMing
 * @date 2022/11/14 17:51
 */
public interface ValidationGroup {

    /**
     * 参数校验分组:添加
     */
    @interface create {
    }

    /**
     * 参数校验分组:修改
     */
    @interface update {
    }

    /**
     * 参数校验分组:添加修改 - 也可使用序列
     */
    @interface createUpdate {
    }

    /**
     * 参数校验分组:删除
     */
    @interface delete {
    }

    /**
     * 参数校验分组:查询
     */
    @interface query {
    }

    /**
     * 先校验update, 再校验delete, 然后时create
     * 代表校验顺序, 和需要校验的分组
     * <p>
     * 参考:
     * <a href="https://blog.csdn.net/qq_17586821/article/details/104661914">validation-api中@GroupSequence的使用</a>
     * <a href="https://blog.csdn.net/chepeng3577/article/details/100719210">@GroupSequence自定义验证顺序</a>
     * <a href="https://blog.csdn.net/linxingliang/article/details/122044749">validation数据校验之分组校验怎么玩?</a>
     */
    @GroupSequence({update.class, delete.class, create.class})
    @interface order {
    }

}

使用:
多个分组时需要使用{}, 单个时可省略
@NotNull(message = "id不能为空1", groups = {ValidationGroup.create.class})
Controller中使用时@Validated({ValidationGroup.create.class})进行校验

分组序列@GroupSequence的使用:

  1. 指定包含的分组(其他分组不会校验, 如上面的querycreateUpdate)
  2. 以及校验的对应的顺序
posted @ 2021-12-13 16:44  Codorld  阅读(2917)  评论(1编辑  收藏  举报