当前位置: 首页> 教育> 高考 > 数据校验(JSR303、SpringBoot、自定义注解)

数据校验(JSR303、SpringBoot、自定义注解)

时间:2025/7/11 15:13:49来源:https://blog.csdn.net/m0_73179389/article/details/139963153 浏览次数:0次
在一个项目中,不仅前端要对用户输入的数据进行校验,避免发送不必要的请求,而且后端也要对数据进行对应的校验,因为操作不都是通过页面过来的。

前端

不是很了解

  • 正则表达式

  • 配合各种组件使用

后端

这里以Java为例,这里主要说声明式,JSR303校验。

常用的注解

  • @Null 验证对象是否为null

  • @NotNull 验证对象是否不为null

  • @Max 对Number和String的最大值进行限制

  • @Min 对Number和String的最小值进行限制

  • @NotBlank 检查字符串是否不为空,即不是null,也不是""

  • @URL 检查是否符合路径规则。

对数据进行校验

  1. 第一步引入对应的依赖

    <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.0.5.RELEASE</version>
    </dependency>

  2. 在实体类中的属性加上对应的注解

    /*** 品牌名*/
    @NotBlank(message = "name参数校验错误")
    private String name;

    message是在校验不正确的时候,响应的信息。

  3. 在对应的Controller中使用@Valid注解

      
    /*** 修改*/@RequestMapping("/update")//@RequiresPermissions("product:brand:update")public R update(@Valid @RequestBody BrandEntity brand){
    brandService.updateById(brand);return R.ok();}

    数据校验不通过,就会朝前断响应400 Bad Request,参数不正确。

    当然,你也可以自定义返回的结果:

    1. 在要校验的参数后面,紧跟一个BindingResult ,就可以拿到校验的结果。

    /*** 修改*/@RequestMapping("/update")//@RequiresPermissions("product:brand:update")public R update(@Valid @RequestBody BrandEntity brand,BindingResult result){
    brandService.updateById(brand);if(result.hasErrors()){//1. 获得所有的错误result.getFieldErrors().forEach((item) -> {//TODO:进行操作。})//TODO:返回自定义的信息即可。  }return R.ok();}

  4. 这样写,显然不合适,每个Controller都有错误校验的话,重复代码太多了,而且这些代码都和我们业务代码耦合了。所以最佳实践:全局异常处理。

     /*** 修改*/@RequestMapping("/update")//@RequiresPermissions("product:brand:update")public R update(@Valid @RequestBody BrandEntity brand){
    brandService.updateById(brand);return R.ok();}

    还是上面的一段代码

    全局异常使用SpringBoot的ControllerAdvice注解。

    1. 编写一个类,加上@ControllerAdvice注解。

    2. 编写对应的方法,加上@ExceptionHandler注解,并写上能处理的异常。

    3. 在方法里写上对应的逻辑。

      //集中处理所有异常  
      @Slf4j
      @RestControllerAdvice(basePackages = "com.atguigu.gulimail.product.app")
      public class GulimailExcdeptionControllerAdvice {
      ​@ExceptionHandler(value = MethodArgumentNotValidException.class)public R handleVaildException(MethodArgumentNotValidException e) {log.error("数据校验出现问题{},异常类型:{}", e.getMessage(), e.getClass());BindingResult bindingResult = e.getBindingResult();//TODO :进行操作即可}
      ​@ExceptionHandler(value = Throwable.class)public R handleException(Throwable throwable) {log.error("错误", throwable);//TODO:进行操作即可。}
      }

  5. 分组校验

    对于一个实体类的属性,在不同的方法下,标准可能是不一样的,比如一个商品的ID,在创建时应该是@Null(前端不用传,数据库自己生成),但在更新修改方法中就得是@NotNull了,所以分组校验就十分重要了。

    那注解就可以这样写:

    /*** 品牌id*/
    @NotNull(message = "修改id不能为空",groups = {UpdateGroup.class})
    @Null(message = "新增id要为空")
    private Long brandId;

    groups接受一个数组,数组里面的是接口,自己定义接口即可,不用做任何操作,就相当于一个标识。

    @Controller层的@valid注解不支持分组,这是就得使用@valiated(Spring提供的注解)注解了。

     /*** 修改*/@RequestMapping("/update")//@RequiresPermissions("product:brand:update")public R update(@Validated({UpdateStatusGroup.class}) @RequestBody BrandEntity brand){
    brandService.updateById(brand);return R.ok();}

    {}里的就是校验分组的标识。

    注意

    @NotBlank在分组情况下不生效,只有在@Validated情况下生效

  6. 自定义注解:

    先看一下@NotBlank注解:

    @Documented
    @Constraint(validatedBy = {}
    )//指定的校验方法。
    @Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
    @Retention(RetentionPolicy.RUNTIME) //触发的时机
    @Repeatable(List.class)
    public @interface NotBlank {String message() default "{javax.validation.constraints.NotBlank.message}"; //默认去找的信息
    ​Class<?>[] groups() default {};   //分组情况
    ​Class<? extends Payload>[] payload() default {};//上面三个是必须要有的。​@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface List {NotBlank[] value();}
    }

    自己写一个类

    1. 首先需要引入对应的依赖:

      <dependency><groupId>javax.validation</groupId><artifactId>validation-api</artifactId><version>2.0.1.Final</version>
      </dependency>

    2. 编写一个注解

      @Documented
      @Constraint(validatedBy = {ListValueConstraintValidator.class}
      )
      @Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
      @Retention(RetentionPolicy.RUNTIME)
      public @interface ListValue {String message() default "{com.atguigu.common.valid.ListValue.message}";
      ​Class<?>[] groups() default {};Class<? extends Payload>[] payload() default  {};
      ​int[] vals() default {};
      }

      String message() default "{com.atguigu.common.valid.ListValue.message}"; 是默认错误信息的路径地址,在resource包下创建一个properties文件即可。

      ValidationMessages.properties

      com.atguigu.common.valid.ListValue.message=信息有误

    3. 创建处理方法

      这两个泛型分别是:注解和需要添加注解的数据的类型。

      public class ListValueConstraintValidator implements ConstraintValidator<ListValue,Integer> {private Set<Integer> set = new HashSet<>();//初始化方法@Overridepublic void initialize(ListValue constraintAnnotation) {int[] vals = constraintAnnotation.vals();for(int val : vals){set.add(val);}}
      ​//判断是否校验成功@Overridepublic boolean isValid(Integer value, ConstraintValidatorContext context) {return set.contains(value);}
      }

    4. 使用注解:

      /*** 显示状态[0-不显示;1-显示]*/
      @ListValue(vals = {0,1})
      private Integer showStatus;

      在ListValueConstraintValidator的initialize方法中,会将vals里的所有值放到set集合中,然后isValid判断实体属性是否在这个set里面,这里可以根据自己的逻辑修改。

关键字:数据校验(JSR303、SpringBoot、自定义注解)

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: