目的
本来Hibernate Validator或Spring Validate应该用注解配置验证, 但业务需求要验证的属性太多, 还要要求验证条件可能随时改变, 所以使用xml配置
本文参考了官方教程
环境
- 一个已经建好的
Spring boot
项目 OpenJDK 1.8
开始
1. maven
引入
为什么是
6.2.5.Final
? 因为后面的版本不支持Java EE, 只支持Jakarta EE, 一般用的都是Java EE, 你需要引入其他包才能在Java EE中使用, 为了方便, 我选择了6.2.5.Final
, 这样只需要引入一个包。
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.2.5.Final</version>
</dependency>
2. 新建实体类Person,Car和分组类Driver
项目中已经引入Lombok, 省去了手写getter,setter, 记得引入Lombok后在Idea中安装Lombok, 不然Idea会标红
src\main\java\cn\o\test\entity\Person.java
package cn.o.test.entity;
import lombok.Data;
@Data
public class Person {
private String name;
private String id;
private String nickname;
@Valid
private Car car;
}
还有Person的成员类Car
src\main\java\cn\o\test\entity\Car.java
package cn.o.test.entity;
import lombok.Data;
@Data
public class Car {
private String carCode;
private String carName;
}
分组类:src\main\java\cn\o\test\validGroup\Driver.java
分组是用类名来分组, 不同分组使用不同的验证条件, 如果继承了
Default
类, 就会使用未分组的验证条件, 觉得单独为分组建个类并非官方的设计初衷, 但大家都是这样用
import javax.validation.groups.Default;
public interface Driver extends Default {
}
3. xml配置文件
这个文件名和路径是固定的,必须要在
resources
下新建一个META-INF
文件夹, 不然Hibernate Validator会找不到, 就不会启用xml配置,而是使用注解(如果你写了验证注解)来验证了
每个版本的xml配置文件命名空间都不一样, 如果使用不同的Hibernate Validator版本, 注意命名空间也要对应改变
主配置文件:src\main\resources\META-INF\validation.xml
<validation-config
xmlns="http://xmlns.jcp.org/xml/ns/validation/configuration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/validation/configuration
http://xmlns.jcp.org/xml/ns/validation/configuration/validation-configuration-2.0.xsd"
version="2.0">
<default-provider>org.hibernate.validator.HibernateValidator</default-provider>
<constraint-mapping>META-INF/validation/person.xml</constraint-mapping>
<property name="hibernate.validator.fail_fast">false</property>
</validation-config>
解释一下
default-provider
: 官方配置, 具体用法不太清楚
constraint-mapping
: 具体的Bean配置文件位置
property
: 启动参数配置, 这里只配置了hibernate.validator.fail_fast
:是否发现第一个未通过验证的参数就停止验证, 这里选择否, 我们需要找到所有未通过验证的属性
具体的验证配置在这里: src\main\resources\META-INF\validation\person.xml
<constraint-mappings
xmlns="http://xmlns.jcp.org/xml/ns/validation/mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/validation/mapping
http://xmlns.jcp.org/xml/ns/validation/mapping/validation-mapping-2.0.xsd"
version="2.0">
<default-package>cn.o.test.entity</default-package>
<bean class="Person" ignore-annotations="true">
<field name="name">
<constraint annotation="javax.validation.constraints.NotBlank">
<message>xml验证: name is null</message>
<groups>
<value>cn.o.test.validGroup.Driver</value>
</groups>
</constraint>
</field>
<field name="id">
<constraint annotation="javax.validation.constraints.NotBlank">
<message>xml验证: id is null</message>
</constraint>
</field>
<field name="car">
<valid/>
</field>
</bean>
<bean class="Car" ignore-annotations="true">
<field name="carName">
<constraint annotation="javax.validation.constraints.NotBlank">
<message>xml验证: 车名 is null</message>
<groups>
<value>cn.o.test.validGroup.Driver</value>
</groups>
</constraint>
</field>
<field name="carCode">
<constraint annotation="javax.validation.constraints.NotBlank">
<message>xml验证: 车牌号 is null</message>
</constraint>
</field>
</bean>
</constraint-mappings>
default-package
: 实体所在的包, 分组类如果只写Driver
而不是cn.o.test.validGroup.Driver
, 默认在这个包里找
ignore-annotations
: 是否忽略实体中写的验证注解
constraint
: 验证条件
groups
: 这个条件是属于哪个分组的, 如果没有’groups’, 就是默认分组
message
: 未通过验证时返回的消息
field
: 属性, 如果是成员类, 直接写<valid/>
, 就会嵌套验证, 同时带着分组信息, 成员类中也会使用同样的分组去验证, 如果是空对象则不会去验证
4. 手动验证
最后, 可以开始验证了, 这里写了个测试类, 正式使用时可以自己写一个工具类, 方便使用
package test;
import cn.o.test.entity.Car;
import cn.o.test.entity.Person;
import cn.o.test.validGroup.Driver;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.util.Set;
public class GeneratorTest {
public static void main(String[] args) {
// 配置
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
// 实体
Person test = new Person();
test.setId("11");
test.setName("");
test.setCar(new Car());
// 手动验证
Set<ConstraintViolation<Person>> validaSet = validator.validate(test, Driver.class);
for (ConstraintViolation<Person> model : validaSet) {
System.out.println(model.getRootBean().getId() + model.getMessage());
}
}
}
可能会遇到的坑
- 不要去修改xml文件开头的命名空间, 不同版本使用的命名空间不一样, 如果是复制过来的xml, 注意修改命名空间
- 具体配置xml中的实体类和分组类如果不是全限定类名, 则会在
default-package
中找 - 建议使用
6.2.5.Final
版本, 之后版本在Java EE
中直接使用会报错, 需要引入其他包
总结
- 最好看官方文档