Spring boot配合Hibernate Validator使用xml配置文件,手动验证Bean属性,并嵌套验证成员类

目的

本来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());
        }
    }
}

可能会遇到的坑

  1. 不要去修改xml文件开头的命名空间, 不同版本使用的命名空间不一样, 如果是复制过来的xml, 注意修改命名空间
  2. 具体配置xml中的实体类和分组类如果不是全限定类名, 则会在default-package中找
  3. 建议使用6.2.5.Final版本, 之后版本在Java EE中直接使用会报错, 需要引入其他包

总结

  1. 最好看官方文档
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值