百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

Hibernate Validator校验器入门

toyiye 2024-06-21 12:17 8 浏览 0 评论


一、声明和验证Bean约束

1. 声明Bean约束

1.1 字段级约束

package org.hibernate.validator.referenceguide.chapter02.fieldlevel;

public class Car {

@NotNull

private String manufacturer;

@AssertTrue

private boolean isRegistered;

public Car(String manufacturer, boolean isRegistered) {

this.manufacturer = manufacturer;

this.isRegistered = isRegistered;

}

//getters and setters...

}

1.2 属性级约束

package org.hibernate.validator.referenceguide.chapter02.propertylevel;

public class Car {

private String manufacturer;

private boolean isRegistered;

public Car(String manufacturer, boolean isRegistered) {

this.manufacturer = manufacturer;

this.isRegistered = isRegistered;

}

@NotNull(message = "制造商不能为空")

public String getManufacturer() {

return manufacturer;

}

public void setManufacturer(String manufacturer) {

this.manufacturer = manufacturer;

}

@AssertTrue

public boolean isRegistered() {

return isRegistered;

}

public void setRegistered(boolean isRegistered) {

this.isRegistered = isRegistered;

}

}

1.3 类及约束

package org.hibernate.validator.referenceguide.chapter02.classlevel;

@ValidPassengerCount

public class Car {

private int seatCount;

private List<Person> passengers;

//...

}

1.4 约束继承

  • 当一个类实现一个接口或扩展另一个类时,所有在超类型上声明的约束注释都

将应用到扩展类上

  • 如果方法被覆盖,约束注释将被聚合(叠加)

1.5 对象图

  • Bean验证API不仅允许验证单个类实例,还允许验证完整的对象图(级联验证)。为此,只需用@Valid注释表示对另一个对象引用的字段或属性,如级联验证中所示

package org.hibernate.validator.referenceguide.chapter02.objectgraph;

public class Car {

@NotNull

@Valid

private Person driver;

//...

}

package org.hibernate.validator.referenceguide.chapter02.objectgraph;

public class Person {

@NotNull

private String name;

//...

}

如果验证了Car的一个实例,那么引用的Person对象也将被验证,因为驱动程

序字段被标注为@Valid。因此,如果引用的Person实例的name字段为null,则Car

的验证将失败

对象图的验证是递归的,也就是说,如果为级联验证标记的引用指向本身具有

@Valid注释的属性的对象,那么验证引擎也将跟踪这些引用。验证引擎将确保级联

验证期间不会出现无限循环,例如,如果两个对象彼此持有引用

  • 对象图验证也适用于集合类型的字段

arrays

implement java.lang.Iterable (especially Collection, List and Set)

implement java.util.Map

可使用@Valid进行注释,这将导致在验证父对象时对每个包含的元素进行验证

2. 验证Bean约束

2.1 获取验证器实例

验证实体实例的第一步是获取验证器实例。通过Validation类和ValidatorFactory。

最简单的方法是使用静态方法Validation#buildDefaultValidatorFactory(),eg:

ValidatorFactory factory = Validation.buildDefaultValidatorFactory();

Validator validator = factory.getValidator();

2.2 验证器方法(Validator方法)

Validator接口包含三个方法,可用于验证整个实体或实体的单个属性

这三个方法都返回一个Set< ConstraintViolation>。如果验证成功,则该集合为

空。否则,将为每个被违反的约束添加一个ConstraintViolation实例

所有验证方法都有一个var-args参数,可用于指定执行验证时应考虑哪些验证组。

如果没有指定该参数,则使用默认验证组(javax.validation.groups.Default)

  • Validator#validate():检验Bean

//获取验证器实例

ValidatorFactory factory = Validation.buildDefaultValidatorFactory();

final Validator validator = factory.getValidator();

Car car = new Car( null, true );//Car类参见1.2 属性级约束

Set<ConstraintViolation<Car>> constraintViolations =

validator.validate( car );

System.out.println(constraintViolations.size());//1

//制造商不能为空

System.out.println(constraintViolations.iterator().next().getMessage());

  • Validator#validateProperty()

在validateProperty()的帮助下,您可以验证给定对象的单个命名属性。属

性名是javabean属性名

final Validator validator = getValidator();

Car car = new Car( null, true );

Set<ConstraintViolation<Car>> constraintViolations =

validator.validateProperty(

car,

"manufacturer"

);

System.out.println(constraintViolations.size());//1

//制造商不能为空

System.out.println(constraintViolations.iterator().next().getMessage());

  • Validator#validateValue()

通过使用validateValue()方法,您可以检查给定类的单个属性是否可以成

功验证(如果该属性具有指定的值)

final Validator validator = getValidator();

