Spring 6【数据校验Validation、JSR 303 和 Hibernate 实现】(十三)-全面详解(学习总结---从入门到深化)

 

目录

数据校验Validation

2.JSR 303 和 Hibernate 实现


数据校验Validation

1.数据校验介绍

数据校验分为客户端数据校验和服务端数据校验。都是为了保证数据完整性的。 客户端数据校验直接使用客户端脚本校验即可。例如在B/S模型项目中,可以选择使用JavaScript或 jQuery进行客户端数据校验。 在京东商城中,如果用户名和密码都没有输入,直接点击登录会提示输入账户名和密码,这就是客户端校验。

一个项目只有客户端数据校验是不严谨的,为了防止不法人员直接通过URL或HTTP工具非法访问服务端,发送非法数据,保险起见,服务端也应该具有数据校验,这种客户端和服务端都有数据校验时,称为双重校验。 

在服务端可以使用Spring框架的数据校验。无论是web环境和是非web环境都可以使用。 在Spring框架的数据校验主要用于web层,但是也可以应用在其他层。实现时需要借助Validator接口和 DataBinder进行实现。

2.Spring框架Validator接口使用 

在代码之前我们先来介绍一下Validator接口

public interface Validator {
    /**
     * 判断校验的类,如果支持对这个类的校验返回true,否则返回false
     * @return 是否支持当前类类型
     */
    boolean supports(Class<?> clazz);
    /**
     * 校验的具体逻辑
     * @param target 目标对象
     * @param errors 校验不同过后的错误信息。可以通过ValidationUtils快速校验和设置错误信息
     */
    void validate(Object target, Errors errors);
}

ValidationUtils是一个工具类,可以快速的判断一个属性是否为null、长度为0、获取全是空格,并把错误绑定上。

2.1 准备好一个实体类 

还是使用People类进行测试。里面给定两个属性。

package com.tong.validation;
import lombok.Data;

@Data
public class People {
      private String name;
      private int age;
}

2.2 新建校验类

新建com.tong.validation.MyValidator。类名和类所在的包都是随意定义的,没有强制要求。

public class MyValidator implements Validator {
     // 定义需要对哪个类进行校验
     @Override
     public boolean supports(Class<?> clazz) {
           if(clazz.equals(People.class)){
                   return true;
            }
         return false;
      }
     // 具体校验规则
     // 简单判断是否为空可以使用工具类。其他的校验规则需要自己定义
 
    @Override
    public void validate(Object target, Errors errors) {
      // rejectIfEmpty(Errors对象,“校验的属性”,"错误码,可以设置为null",“校验不通过时日志打印的消息”):为空校验不通过
      ValidationUtils.rejectIfEmpty(errors,"name",null,"姓名不能为空");
     // 如果希望判断其他逻辑,需要手动编写
     Object ageValue = errors.getFieldValue("age");// 获取age属性的值
     if(ageValue!=null){
           Integer age = Integer.parseInt(ageValue.toString());
           if(age<1||age>150){
              // rejectValue("校验的属性",“错误码”,"校验不通过时日志打印的消息"):表示属性校验不通过
               errors.rejectValue("age",null,"年龄必须是1-150之间的数字");
             }
         }
    }
}

 2.3 测试校验结果

在测试类中编写代码

@Test
void testValidator(){
     People people = new People();
     DataBinder dataBinder = new DataBinder(people);
     dataBinder.setValidator(new MyValidator());
     dataBinder.validate();
     BindingResult bindingResult = dataBinder.getBindingResult();
     bindingResult.getAllErrors().forEach(err->{
     System.out.println(err);
   });
}

2.JSR 303 和 Hibernate 实现

2.1 JSR介绍

JCP(Java Community Process)是一个开发的国际组织,里面包含了一些Java开发者和其他被允许加入的成员。JCP组织主要负责对Java社区进行发展和更新。维护的规范包含:J2ME、J2SE、J2EE、XML等相关规范。组织成员可以提交JSR(Java Specification Requests,Java 规范提案),待组织成员通过提案后会 把相关内容加入到下一个版本的规范中。

 2.2 JSR 303介绍

JSR每个提案都带有数字名称。例如JSR 107、JSR 303等。一定要注意的是,对于JSR提案并不是数字越大就需要包含前面内容。例如JSR 107主要是对缓存的提案、JSR 303是对数据校验的提案,这两个提案 不存在包含和被包含的关系,也不存在版本先后的关系。这个和我国政协会议是类似的,第一个政协委员提出的建议叫做建议1、第二个政协委员提出的建议是建议2。建议1建议提高个税起征点、建议2建议国家分配对象。这俩建议是没有关系的。 JSR 303是Java EE 6规范的子规范。叫做Bean Validation。这些规范都是注解。各大公司可以针对这些规范做具体实现。 在Java开发中使用的最多的JSR 303具体实现就是Hibernate框架中Hibernate-Validator。它对JSR 303的 所有约定(constraint)都做了实现,同时还进行了一定的扩充。

