1.Bean Validation

在任何时候,当你要处理一个应用程序的业务逻辑,数据校验是你必须要考虑和面对的事情。应用程序必须通过某种手段来确保输入进来的数据从语义上来讲是正确的。在通常的情况下,应用程序是分层的,不同的层由不同的开发人员来完成。很多时候同样的数据验证逻辑会出现在不同的层,这样就会导致代码冗余和一些管理的问题,比如说语义的一致性等。为了避免这样的情况发生,最好是将验证逻辑与相应的域模型进行绑定。

Bean Validation 为 JavaBean 验证定义了相应的元数据模型和 API。缺省的元数据是 Java Annotations,通过使用 XML 可以对原有的元数据信息进行覆盖和扩展。在应用程序中,通过使用 Bean Validation 或是你自己定义的 constraint,例如 @NotNull, @Max, @ZipCode, 就可以确保数据模型(JavaBean)的正确性。constraint 可以附加到字段,getter 方法,类或者接口上面。对于一些特定的需求,用户可以很容易的开发定制化的 constraint。Bean Validation 是一个运行时的数据验证框架,在验证之后验证的错误信息会被马上返回。

Bean Validation 中内置的 constraint
@NotNull/@Null
验证字段:引用数据类型
注解说明:注解元素必须是非空/空

@AssertTrue/@AssertFalse
验证字段:boolean
注解说明:注解元素必须是true/false

@Max(value)/@Min(value)
验证字段:byte、short、int、long及对应的包装类型以及BigDecimal、BigInteger
注解说明:验证值是否小于等于最大指定整数值/大于等于最小指定整数值

@DecimalMax(value)/@DecimalMin(value)
验证字段:byte、short、int、long及对应的包装类型以及BigDecimal、BigInteger、String
属性说明:验证值是否小于等于最大指定小数值/大于等于最小指定小数值

@Size(max, min)
验证字段:String、Collection、Map和数组
注解说明:验证元素大小是否在指定范围内
属性说明:max:最大长度,min:最小长度,message:提示信息,默认:{constraint.size}

@Digits(integer, fraction)
验证字段:byte、short、int、long及各自的包装类型以及BigDecimal、BigInteger、String
注解说明:验证数字构成是否合法
属性说明:integer:指定整数部分数字位数,fraction:指定小数部分数字位数

@Future/@Past
验证字段:java.util.Date,java.util.Calendar
注解说明:验证是否在当前系统时间之后/之前

@Pattern(value)
验证字段:String
注解说明:验证字符串是否匹配指定的正则表达式
属性说明:regexp:匹配的正则表达式,flags:指定Pattern.Flag的数值,表示正则表达式的选项

@Valid
验证字段:引用类型
属性说明:验证值是否需要递归调用

示例
@size (min=3, max=20, message="用户名长度只能在3-20之间")
@size (min=6, max=20, message="密码长度只能在6-20之间")
@pattern (regexp="[a-za-z0-9._%+-]+@[a-za-z0-9.-]+\.[a-za-z]{2,4}", message="邮件格式错误")
@NotNull(message = "用户名称不能为空")
@Max(value = 100, message = "年龄不能大于100岁")
@Min(value= 18 ,message= "必须年满18岁!" )

@AssertTrue(message = "bln4 must is true")
@AssertFalse(message = "blnf must is falase")
@DecimalMax(value="100",message="decim最大值是100")
DecimalMin(value="100",message="decim最小值是100")
@NotNull(message = "身份证不能为空")
@Pattern(regexp="\d{18,18}|\d{15,15}|(\d{17,17}[x|X])$", message="身份证格式错误")

2.Hibernate Validator

Hibernate Validator 是 Bean Validation 的参考实现 . Hibernate Validator 提供了 JSR 303 规范中所有内置 constraint 的实现,除此之外还有一些附加的 constraint。

Hibernate Validator 附加的 constraint
@Email
注解说明:被注释的元素必须是电子邮箱地址
@Length
注解说明:长度限制。被注释的字符串的大小必须在指定的范围内
@NotEmpty
注解说明:被注释的字符串的必须非空
@Range
注解说明:被注释的元素必须在合适的范围内

示例
@Email(message = "比如输入正确的邮箱")
@Length(min = 5, max = 20, message = "用户名长度必须位于5到20之间")

3.扩展自定义的constraint

