JSR303-BeanValidation简介及使用

JSR-303简介

JSR-303 是 JAVA EE 6 中的一项子规范,叫做 Bean Validation,官方参考实现是Hibernate Validator。

在任何时候,当你要处理一个应用程序的业务逻辑,数据校验是你必须要考虑和面对的事情。应用程序必须通过某种手段来确保输入进来的数据从语义上来讲是正确的。在通常的情况下,应用程序是分层的,不同的层由不同的开发人员来完成。很多时候同样的数据验证逻辑会出现在不同的层,这样就会导致代码冗余和一些管理的问题,比如说语义的一致性等。为了避免这样的情况发生,最好是将验证逻辑与相应的域模型进行绑定。 Bean Validation 为 JavaBean 验证定义了相应的元数据模型和 API。缺省的元数据是 Java Annotations,通过使用 XML 可以对原有的元数据信息进行覆盖和扩展。在应用程序中,通过使用 Bean Validation 或是你自己定义的 constraint,例如 @NotNull, @Max, @ZipCode, 就可以确保数据模型(JavaBean)的正确性。constraint 可以附加到字段,getter 方法,类或者接口上面。对于一些特定的需求,用户可以很容易的开发定制化的 constraint。Bean Validation 是一个运行时的数据验证框架,在验证之后验证的错误信息会被马上返回。

注:此实现与 Hibernate ORM 没有任何关系。 JSR 303 用于对 Java Bean 中的字段的值进行验证。 Spring MVC 3.x 之中也大力支持 JSR-303,可以在控制器中对表单提交的数据方便地验证。 可以使用注解的方式进行验证

JSR 303 基本的校验规则

表 1. Bean Validation 中内置的 constraint

Constraint 详细信息
@Null 被注释的元素必须为 null
@NotNull 被注释的元素必须不为 null
@NotBlank 被注释的元素必须是字符串,检查元素是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格 @AssertTrue 被注释的元素必须为 true
@AssertFalse 被注释的元素必须为 false
@Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max, min) 被注释的元素的大小必须在指定的范围内
@Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past 被注释的元素必须是一个过去的日期
@Future 被注释的元素必须是一个将来的日期
@Pattern(value) 被注释的元素必须符合指定的正则表达式

表 2. Hibernate Validator 附加的 constraint

Constraint 详细信息
@Email 被注释的元素必须是电子邮箱地址
@Length 被注释的字符串的大小必须在指定的范围内 @NotEmpty 被注释的字符串的必须非空
@Range 被注释的元素必须在合适的范围内

一个 constraint 通常由 annotation 和相应的 constraint validator 组成,它们是一对多的关系。也就是说可以有多个 constraint validator 对应一个 annotation。在运行时,Bean Validation 框架本身会根据被注释元素的类型来选择合适的 constraint validator 对数据进行验证。 有些时候,在用户的应用中需要一些更复杂的 constraint。Bean Validation 提供扩展 constraint 的机制。可以通过两种方法去实现,一种是组合现有的 constraint 来生成一个更复杂的 constraint,另外一种是开发一个全新的 constraint。

使用案例

准备

依赖jar

validation-api-2.0.1.Final.jar:JSR的接口; hibernate-validator-6.0.16.Final.jar是对上述接口的实现; log4j、slf4j、slf4j-log4j

POM中添加注解

<!--jsr 303-->
<!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>2.0.1.Final</version>
</dependency>
<!-- hibernate validator-->
<!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.0.16.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.glassfish/javax.el -->
<dependency>
	<groupId>org.glassfish</groupId>
	<artifactId>javax.el</artifactId>
	<version>3.0.0</version>
</dependency>

完整案例

通过创建一个虚构的订单管理系统来演示如何在 Java 开发过程中应用 Bean Validation。通过ValidatorTest来验证系统对订单对象验证。

代码清单

code list

声明了contraint的JavaBean

Order类

package io.order;

import java.util.Date;

import javax.validation.Valid;
import javax.validation.constraints.*;

import io.order.annotation.Status;

