背景:
一般系统对表单的提交都会提供一定的校验,分为前台校验和后台校验,前台校验主要为了减轻服务器的负担,后台校验增加系统安全性。在公司项目里看到validation的使用,在此做个简单学习记录。
例子学习:
创建一个maven项目,pom.xml 如下
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.test</groupId>
<artifactId>validationTest</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>2.2.4</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.1.3.Final</version>
</dependency>
</dependencies>
</project>
创建一个实体类StudentInfo
public class StudentInfo {
@NotBlank(message="用户名不能为空")
private String userName;
@NotBlank(message="年龄不能为空")
@Pattern(regexp="^[0-9]{1,2}$",message="年龄是整数")
private String age;
/**
* @Pattern的意思是,如果是空,则不校验,如果不为空,则校验
*/
@Pattern(regexp="^[0-9]{4}-[0-9]{2}-[0-9]{2}$",message="出生日期格式不正确")
private String birthday;
@NotBlank(message="学校不能为空")
private String school;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
public String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
}
创建校验工具ValidatorUtil.java(这里写成工具类的形式便于使用)
public class ValidatorUtil{
//创建静态校验工厂
private static Validator validator = Validation.buildDefaultValidatorFactory()
.getValidator();
public static <T> Map<String,StringBuffer> validate(T obj){
//校验过程
Set<ConstraintViolation<T>> set = validator.validate(obj,Default.class);
//校验结果输出,可以自定义
Map<String,StringBuffer> errorMap = null;
if(set != null && set.size() >0 ){
errorMap = new HashMap<String,StringBuffer>();
String property = null;
for(ConstraintViolation<T> cv : set){
//这里循环获取错误信息,可以自定义格式
property = cv.getPropertyPath().toString();
if(errorMap.get(property) != null){
errorMap.get(property).append("," + cv.getMessage());
}else{
StringBuffer sb = new StringBuffer();
sb.append(cv.getMessage());
errorMap.put(property, sb);
}
}
}
return errorMap;
}
}
最后写个测试类ValidatorTest.java
public class ValidatorTest {
public static void main(String[] args) {
StudentInfo s = new StudentInfo();
long startTime = System.currentTimeMillis();
print(ValidatorUtil.validate(s));
System.out.println("===============耗时(毫秒)=" + (System.currentTimeMillis() - startTime));
s.setUserName("chenwb");
s.setAge("a10");
s.setBirthday("2016-9-1");
startTime = System.currentTimeMillis();
print(ValidatorUtil.validate(s));
System.out.println("===============耗时(毫秒)=" + (System.currentTimeMillis() - startTime));
}
private static void print(Map<String,StringBuffer> errorMap){
if(errorMap != null){
for(Map.Entry<String, StringBuffer> m : errorMap.entrySet()){
System.out.println(m.getKey() + ":" + m.getValue().toString());
}
}
}
}
------------------------------------------------------------------------------------
测试结果:
school:学校不能为空
userName:用户名不能为空
age:年龄不能为空
===============耗时(毫秒)=298
birthday:出生日期格式不正确
school:学校不能为空
age:年龄是整数
===============耗时(毫秒)=4
总结:
对于这个例子相信主要的问题是在这个工具类上,目前已知的是校验过程在
//校验过程
Set<ConstraintViolation<T>> set = validator.validate(obj,Default.class);这句话中,validate()是Validator类的方法,返回的是Set<ConstraintViolation<T>>集合。
看一下这个接口的注释:(Validates all constraints on {@code object})
/**
* Validates all constraints on {@code object}.
*
* @param object object to validate
* @param groups the group or list of groups targeted for validation (defaults to
* {@link Default})
* @return constraint violations or an empty set if none
* @throws IllegalArgumentException if object is {@code null}
* or if {@code null} is passed to the varargs groups
* @throws ValidationException if a non recoverable error happens
* during the validation process
*/
<T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups);
ConstraintViolation类源码:
public interface ConstraintViolation<T> {
/**
* @return the interpolated error message for this constraint violation
*/
String getMessage();
/**
* @return the non-interpolated error message for this constraint violation
*/
String getMessageTemplate();
/**
* Returns the root bean being validated. For method validation, returns
* the object the method is executed on.
* <p/>
* Returns {@code null} when:
* <ul>
* <li>the {@code ConstraintViolation} is returned after calling
* {@link Validator#validateValue(Class, String, Object, Class[])}</li>
* <li>the {@code ConstraintViolation} is returned after validating a
* constructor.</li>
* </ul>
*
* @return the validated object, the object hosting the validated element or {@code null}
*/
T getRootBean();
/**
* Returns the class of the root bean being validated.
* For method validation, this is the object class the
* method is executed on.
* For constructor validation, this is the class the constructor
* is declared on.
*
* @return the class of the root bean or of the object hosting the validated element
*/
Class<T> getRootBeanClass();
/**
* Returns:
* <ul>
* <li>the bean instance the constraint is applied on if it is
* a bean constraint</li>
* <li>the bean instance hosting the property the constraint
* is applied on if it is a property constraint</li>
* <li>{@code null} when the {@code ConstraintViolation} is returned
* after calling {@link Validator#validateValue(Class, String, Object, Class[])}
* </li>
* <li>the object the method is executed on if it is
* a method parameter, cross-parameter or return value constraint</li>
* <li>{@code null} if it is a constructor parameter or
* cross-parameter constraint</li>
* <li>the object the constructor has created if it is a
* constructor return value constraint</li>
* </ul>
*
* @return the leaf bean
*/
Object getLeafBean();
/**
* Returns an {@code Object[]} representing the constructor or method invocation
* arguments if the {@code ConstraintViolation} is returned after validating the
* method or constructor parameters.
* Returns {@code null} otherwise.
*
* @return parameters of the method or constructor invocation or {@code null}
*
* @since 1.1
*/
Object[] getExecutableParameters();
/**
* Returns the return value of the constructor or method invocation
* if the {@code ConstraintViolation} is returned after validating the method
* or constructor return value.
* <p/>
* Returns {@code null} if the method has no return value.
* Returns {@code null} otherwise.
*
* @return the method or constructor return value or {@code null}
*
* @since 1.1
*/
Object getExecutableReturnValue();
/**
* @return the property path to the value from {@code rootBean}
*/
Path getPropertyPath();
/**
* Returns the value failing to pass the constraint.
* For cross-parameter constraints, an {@code Object[]} representing
* the method invocation arguments is returned.
*
* @return the value failing to pass the constraint
*/
Object getInvalidValue();
/**
* Returns the constraint metadata reported to fail.
* The returned instance is immutable.
*
* @return constraint metadata
*/
ConstraintDescriptor<?> getConstraintDescriptor();
/**
* Returns an instance of the specified type allowing access to
* provider-specific APIs. If the Bean Validation provider
* implementation does not support the specified class,
* {@link ValidationException} is thrown.
*
* @param type the class of the object to be returned
* @return an instance of the specified class
* @throws ValidationException if the provider does not support the call
*
* @since 1.1
*/
<U> U unwrap(Class<U> type);
}
例子中主要用到了getMessage()和getPropertyPath()