2.3 Hibernate Validator包含的内容 

Hiberante 框架是Java行业曾经风靡一时的ORM框架,目前在企业中只有一些老项目还在使用。 但Hibernate里面却有着一些很好的功能一直被使用。其中就包含hibernate-validator。 hibernate-validator对JSR 303实现都存在于依赖的Validation-api.jar的javax.validation.constraints包 中。 里面所有注解都包含message属性,表示校验不通过后日志打印的信息。但是不建议设置,因为默认的 提示信息就非常好。 Hibernate Validator对JSR 303具体实现的解释:

Hibernate-Validator还有除了JSR 303的额外补充,这些注解都在Hibernate-validator.jar的 org.hibernate.validator.constraints包中。 

 

2.4 hibernate-validator使用 

添加依赖

除了项目正常的依赖以外,额外需要导入Hibernate-validator依赖和EL表达式依赖。

<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>8.0.0.Final</version>
</dependency>
<dependency>
    <groupId>jakarta.el</groupId>
    <artifactId>jakarta.el-api</artifactId>
    <version>5.0.1</version>
</dependency>
<dependency>
    <groupId>org.glassfish</groupId>
    <artifactId>jakarta.el</artifactId>
    <version>5.0.0-M1</version>
</dependency>

在实体类属性上添加注解

示例中只是以NotNull和Length和Range进行举例。

(1)@NotNull中message是可选属性,如果设置了message,在违反规则后日志会打印message中内容

(2)@Length是设置字符串长度。

(3)@Range 设置取值范围。可以用在int类型属性上。 所以name必须不能是null的,且长度是2-6位。age取值范围必须是1~150 这些注解虽然可以放在方法、属性、其他注解、构造方法、参数上。我们多把这些注解放在实体类的属 性上面,每个实体类属性都支持配置多个注解,这些注解同时生效。

@Data
public class People {
     @NotNull(message = "姓名不能是null")
     @Length(min = 2,max = 6,message = "长度应该是2-6位")
     private String name;
     @Range(min=1,max=150)
     private int age;
}

编写测试类,测试hibernate-validator

@Test
void testHibernateValidator(){
    ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
    Validator validator = factory.getValidator();
    People people = new People();
    Set<ConstraintViolation<People>> constraintViolations = validator.validate(people);
    for (ConstraintViolation<People> constraintViolation : constraintViolations)
     {
        System.out.println("错误:" + constraintViolation.getMessage());
    }
}

运行后控制台输出信息

错误:不能为null

错误:需要在1和150之间

3.Spring框架对Hibernate-validator的集成 

在Spring框架中有LocalValidatorFactoryBean类,这个类实现了ValidatorFactory接口和Validator接口。所以我们在Spring框架中可以直接使用这个类作为Validator实例化的对象。

通过使用LocalValidatorFactoryBean可以简化Hibernate实例化Validator的两行代码,其他使用方式都一样。

public class LocalValidatorFactoryBean extends SpringValidatorAdapter
implements ValidatorFactory, ApplicationContextAware, InitializingBean,
DisposableBean {
   
   

3.1 保证项目包含hibernate-validator依赖

在上面学习Hibernate-validator使用时已经导入过了

<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>8.0.0.Final</version>
</dependency>
<dependency>
    <groupId>jakarta.el</groupId>
    <artifactId>jakarta.el-api</artifactId>
    <version>5.0.1</version>
</dependency>
<dependency>
    <groupId>org.glassfish</groupId>
    <artifactId>jakarta.el</artifactId>
    <version>5.0.0-M1</version>
</dependency>

3.2 创建一个类

创建com.tong.validation.Student,添加几个注解进行测试

@Data
public class Student {
    @NotBlank
    private String name;
    @Positive
    private int age;
}

 3.3 编写配置

创建配置文件applicationContext-validation.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

   <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
  </bean>

   <bean id="student" class="com.tong.validation.Student"></bean>
</beans>

3.4 编写测试类

在com.tong.test.ValidationTest中测试

@SpringJUnitConfig
@ContextConfiguration("classpath:applicationContext-validation.xml")
public class ValidationTest {
    @Autowired
    LocalValidatorFactoryBean validator;
    @Autowired
    Student student;
    @Test
    void test(){
       Set<ConstraintViolation<Student>> constraintViolations = validator.validate(student);
       for (ConstraintViolation<Student> constraintViolation : constraintViolations) {
              System.out.println("错误:" + constraintViolation.getMessage());
           }
      }
}

 3.5 观察运行结果

在IDEA控制台可以看到

错误:不能为空
错误:必须是正数

猜你喜欢

转载自blog.csdn.net/m0_58719994/article/details/132000508