JSR 303(Bean Validation )

说明:

  在任何时候,当你要处理一个应用程序的业务逻辑,数据校验是你必须要考虑和面对的事情。应用程序必须通过某种手段来确保输入进来的数据从语义上来讲是正确的。

  在通常的情况下,应用程序是分层的,不同的层由不同的开发人员来完成。很多时候同样的数据验证逻辑会出现在不同的层,这样就会导致代码冗余和一些管理的问题,比如说语义的一致性等。为了避免这样的情况发生,最好是将验证逻辑与相应的域模型进行绑定。

  Bean Validation 为 JavaBean 验证定义了相应的元数据模型和 API。默认的元数据是 Java Annotations,也可以通过使用 XML 可以对原有的元数据信息进行覆盖和扩展。在应用程序中,通过使用 Bean Validation 或是你自己定义的 constraint(约束/限制),例如 @NotNull, @Max, @ZipCode, 就可以确保数据模型(JavaBean)的正确性。constraint 可以附加到字段,getter 方法,类或者接口上面。对于一些特定的需求,用户可以很容易的开发定制化的 constraint。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

Bean Validation 中的 constraint

表 1. Bean Validation 中内置的 constraint

Constraint 详细信息
@Null 被注释的元素必须为 null
@NotNull 被注释的元素必须不为 null
@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 被注释的元素必须在合适的范围内

在IDEA中使用JSR 303

加入Jar包

  

  说明:切记要同时拷贝入在Tomcat的lib目录中。

在要验证的的JavaBean中加入约束条件

package domain;