Set<ConstraintViolation<Car>> constraintViolations =

validator.validateValue(

Car.class,

"manufacturer",

null

);

System.out.println(constraintViolations.size());//1

//制造商不能为空

System.out.println(constraintViolations.iterator().next().getMessage());

2.3 约束违反方法(ConstraintViolation methods)

  • getMessage():获取内置的错误信息
  • getMessageTemplate():获取非内置的错误信息
  • getRootBean():获取正在接受验证的对象
  • getRootBeanClass():获取正在接受验证的对象的类
  • getLeafBean():如果一个类级约束,则返回该约束应用于bean实例;如果是属

性级约束,则返回承载该约束的属性的bean实例

  • getPropertyPath():获取验证失败的属性名称
  • getInvalidValue():获取未通过验证的属性值
  • getConstraintDescriptor():获取约束元数据描述符

2.4 内置约束

Bean验证约束都适用于字段/属性级别,Bean验证规范中没有定义类级别约束

  • @AssertFalse:验证被注解元素是false
  • @AssertTrue:验证被注解元素是true
  • @DecimalMax(value=, inclusive=):验证小于或等于(取决于inclusive)

value,支持BigDecimal, BigInteger, CharSequence, byte, short, int, long以

及它们的包装类

  • @DecimalMin(value=, inclusive=)
  • @Digits(integer=, fraction=):验证被注解元素具有最多的整数位数和小数位数
  • @Future:Checks whether the annotated date is in the future
  • @Past
  • @Max(value=):验证被注解元素是否小于或等于value
  • @Min(value=)
  • @NotNull:Checks that the annotated value is not null,Supported data

types:Any type

  • @Null
  • @Pattern(regex=, flags=):检查带注释的字符串是否与正则表达式匹配(考虑

给定的标志匹配)

  • @Size(min=, max=):检查带注释的元素的大小是否在min和max之间(包括),

支持类型:CharSequence, Collection, Map and arrays

  • @Valid:递归地对关联对象执行验证。如果对象是集合或数组,则递归地验证

元素。如果对象是Map,则递归地验证值元素

2.5 附加约束

  • @Email
  • @Length(min=, max=):验证字符序列在min和max之间(含)
  • @NotBlank:验证字符串是否为“ ”或null或""
  • @NotEmpty:验证CharSequence, Collection, Map and arrays是否为null或empty
  • @Range(min=, max=):Checks whether the annotated value lies between (inclusive) the specified minimum and maximum;Supported data types:

BigDecimal, BigInteger, CharSequence, byte, short, int, long and the respective

wrappers of the primitive types

  • @ScriptAssert(lang=, script=, alias=, reportOn=):检查给定脚本是否可以根据带注释的元素成功计算。为了使用这个约束,JSR 223定义的Java脚本API的实现(“针对JavaTM平台的脚本”)必须是类路径的一部分。要计算的表达式可以用任何脚本或表达式语言编写,在类路径中可以找到JSR 223兼容的引擎。即使这是一个类级约束,也可以使用reportOn属性报告对特定属性而不是整个对象的约束违反

@ScriptAssert.List({

@ScriptAssert(lang = "javascript", alias = "_",

script = "_.tpl != null && _.tpl > 0 ? _.tplQuota != null : true",

message = "第三者责任险额度未选择"),

@ScriptAssert(lang = "javascript", alias = "_",

script = "_.rat != null && _.rat > 0 ? _.vdi != null && _.vdi > 0 : true",

message = "购买无法找到第三者特约险,必须同时购买车辆损失险"),

@ScriptAssert(lang = "javascript", alias = "_",

script = "_.uft != null && _.uft > 0 ? _.vdi != null && _.vdi > 0 : true",

message = "购买全车盗抢险,必须同时购买车辆损失险"),

@ScriptAssert(lang = "javascript", alias = "_",

script = "_.gbr != null && _.gbr > 0 ? _.vdi != null && _.vdi > 0 : true",

message = "购买玻璃单独破碎险,必须同时购买车辆损失险"),

@ScriptAssert(lang = "javascript", alias = "_",

script = "_.gbr != null && _.gbr > 0 ? _.gbrGlassType != null : true",

message = "玻璃单独破碎险,玻璃类型未选择"),

@ScriptAssert(lang = "javascript", alias = "_",

script = "_.blb != null && _.blb > 0 ? _.tpl != null && _.tpl > 0 : true",

message = "购买无过责任险,必须同时购买第三者责任险"),

@ScriptAssert(lang = "javascript", alias = "_",

script = "_.bsr != null && _.bsr > 0 ? _.vdi != null && _.vdi > 0 : true",

message = "购买车身划痕险,必须同时购买车辆损失险"),

@ScriptAssert(lang = "javascript", alias = "_",

script = "_.bsr != null && _.bsr > 0 ? _.bsrQuota != null : true",

message = "车身划痕险额度未选择"),

@ScriptAssert(lang = "javascript", alias = "_",

script = "_.wad != null && _.wad > 0 ? _.vdi != null && _.vdi > 0 : true",

message = "购买涉水险/发动机特别损失险,必须同时购买车辆损失险")

})