一个 constraint 通常由 annotation 和相应的 constraint validator 组成,它们是一对多的关系。也就是说可以有多个 constraint validator 对应一个 annotation。在运行时,Bean Validation 框架本身会根据被注释元素的类型来选择合适的 constraint validator 对数据进行验证。

有些时候,在用户的应用中需要一些更复杂的 constraint。Bean Validation 提供扩展 constraint 的机制。可以通过两种方法去实现,一种是组合现有的 constraint 来生成一个更复杂的 constraint,另外一种是开发一个全新的 constraint

4.实战

通过创建一个虚构的订单管理系统(基于 JSP 的 web 应用)来演示如何在 Java 开发过程中应用 Bean Validation。

1>.系统设计和运用的技术

2>.数据模型

3>.声明了 contraint 的 JavaBean

Order.java
```代码
package net.quickcodes.demo.domain;

import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;

import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.Date;

/**
* Created by mac.manon on 2016/10/20.
*/
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; // 嵌套验证
@Valid
private Product product; 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;
}

}
```

Product.java
```代码
package net.quickcodes.demo.domain;

import org.hibernate.validator.constraints.NotEmpty;

/**
* Created by mac.manon on 2016/10/20.
*/
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;
}

}
```

OrderQuery.java

package net.quickcodes.demo.domain;

import java.util.Date;

/**
* Created by mac.manon on 2016/10/20.
*/
// 'to'所表示的日期必须在'from'所表示的日期之后
// @QueryConstraint 是一个定制化的 constraint
@QueryConstraint
public class OrderQuery { private Date from; private Date to; public Date getFrom() {
return from;
} public void setFrom(Date from) {
this.from = from;
} public Date getTo() {
return to;
} public void setTo(Date to) {
this.to = to;
}
}

4>.定制化的 constraint

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

package net.quickcodes.demo.domain;

import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import java.lang.annotation.*; /**
* Created by mac.manon on 2016/10/20.
*/
// @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.
@Status 的 annotation 部分

package net.quickcodes.demo.domain;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*; /**
* Created by mac.manon on 2016/10/20.
*/
@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 部分

package net.quickcodes.demo.domain;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.Arrays; /**
* Created by mac.manon on 2016/10/20.
*/
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;
}
}

5>.界面

6>.使用 Bean Validation API对这些信息的校验

关键代码:
Order order = new Order();
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Set> violations = validator.validate(order);

protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
HttpSession session = req.getSession(); // 从 request 中获取输入信息
String orderId = (String) req.getParameter("orderId");
String customer = (String) req.getParameter("customer");
String email = (String) req.getParameter("email");
String address = (String) req.getParameter("address");
String status = (String) req.getParameter("status");
String productName = (String) req.getParameter("productName");
String productPrice = (String) req.getParameter("productPrice"); // 将 Bean 放入 session 中
Order order = new Order();
order.setOrderId(orderId);
order.setCustomer(customer);
order.setEmail(email);
order.setAddress(address);
order.setStatus(status);
order.setCreateDate(new Date()); Product product = new Product();
product.setName(productName);
if(productPrice != null && productPrice.length() > 0)
product.setPrice(Float.valueOf(productPrice));
order.setProduct(product); session.setAttribute("order", order); ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Set<ConstraintViolation<Order>> violations = validator.validate(order); if(violations.size() == 0) {
session.setAttribute("order", null);
session.setAttribute("errorMsg", null);
resp.sendRedirect("creatSuccessful.jsp");
} else {
StringBuffer buf = new StringBuffer();
ResourceBundle bundle = ResourceBundle.getBundle("messages"); for(ConstraintViolation<Order> violation: violations) {
buf.append("-" + bundle.getString(violation.getPropertyPath().toString()));
buf.append(violation.getMessage() + "<BR>\n");
}
session.setAttribute("errorMsg", buf.toString());
resp.sendRedirect("createOrder.jsp");
}
}

如果用户不填写任何信息提交订单,相应的错误信息将会显示在页面上

