Spring Boot使用JSR303校验


前言

数据校验是系统接口对接、网站交互等场景不可或缺的功能,涉及页面交互的一般通过js在录入时进行校验,但是还是存在绕过前端校验的可能,还有系统间调用的接口,或者是其他意外情况绕过校验,而一旦系统中出现非法的数据,这对运维来说是件很头疼的事情,所以服务端的数据校验也是十分必要的,本文介绍的validation就是进行这样的数据校验。

一、JSR303简介

  • JSR-303/JSR-349 是JAVA EE 6 中的一项子规范,叫做Bean Validation。JSR-349 是其升级版本,添加了一些新特性,他们规定了一些校验规范即校验注解,如 @Null,@NotNull,@Pattern等,这些规范位于 JDK的javax.validation.constraints 包下,只提供规范不提供实现,包名validation-api-x.x.x.jar。
  • Hibernate Validator是JSR-303/JSR-349的主要实现,这里的Hibernate不是数据库ORM框架的Hibernate,他提供了基本的实现,并增加了一些其他校验注解,如 @Email,@Length,@Range 等等,他们位于 org.hibernate.validator.constraints 包下,包名hibernate-validator-x.x.x.jar。
  • Spring Vlidation是JSR-303/JSR-349的另外一种实现,Spring Vlidation是Spring给开发者提供的一个便捷的校验实现,它对Hibernate Validator进行了二次封装,在需要使用校验时,你可以选择使用Spring Vlidation或者Hibernate Validator,都能达到同样的目的,Spring Vlidation有一个特性,便是其在 SpringMVC 模块中添加了自动校验,并将校验信息封装进了特定的类中,这无疑便捷了我们的 web 开发。
  • JSR-303/JSR-349其他的实现还有Dubbo Validation,只要在Dubbo注册时配置validation = true,并在参数上使用 JSR303 标准的验证 annotation 就可以生效了。dubbo启用参数验证也要依赖hiberate-validator包,最终底层八成也是调用Hibernate Validator执行校验。

二、JSR303定义的注解

注解类型功能描述
@Valid被注释的元素是一个对象,需要检查此对象的所有字段值
@Null被注释的元素必须为 null
@NotNull被注释的元素必须不为 null,任何对象的value不能为null
@AssertTrue被注释的元素必须为 true
@AssertFalse被注释的元素必须为 false
@Min(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max, min)被注释的元素的大小必须在指定的范围内
@Digits (integer, fraction)被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past被注释的元素必须是一个过去的日期
@Future被注释的元素必须是一个将来的日期
@Pattern(value)被注释的元素必须符合指定的正则表达式

三、Hibernate Validator定义的注解

注解类型功能描述
@Email被注释的元素必须是电子邮箱地址
@Length(min=, max=)被注释的字符串的大小必须在指定的范围内
@NotEmpty被注释的字符串的必须非空,集合对象的元素不为0,即集合不为空,也可以用于字符串不为null
@Range(min=, max=)被注释的元素必须在合适的范围内
@NotBlank被注释的字符串的必须非空,只能用于字符串不为null,并且字符串trim()以后length要大于0
@URL(protocol=,host=, port=, regexp=, flags=)被注释的字符串必须是一个有效的url
@CreditCardNumber被注释的字符串必须通过Luhn校验算法,银行卡,信用卡等号码一般都用Luhn计算合法性
@ScriptAssert(lang=, script=, alias=)要有Java Scripting API 即JSR 223 (“Scripting for the JavaTM Platform”)的实现
@SafeHtml(whitelistType=, additionalTags=)classpath中要有jsoup包

hibernate补充的注解中,最后3个不常用,可忽略

四、使用方式

以下是基本的使用方法,其他用法诸如分组校验、方法校验等读者可自行查阅相关文档学习,这里就不做介绍了。

1、Hibernate Validator使用方法

  • pom导入依赖项
<dependency>
      <groupId>org.hibernate.validator</groupId>
      <artifactId>hibernate-validator</artifactId>
      <version>6.0.18.Final</version>
      <exclusions>
        <exclusion>
          <groupId>jakarta.validation</groupId>
          <artifactId>jakarta.validation-api</artifactId>
        </exclusion>
      </exclusions>
</dependency>

或者直接导入Spring Boot提供的starter

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
    <version>2.4.5</version>