二、声明和验证方法约束

从Bean Validation 1.1开始,约束不仅可以应用于javabean及其属性,还可以应用于任何Java类型的方法和构造函数的参数和返回值。这样就可以使用Bean验证约束来指定

1.声明方法约束

1.1 参数约束

通过向其参数添加约束注释来指定方法或构造函数的前提条件

public class RentalStation {

public RentalStation(@NotNull String name) {

//...

}

public void rentCar(

@NotNull Customer customer,

@NotNull @Future Date startDate,

@Min(1) int durationInDays) {

//...

}

}

约束只能应用于实例方法,即不支持对静态方法声明约束

1.2 交叉参数约束

有时,验证不仅取决于单个参数,还取决于方法或构造函数的几个甚至所有参数。可以借助交叉参数约束来满足这种要求。可以将交叉参数约束视为等同于类级约束的方法验证。两者都可用于实现基于多个元素的验证要求。虽然类级约束适用于bean的多个属性,但交叉参数约束适用于可执行文件的多个参数。例如:

在load()方法上声明的交叉参数约束用于确保没有乘客有两件以上的行李

public class Car {

@LugCountMatchesPassengerCount(piecesOfLugPerPassenger = 2)

public void load(List<Person> passengers, List<PieceOfLuggage> luggage) {

//...

}

}

返回值约束也在方法级别上声明。为了区分交叉参数约束和返回值约束,ConstraintValidator使用@SupportedValidationTarget注释在实现中配置约束目标

约束可以应用于可执行文件的参数(即,它是交叉参数约束),但也可以应用于返回值。一个例子是自定义约束,它允许使用表达式或脚本语言指定验证规则。类约束必须定义validationAppliesTo()可在声明时使用以指定约束目标的成员。如指定约束的目标所示,通过指定将约束应用于可执行文件的参数 validationAppliesTo = ConstraintTarget.PARAMETERS,同时ConstraintTarget.RETURN_VALUE用于将约束应用于可执行返回值。

public class Garage {

@ELAssert(expression = "...", validationAppliesTo = ConstraintTarget.PARAMETERS)

public Car buildCar(List<Part> parts) {

//...

return null;

}

@ELAssert(expression = "...", validationAppliesTo = ConstraintTarget.RETURN_VALUE)

public Car paintCar(int color) {

//...

return null;

}

}

1.3 返回值约束

通过向可执行文件添加约束注释来声明方法或构造函数的后置条件

public class RentalStation {

@ValidRentalStation

public RentalStation() {

//...

}

@NotNull

@Size(min = 1)

public List<Customer> getCustomers() {

//...

return null;

}

}

1.4 级联验证

@Valid注释可用于标记可执行参数并返回级联验证的值。验证带有注释@Valid的参数或返回值时,也会验证在参数或返回值对象上声明的约束

public class Garage {

@NotNull

private String name;

@Valid

public Garage(String name) {

this.name = name;

}

public boolean checkCar(@Valid @NotNull Car car) {

//...

return false;

}

}

public class Car {

@NotNull

private String manufacturer;

@NotNull

@Size(min = 2, max = 14)

private String licensePlate;

public Car(String manufacturer, String licencePlate) {

this.manufacturer = manufacturer;

this.licensePlate = licencePlate;

}

//getters and setters ...

}

验证checkCar()方法的参数时,Car也会评估传递对象的属性约束。类似地,在验证构造函数的返回值时@NotNull,Garage将检查名称字段的约束 Garage

级联验证不仅可以应用于简单对象引用,还可以应用于集合类型参数和返回值

is an array or implements java.lang.Iterable or implements java.util.Map

1.5 继承层次结构中的方法约束(todo 2019/05/12 23:44 )

2.验证方法约束

方法约束的验证是使用ExecutableValidator接口完成的

2.1 获取ExecutableValidator实例

ValidatorFactory factory = Validation.buildDefaultValidatorFactory();

ExecutableValidator executableValidator =

factory.getValidator().forExecutables();

2.2 ExecutableValidator方法

  • validateParameters():验证方法调用的参数

Car object = new Car( "Morris" );

Method method = Car.class.getMethod( "drive", int.class );

Object[] parameterValues = { 80 };

Set<ConstraintViolation<Car>> violations =

executableValidator.validateParameters(

object,

method,

parameterValues

);