JSR教程1——JSR 303 - Bean Validation介绍的更多相关文章

  1. JSR 303 - Bean Validation 介绍及最佳实践

    JSR 303 - Bean Validation 介绍及最佳实践 JSR 303 – Bean Validation 是一个数据验证的规范,2009 年 11 月确定最终方案.2009 年 12 月 ...

  2. JSR 303 - Bean Validation 介绍及最佳实践(转)

    JSR 303 – Bean Validation 是一个数据验证的规范,2009 年 11 月确定最终方案.2009 年 12 月 Java EE 6 发布,Bean Validation 作为一个 ...

  3. JSR 303 - Bean Validation 是什么?

    关于 Bean Validation JSR 303 - Bean Validation 是jree6 中的一项子规范,JSR 303 - Bean Validation着重解决以下实际问题: 在任何 ...

  4. JSR 303 - Bean Validation 模型验证

    类是转载的,不知道转的哪里的. 此类依赖 JSR 303 – Bean Validation, Hibernate Validator. 代码不能直接运行.意会一下.自己改改. import com. ...

  5. JSR 303 - Bean Validation 简单介绍及用法

    一.JSR-303简单介绍 JSR-303 是 JAVA EE 6 中的一项子规范.叫做 Bean Validation,官方參考实现是Hibernate Validator. 此实现与 Hibern ...

  6. spring 3.1 配置 JCR 303 Bean Validation

    A) 导入Hibernate-Validator  要使用JSR303 校验框架, 需要加入框架的具体实现Hibernate-Validator, 在soureforge上下载最新的Hibernate ...

  7. JSR-303 Bean Validation 介绍及 Spring MVC 服务端参数验证最佳实践

    任何时候,当要处理一个应用程序的业务逻辑,数据校验是你必须要考虑和面对的事情. 应用程序必须通过某种手段来确保输入参数在上下文来说是正确的. 分层的应用很多时候同样的数据验证逻辑会出现在不同的层,这样 ...

  8. JSR-303 Bean Validation 介绍及 Spring MVC 服务端验证最佳实践

    任何时候,当要处理一个应用程序的业务逻辑,数据校验是你必须要考虑和面对的事情. 应用程序必须通过某种手段来确保输入参数在上下文来说是正确的. 分层的应用在很多时候,同样的数据验证逻辑会出现在不同的层, ...

  9. JSR 303 - Bean Validation 简介及使用方法

    参考:https://blog.csdn.net/xlgen157387/article/details/46848507 自己写的验证: /** * * @ClassName: BeanValida ...

随机推荐

  1. 分库分表中间件sharding-jdbc的使用

    数据分片产生的背景,可以查看https://shardingsphere.apache.org/document/current/cn/features/sharding/,包括了垂直拆分和水平拆分的 ...

  2. C/C++ 类成员函数指针 类成员数据指针

    普通函数指针:  "return_type (*ptr_name)(para_types) " 类成员函数指针: "return_type (class_name::*p ...

  3. python(27) 抓取淘宝买家秀

    selenium 是Web应用测试工具,可以利用selenium和python,以及chromedriver等工具实现一些动态加密网站的抓取.本文利用这些工具抓取淘宝内衣评价买家秀图片. 准备工作 下 ...

  4. 开源.NET界面库

    一.十大开源的.NET用户界面框架 选择一款合适的GUI框架是.NET开发中比较重要但又很棘手的问题,因为用户界面相当于一款应用的"门面",直接面向用户.好的UI更能吸引用户,有时 ...

  5. SQL记录-PLSQL游标

    PL/SQL游标 Oracle会创建一个存储区域,被称为上下文区域,用于处理SQL语句,其中包含需要处理的语句,例如所有的信息,行数处理,等等. 游标是指向这一上下文的区域. PL/SQL通过控制光标 ...

  6. 深度学习 vs. 概率图模型 vs. 逻辑学

    深度学习 vs. 概率图模型 vs. 逻辑学 摘要:本文回顾过去50年人工智能(AI)领域形成的三大范式:逻辑学.概率方法和深度学习.文章按时间顺序展开,先回顾逻辑学和概率图方法,然后就人工智能和机器 ...

  7. MySql数据库资料收集

    1.下载MySQL历史版本 https://downloads.mysql.com/archives/community/ https://downloads.mysql.com/archives/i ...

  8. expect 交互 telnet 交互

    telnet 交互 #!/bin/bash Ip="10.0.1.53" a="\{\'method\'\:\'doLogin\'\,\'params\'\:\{\'uN ...

  9. JAVA不可变类与可变类、值传递与引用传递深入理解

    一个由try...catch...finally引出的思考,在前面已经初步了解过不可变与可变.值传递与引用传递,在这里再次深入理解. 1.先看下面一个try..catch..finally的例子: P ...

  10. USB的挂起和唤醒(Suspend and Resume)【转】

    转自:http://m.blog.csdn.net/blog/luckywang1103/25244091 USB协议的第9章讲到USB可见设备状态[Universal Serial Bus Spec ...