public class Order {
	// 必须不为 null, 大小是 10
	@NotNull
	@Size(min = 10, max = 10)
	private String orderId;
	// 必须不为空
	@NotEmpty
	private String customer;
	// 必须是一个电子信箱地址
	@Email
	private String email;
	// 必须不为空
	@NotEmpty
	private String address;
	// 必须不为 null, 必须是下面四个字符串'created', 'paid', 'shipped', 'closed'其中之一
	// @Status 是一个定制化的 contraint
	@NotNull
	@Status
	private String status;
	// 必须不为 null
	@NotNull
	private Date createDate;
	public String getOrderId() {
		return orderId;
	}
	public void setOrderId(String orderId) {
		this.orderId = orderId;
	}
	public String getCustomer() {
		return customer;
	}
	public void setCustomer(String customer) {
		this.customer = customer;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	public String getStatus() {
		return status;
	}
	public void setStatus(String status) {
		this.status = status;
	}
	public Date getCreateDate() {
		return createDate;
	}
	public void setCreateDate(Date createDate) {
		this.createDate = createDate;
	}
	public Product getProduct() {
		return product;
	}
	public void setProduct(Product product) {
		this.product = product;
	}
	// 嵌套验证
	@Valid
	private Product product;
}

Product类

package io.order;

import javax.validation.constraints.NotEmpty;

import io.order.annotation.Price;

public class Product {
	// 必须非空
	@NotEmpty
	private String productName;
	// 必须在 8000 至 10000 的范围内
	// @Price 是一个定制化的 constraint
	/**
	 * 
	 */
	@Price
	private float price;
	
	public String getProductName() {
		return productName;
	}
	public void setProductName(String productName) {
		this.productName = productName;
	}
	public float getPrice() {
		return price;
	}
	public void setPrice(float price) {
		this.price = price;
	}
}

定制化的 constraint

@Price是一个定制化的 constraint,由两个内置的 constraint 组合而成。

@Price 的 annotation 部分

package io.order.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;

import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.constraints.*;

//@Max 和 @Min 都是内置的 constraint 
@Max(10000)
@Min(8000)
@Constraint(validatedBy = {})
@Documented
@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface Price {
	String message() default "错误的价格";

	Class<?>[] groups() default {};

	Class<? extends Payload>[] payload() default {};
}

@Status是一个新开发的 constraint.

package io.order.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import javax.validation.Constraint;
import javax.validation.Payload;
import io.order.validator.*;

@Constraint(validatedBy = { StatusValidator.class })
@Documented
@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface Status {
	String message() default "不正确的状态 , 应该是 'created', 'paid', shipped', closed'其中之一";

	Class<?>[] groups() default {};

	Class<? extends Payload>[] payload() default {};
}

@Status 的 constraint validator 部分(StatusValidator)

package io.order.validator;

import java.util.Arrays;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

import io.order.annotation.Status;

public class StatusValidator implements ConstraintValidator<Status, String> {
	private final String[] ALL_STATUS = { "created", "paid", "shipped", "closed" };

	public void initialize(Status status) {
	}

	public boolean isValid(String value, ConstraintValidatorContext context) {
		if (Arrays.asList(ALL_STATUS).contains(value))
			return true;
		return false;
	}
}

Bean Validation API 使用示例

ValidatorTest

package io.order;

import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

public class ValidatorTest {

	public static void main(String[] args) {
		Order order = new Order();
		order.setEmail("simon.qq.com");

		ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
		Validator validator = factory.getValidator();
		Set<ConstraintViolation<Order>> violations = validator.validate(order);

		if (violations.size() == 0) {
			System.out.println("validate ok!!!");
		} else {
			StringBuilder strbuilder = new StringBuilder();
			for (ConstraintViolation<Order> violation : violations) {
				strbuilder.append("-" + violation.getPropertyPath().toString());
				strbuilder.append(violation.getMessage() + "\n");
			}
			System.out.println(strbuilder.toString());			
		}
	}

}

结果

六月 08, 2019 11:11:27 下午 org.hibernate.validator.internal.util.Version <clinit>
INFO: HV000001: Hibernate Validator 6.0.16.Final
-customer不能为空
-status不能为null
-address不能为空
-status不正确的状态 , 应该是 'created', 'paid', shipped', closed'其中之一
-orderId不能为null
-email不是一个合法的电子邮件地址
-createDate不能为null

在Web项目中,通常是在controller层在调用service之前调用Bean Validation API进行bean进行校验。

附录

JSR303–Bean Validation规范

下载 JSR 303 – Bean Validation 规范 http://jcp.org/en/jsr/detail?id=303 Hibernate Validator 是 Bean Validation 的参考实现 . Hibernate Validator 提供了 JSR 303 规范中所有内置 constraint 的实现,除此之外还有一些附加的 constraint。如果想了解更多有关 Hibernate Validator 的信息,请查看 http://www.hibernate.org/subprojects/validator.html

转载于:https://my.oschina.net/socoolfj/blog/3059748

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值