import javax.validation.constraints.Past;
import javax.validation.constraints.Size;
import java.io.Serializable;
import java.util.Date; /**
* Created by zy on 17-2-28.
*/
public class Product implements Serializable {
//实现了这个接口,可以安全的将数据保存到HttpSession中
private static final long serialVersionUID= 748392348L;
/**
* 序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。如果接收者加载的该对象的类的 serialVersionUID 与对应的发送者的类的版本号不同,则反序列化将会导致 InvalidClassException。可序列化类可以通过声明名为 "serialVersionUID" 的字段(该字段必须是静态 (static)、最终 (final) 的 long 型字段)显式声明其自己的 serialVersionUID:
*/
private long id;
//被注释的元素的大小必须在指定的范围内
@Size(min = ,max = ,message="不能超过十个字符")
private String name; private String description;
private String price;
//被注释的元素必须是一个过去的日期
@Past
private Date productionDate; public Date getProductionDate() {
return productionDate;
} public void setProductionDate(Date productionDate) {
this.productionDate = productionDate;
} public long getId() {
return id;
} public void setId(long id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getDescription() {
return description;
} public void setDescription(String description) {
this.description = description;
} public String getPrice() {
return price;
} public void setPrice(String price) {
this.price = price;
} public String toString() {
return "Product{" +
"id=" + id +
", name='" + name + '\'' +
", description='" + description + '\'' +
", price='" + price + '\'' +
", productionDate=" + productionDate +
'}';
}
}

在要进行验证的控制器参数前加上@Valid

@RequestMapping(value = "/product_save",method = RequestMethod.POST)
public String saveProduct(@Valid @ModelAttribute Product product, BindingResult bindingResult,Model model)
{
logger.info("saveProduct called");
if(bindingResult.hasErrors())
{
List<ObjectError>objectErrors=bindingResult.getAllErrors();
Iterator<ObjectError> it =objectErrors.iterator();
while (it.hasNext())
{ System.out.println(it.next().toString());
}
//FieldError fieldError = bindingResult.getFieldError();
//logger.info("code:"+fieldError.getCode()+",object:"+fieldError.getObjectName()+",field:"+fieldError.getField());
product.setProductionDate(null);
model.addAttribute("product",product);
return "ProductForm";
}
model.addAttribute("product",product);
return "ProductForm";
}

其他:调用转换器,来规范日期时间

1.编译转换器

package converter;

import org.springframework.core.convert.converter.Converter;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date; public class MyConverter implements Converter<String,Date> {
//<源类型,目标类型>
private String dataPattern;
public MyConverter(String dataPattern)
{
this.dataPattern=dataPattern;
System.out.println("DataPattern is"+dataPattern);
}
public Date convert(String s) {
try {
SimpleDateFormat simpleDateFormat= new SimpleDateFormat(dataPattern);
simpleDateFormat.setLenient(false);
//设置日期/时间的解析是否不严格,为false表示严格 return simpleDateFormat.parse(s);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}

2.在SpringMVC的xml文件中配置转换器

<!--【注册转换器】-->
<mvc:annotation-driven conversion-service="conversionService"/>
<!--【配置转换器】-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="converter.MyConverter">
<constructor-arg type="java.lang.String" value="MM-dd-yyyy"/>
</bean>
</list>
</property>
</bean>

测试应用

输入错误表单信息:

  

控制台显示错误日志:

Field error in object 'product' on field 'name': rejected value [我就是要超过十个字符啊]; codes [Size.product.name,Size.name,Size.java.lang.String,Size]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [product.name,name]; arguments []; default message [name],10,1]; default message [不能超过十个字符]
Field error in object 'product' on field 'productionDate': rejected value [Sat Dec 23 00:00:00 CST 2017]; codes [Past.product.productionDate,Past.productionDate,Past.java.util.Date,Past]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [product.productionDate,productionDate]; arguments []; default message [productionDate]]; default message [需要是一个过去的时间]

SpringMVC:学习笔记(7)——验证器(JSR303)的更多相关文章

  1. SpringMVC学习笔记九:拦截器及拦截器的简单实用

    SpringMVC中的interceptor拦截器是非常重要的,它的主要作用就是拦截指定的用户请求,并进行相应的预处理和后处理. 拦截时间点在"处理器映射器根据用户提交的请求映射出所要执行的 ...

  2. SpringMVC 学习笔记(六)拦截器

    5.1.处理器拦截器简介 Spring Web MVC的处理器拦截器(如无特殊说明,下文所说的拦截器即处理器拦截器) 类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理. ...

  3. SpringMVC 学习笔记(处理器映射器的配置)

    前端控制器(dispatchServlet) 在web.xml中配置前端控制器,在服务器启动时就被创建,用来对请求和响应进行接收 和 分发处理,其在配置时可以设置一个初始化参数,用来定位SpringM ...

  4. SpringMVC学习笔记:拦截器和过滤器

    首先说明一下二者的区别: 1. 拦截器基于java的反射机制,而过滤器是基于函数回调 2. 拦截器不依赖于servlet容器,过滤器依赖servlet容器 3. 拦截器只能对action请求起作用,而 ...

  5. 史上最全的SpringMVC学习笔记

    SpringMVC学习笔记---- 一.SpringMVC基础入门,创建一个HelloWorld程序 1.首先,导入SpringMVC需要的jar包. 2.添加Web.xml配置文件中关于Spring ...

  6. springmvc学习笔记(简介及使用)

    springmvc学习笔记(简介及使用) 工作之余, 回顾了一下springmvc的相关内容, 这次也为后面复习什么的做个标记, 也希望能与大家交流学习, 通过回帖留言等方式表达自己的观点或学习心得. ...

  7. springmvc学习笔记(常用注解)

    springmvc学习笔记(常用注解) 1. @Controller @Controller注解用于表示一个类的实例是页面控制器(后面都将称为控制器). 使用@Controller注解定义的控制器有如 ...

  8. java之jvm学习笔记四(安全管理器)

    java之jvm学习笔记四(安全管理器) 前面已经简述了java的安全模型的两个组成部分(类装载器,class文件校验器),接下来学习的是java安全模型的另外一个重要组成部分安全管理器. 安全管理器 ...

  9. SpringMVC:学习笔记(8)——文件上传

    SpringMVC--文件上传 说明: 文件上传的途径 文件上传主要有两种方式: 1.使用Apache Commons FileUpload元件. 2.利用Servlet3.0及其更高版本的内置支持. ...

随机推荐

  1. PyCharm创建文件时自动添加头注释

    进入设置 File->settings->Editor->File and Code Templates->Python Script 添加以下代码: #!/usr/bin/e ...

  2. 在python中Flask配置服务

    from flask import Flask, request from data_util import UtilsLTPTranslate import json model = UtilsLT ...

  3. shell实现倒计时功能

    #!/bin/bash ############################################################## # File Name: oldboyedu.sh ...

  4. Mongodb 与 MySQL对比

    在数据库存放的数据中,有一种特殊的键值叫做主键,它用于惟一地标识表中的某一条记录.也就是说,一个表不能有多个主键,并且主键不能为空值. 无论是MongoDB还是MySQL,都存在着主键的定义. 对于M ...

  5. 第一百六十七节,jQuery,DOM 节点操作,DOM 节点模型操作

    jQuery,DOM 节点操作,DOM 节点模型操作 学习要点: 1.创建节点 2.插入节点 3.包裹节点 4.节点操作 DOM 中有一个非常重要的功能,就是节点模型,也就是 DOM 中的“M”.页面 ...

  6. 利用微信小程序实现web监控界面

    1.实现思路 利用小程序去调用公司zabbix的接口获取网站监控数据并展示出来. 2.准备阶段 1.小程序公众号 2.企业号 3.zabbix接口 3.实现过程

  7. MVC action 执行两次 background url()

    大年初七第一天上班就来解决问题,我也是醉了. 其实是历史遗留问题,今天看到后不能忍了,赶紧解决一下. 旧系统中以一个微信版本的列表页面没有问题,在新系统中重新开发一边后发现列表页面的action总是请 ...

  8. Java的四种引用,强弱软虚,用到的场景

    众所周知,java中是JVM负责内存的分配和回收,这是它的优点(使用方便,程序不用再像使用c那样操心内存),但同时也是它的缺点(不够灵活).为了解决内存操作不灵活这个问题,可以采用软引用等方法. 在J ...

  9. JFrame上添加、删除Jpanel后动态显示界面问题

    JFrame中动态添加或者删除JPanel后总是不正确显示需要的界面问题: 1.删除panel后还是显示之前的界面,新删除的panel在界面上并没有被删除: 2.删除panel1后添加新的panel2 ...

  10. Django 模板系统(template)

    介绍 官方文档 常用模板语法 只需要记两种特殊符号: {{  }} 和  {% %} 变量相关的用{{}} 逻辑相关的用{%%} 变量 {{ 变量名 }} 变量名由字母数字和下划线组成. 点(.)在模 ...