assertEquals( 1, violations.size() );

Class<? extends Annotation> constraintType = violations.iterator()

.getConstraintDescriptor()

.getAnnotation()

.annotationType();

assertEquals( Max.class, constraintType );

  • validateReturnValue():验证返回值

Car object = new Car( "Morris" );

Method method = Car.class.getMethod( "getPassengers" );

Object returnValue = Collections.<Passenger>emptyList();

Set<ConstraintViolation<Car>> violations =

executableValidator.validateReturnValue(

object,

method,

returnValue

);

assertEquals( 1, violations.size() );

Class<? extends Annotation> constraintType = violations.iterator()

.next()

.getConstraintDescriptor()

.getAnnotation()

.annotationType();

assertEquals( Size.class, constraintType );

  • validateConstructorParameters():验证构造函数调用的参数

Constructor<Car> constructor = Car.class.getConstructor( String.class );

Object[] parameterValues = { null };

Set<ConstraintViolation<Car>> violations =

executableValidator.validateConstructorParameters(

constructor,

parameterValues

);

assertEquals( 1, violations.size() );

Class<? extends Annotation> constraintType = violations.iterator()

.next()

.getConstraintDescriptor()

.getAnnotation()

.annotationType();

assertEquals( NotNull.class, constraintType );

  • validateConstructorReturnValue():验证构造函数的返回值

Constructor<Car> constructor = Car.class.getConstructor( String.class,

String.class );

Car createdObject = new Car( "Morris", null );

Set<ConstraintViolation<Car>> violations =

executableValidator.validateConstructorReturnValue(

constructor,

createdObject

);

assertEquals( 1, violations.size() );

Class<? extends Annotation> constraintType = violations.iterator()

.next()

.getConstraintDescriptor()

.getAnnotation()

.annotationType();

assertEquals( ValidRacingCar.class, constraintType );

3. 内置方法约束

  • @ParameterScriptAssert:通用的跨参数限制

public class Car {

@ParameterScriptAssert(lang = "javascript", script = "arg1.size() <=

arg0.size() * 2")

public void load(List<Person> passengers, List<PieceOfLuggage>

luggage)

{

//...

}

}

三、分组验证

1. Requesting groups

//人类

public class Person {

@NotNull

private String name;

public Person(String name) {

this.name = name;

}

// getters and setters ...

}

//司机

public class Driver extends Person {

@Min(

value = 18,

message = "You have to be 18 to drive a car",

groups = DriverChecks.class

)

public int age;

@AssertTrue(

message = "You first have to pass the driving test",

groups = DriverChecks.class

)

public boolean hasDrivingLicense;

public Driver(String name) {

super( name );

}

public void passedDrivingTest(boolean b) {

hasDrivingLicense = b;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

}

//司机校验组

public interface DriverChecks {

}

//车辆

public class Car {

@NotNull

private String manufacturer;

@NotNull

@Size(min = 2, max = 14)

private String licensePlate;

@Min(2)

private int seatCount;

@AssertTrue(

message = "The car has to pass the vehicle inspection first",

groups = CarChecks.class

)

private boolean passedVehicleInspection;

@Valid

private Driver driver;

public Car(String manufacturer, String licencePlate, int seatCount) {

this.manufacturer = manufacturer;

this.licensePlate = licencePlate;

this.seatCount = seatCount;

}

public boolean isPassedVehicleInspection() {

return passedVehicleInspection;

}

public void setPassedVehicleInspection(boolean passedVehicleInspection) {

this.passedVehicleInspection = passedVehicleInspection;

}

public Driver getDriver() {

return driver;

}

public void setDriver(Driver driver) {

this.driver = driver;

}

// getters and setters ...

}

//车辆校验组

public interface CarChecks {

}

Person.name,Car.manufacturer,Car.licensePlate和Car.seatCount 都属于

Default组

Driver.age和Driver.hasDrivingLicense属于DriverChecks

Car.passedVehicleInspection属于该组CarChecks

2. Group inheritance(组继承)

在使用验证组时,我们需要调用validate()每个验证组,或逐个指定所有验证

组。在某些情况下,您可能希望定义一组包含另一个组的约束。您可以使用组继承

来实现。

public class SuperCar extends Car {

@AssertTrue(

message = "Race car must have a safety belt",

groups = RaceCarChecks.class

)

private boolean safetyBelt;

// getters and setters ...

}

import javax.validation.groups.Default;

public interface RaceCarChecks extends Default {

}

3. 定义组序列

为了实现这样的验证顺序,只需要定义一个接口并对其进行注解@GroupSequence

@GroupSequence({ Default.class, CarChecks.class, DriverChecks.class })

public interface OrderedChecks {

}

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码