</dependency>
  • 添加注解
@Data
public class UserInfo {
   @javax.validation.constraints.NotNull
   private Long id;

   @javax.validation.constraints.NotEmpty
   private String name;

   @org.hibernate.validator.constraints.Range
   private Integer age;

   @javax.validation.constraints.Email
   private String email;

   private LocalDate birthdate;
}
  • 使用校验
public void ValidatorTest {
    private Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
    UserInfo userInfo = new UserInfo ();
    //如果校验对象userInfo 不通过,则存在校验不通过信息
    Set<ConstraintViolation<UserInfo>> set =   validator.validate(userInfo);
    set.stream().forEach(cv -> {
            System.out.println("属性:"+cv.getPropertyPath()+",属性值:"+cv.getInvalidValue()+",校验不通过,触发规则:"+cv.getMessage());
        });
}

2、Spring Vlidation使用方法

  • pom导入依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>2.4.5</version>
</dependency>
  • 添加注解
@Data
public class UserInfo {
    @javax.validation.constraints.NotNull
    private Long id;

    @javax.validation.constraints.NotEmpty
    private String name;

    @org.hibernate.validator.constraints.Range
    private Integer age;

    @javax.validation.constraints.Email
    private String email;

    private LocalDate birthdate;
}
  • 使用@Valid/@Validated开启注解
Void updateUser(@RequestBody @Valid UserInfo req);

@Valid和@Validated区别的区别如下
在这里插入图片描述

  • 使用校验
    spring-mvc自动解析参数,并调用Hibernate Validator进行校验

2、Dubbo Vlidation使用方法

  • pom引入依赖项
<dependency>
      <groupId>org.hibernate.validator</groupId>
      <artifactId>hibernate-validator</artifactId>
      <version>6.0.10.Final</version>
</dependency>
<dependency>
      <groupId>javax.validation</groupId>
      <artifactId>validation-api</artifactId>
      <version>2.0.1.Final</version>
</dependency>
  • 添加校验注解
  • 开启校验
<dubbo:reference id="validationService" interface="org.apache.dubbo.examples.validation.api.ValidationService" validation="true" />

只要在dubbo注册时配置validation = true,并在参数上使用 JSR303 标准的验证 annotation 就可以生效了

五、附录

这里分享一个Hibernate Validator方式校验常用工具类,在实际使用中,很多场景下都需要手动发起校验,例如批量导入对文件中数据的校验等,仅供大家参考。

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.groups.Default;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
 * @description:自定义校验
 * @author Mr.bin
 * @date 2022/7/4
 */
public class CustomValidator {

    private CustomValidator() {
    }

    private static Validator validator;

    static {
        validator = Validation.buildDefaultValidatorFactory().getValidator();
    }

    public static <T> Map<String,StringBuffer> validate(T obj){
        Map<String,StringBuffer> errorMap = null;
        Set<ConstraintViolation<T>> set = validator.validate(obj, Default.class);
        if(set != null && set.size() >0 ){
            errorMap = new HashMap<String,StringBuffer>();
            String property = null;
            for(ConstraintViolation<T> cv : set){
                //这里循环获取错误信息,可以自定义格式
                property = cv.getPropertyPath().toString();
                if(errorMap.get(property) != null){
                    errorMap.get(property).append("," + cv.getMessage());
                }else{
                    StringBuffer sb = new StringBuffer();
                    sb.append(cv.getMessage());
                    errorMap.put(property, sb);
                }
            }
        }
        return errorMap;
    }

    public static <T> Map<String,StringBuffer> validate(T obj, Class<?>... groups){
        Map<String,StringBuffer> errorMap = new HashMap<>();
        Set<ConstraintViolation<T>> set = validator.validate(obj, groups);
        if(set != null && set.size() >0 ){
            errorMap = new HashMap<String,StringBuffer>();
            String property = null;
            for(ConstraintViolation<T> cv : set){
                //这里循环获取错误信息,可以自定义格式
                property = cv.getPropertyPath().toString();
                if(errorMap.get(property) != null){
                    errorMap.get(property).append("," + cv.getMessage());
                }else{
                    StringBuffer sb = new StringBuffer();
                    sb.append(cv.getMessage());
                    errorMap.put(property, sb);
                }
            }
        }
        return errorMap;
    }
}


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值