目录
数据校验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 {// 定义需要对哪个类进行校验@Overridepublic boolean supports(Class<?> clazz) {if(clazz.equals(People.class)){return true;}return false;}// 具体校验规则// 简单判断是否为空可以使用工具类。其他的校验规则需要自己定义@Overridepublic 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 {@NotBlankprivate String name;@Positiveprivate 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/beanshttp://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 {@AutowiredLocalValidatorFactoryBean validator;@AutowiredStudent student;@Testvoid test(){Set<ConstraintViolation<Student>> constraintViolations = validator.validate(student);for (ConstraintViolation<Student> constraintViolation : constraintViolations) {System.out.println("错误:" + constraintViolation.getMessage());}}
}
3.5 观察运行结果
在IDEA控制台可以看到
错误:不能为空
错误:必须是正数