Java validator整理

因为想对方法的入参和出参作简单的非空或者非空字符做校验,所以找了下相关的@NotNull注解

说明
javax.validation.constraints.NotNull Java提供的JSR校验规范
org.jetbrains.annotations.NotNull idea提供的校验注解,只在使用idea工具时有效,主要起注释功能,提醒调用者
com.sun.istack.internal 还不清楚

这里主要看下Java的JSR规范提供的校验

主要的实现框架有Hibernate validation和Spring Validation

依赖jar

<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>

JSR-303原生支持的限制有如下几种:

限制 说明
@Null 限制只能为null
@NotNull 限制必须不为null
@AssertFalse 限制必须为false
@AssertTrue 限制必须为true
@DecimalMax(value) 限制必须为一个不大于指定值的数字
@DecimalMin(value) 限制必须为一个不小于指定值的数字
@Digits(integer,fraction) 限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction
@Future 限制必须是一个将来的日期
@Max(value) 限制必须为一个不大于指定值的数字
@Min(value) 限制必须为一个不小于指定值的数字
@Past 限制必须是一个过去的日期
@Pattern(value) 定的正则表达式
@Size(max,min) 限制字符长度必须在min到max之间

除此之外,hibernate也还提供了其它的限制校验,在org.hibernate.validator.constraints包下

@NotBlank(message =) 验证字符串非null,且长度必须大于0

@Email 被注释的元素必须是电子邮箱地址

@Length(min=,max=) 被注释的字符串的大小必须在指定的范围内

@NotEmpty 被注释的字符串的必须非空

@Range(min=,max=,message=) 被注释的元素必须在合适的范围内

单独使用hibernate validation校验bean对象

参考ytasd项目代码

public class ValidatorUtil {
private static Validator validator = Validation.buildDefaultValidatorFactory()
.getValidator();
public static <T> ValidatorResult validate(T obj){
ValidatorResult result = new ValidatorResult();
Set<ConstraintViolation<T>> set = validator.validate(obj,Default.class);
if( CollectionUtils.isNotEmpty(set) ){
result.setHasErrors(true);
Map<String,String> errorMsg = new HashMap<String,String>();
for(ConstraintViolation<T> cv : set){
errorMsg.put(cv.getPropertyPath().toString(), cv.getMessage());
}
result.setErrorMsg(errorMsg);
}
return result;
} public static <T> ValidatorResult validateProperty(T obj,String propertyName){
ValidatorResult result = new ValidatorResult();
Set<ConstraintViolation<T>> set = validator.validateProperty(obj,propertyName,Default.class);
if( CollectionUtils.isNotEmpty(set) ){
result.setHasErrors(true);
Map<String,String> errorMsg = new HashMap<String,String>();
for(ConstraintViolation<T> cv : set){
errorMsg.put(propertyName, cv.getMessage());
}
result.setErrorMsg(errorMsg);
}
return result;
}
}

整合Spring

Bean校验处理器:BeanValidationPostProcessor

方法校验处理器:MethodValidationPostProcessor

这里我们主要关心对方法的入参、出参校验,所以主要看下MethodValidationPostProcessor的实现

关键代码

private Class<? extends Annotation> validatedAnnotationType = Validated.class;
@Override
public void afterPropertiesSet() {
Pointcut pointcut = new AnnotationMatchingPointcut(this.validatedAnnotationType, true);
Advice advice = (this.validator != null ? new MethodValidationInterceptor(this.validator) :
new MethodValidationInterceptor());
this.advisor = new DefaultPointcutAdvisor(pointcut, advice);
}

通过这段代码,我们可以看出,它主要对使用了Validated注解的类作拦截,拦截器是MethodValidationInterceptor

核心代码

private static Method forExecutablesMethod;

	private static Method validateParametersMethod;

	private static Method validateReturnValueMethod;

	static {
try {
//这里拿到ExecutableValidator
forExecutablesMethod = Validator.class.getMethod("forExecutables");
Class<?> executableValidatorClass = forExecutablesMethod.getReturnType();
validateParametersMethod = executableValidatorClass.getMethod(
"validateParameters", Object.class, Method.class, Object[].class, Class[].class);
validateReturnValueMethod = executableValidatorClass.getMethod(
"validateReturnValue", Object.class, Method.class, Object.class, Class[].class);
}
catch (Exception ex) {
// Bean Validation 1.1 ExecutableValidator API not available
}
}
public Object invoke(MethodInvocation invocation) throws Throwable {
Class<?>[] groups = determineValidationGroups(invocation);
if (forExecutablesMethod != null) {
Object executableValidator = ReflectionUtils.invokeMethod(forExecutablesMethod, this.validator);
Set<ConstraintViolation<?>> result = (Set<ConstraintViolation<?>>)
ReflectionUtils.invokeMethod(validateParametersMethod, executableValidator,
invocation.getThis(), invocation.getMethod(), invocation.getArguments(), groups);
if (!result.isEmpty()) {
throw new ConstraintViolationException(result);
}
Object returnValue = invocation.proceed();
result = (Set<ConstraintViolation<?>>)
ReflectionUtils.invokeMethod(validateReturnValueMethod, executableValidator,
invocation.getThis(), invocation.getMethod(), returnValue, groups);
if (!result.isEmpty()) {
throw new ConstraintViolationException(result);
}
return returnValue;
}
else {
return HibernateValidatorDelegate.invokeWithinValidation(invocation, this.validator, groups);
}
}

ExecutableValidator是关键的接口,它提供了对方法入参和返回值的校验

validateParameters(T object,
Method method,
Object[] parameterValues,
Class... groups);

validateReturnValue(T object,
Method method,
Object returnValue,
Class... groups);

validateConstructorParameters(Constructor constructor,
Object[] parameterValues,
Class... groups);

validateConstructorReturnValue(Constructor constructor,
T createdObject,
Class... groups);

返回的都是Set>,ConstraintViolation中封装了具体的信息

通过MethodValidationInterceptor可以看出,它主要帮我们做了自动调用校验方法的逻辑,但使用上比较麻烦,需要在类上加上Validated

默认只对@org.springframework.validation.annotation.Validated注解的Bean进行验证,我们可以修改validatedAnnotationType为其他注解类型来支持其他注解验证。而且目前只支持Hibernate Validator实现,在未来版本可能支持其他实现。

Controller层的校验只能使用BeanValidator?

我们可以自己写个aop调用MethodValidationInterceptor

<bean class="org.springframework.validation.beanvalidation.MethodValidationInterceptor" id="validationInterceptor" />
<aop:config>
<aop:pointcut id="validator" expression="execution(* com.yt.trade..*(..))" />
<aop:advisor advice-ref="validationInterceptor" pointcut-ref="validator"/>
</aop:config>

限制:

  1. 只能对Spring代理的类和方法进行验证,不能在内部调用中起效。
  2. 返回的信息类中没有参数名,提示不直观

    基于这两个问题,我们可以自己写拦截器作校验

自定义校验器

实现ConstraintValidator接口

@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy=MinValidator.class)
public @interface Min { int value() default 0; String message(); Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {};
}
public class MinValidator implements ConstraintValidator<Min, Integer> { private int minValue; public void initialize(Min min) {
// TODO Auto-generated method stub
//把Min限制类型的属性value赋值给当前ConstraintValidator的成员变量minValue
minValue = min.value();
} public boolean isValid(Integer value, ConstraintValidatorContext arg1) {
// TODO Auto-generated method stub
//在这里我们就可以通过当前ConstraintValidator的成员变量minValue访问到当前限制类型Min的value属性了
return value >= minValue;
} }

参考:

Spring3.1 对Bean Validation规范的新支持(方法级别验证)

http://www.iteye.com/topic/1122937

hibernate Validation使用示例及讲解

在系统中使用Bean Validation验证参数

http://haohaoxuexi.iteye.com/blog/1812584

http://my.oschina.net/qjx1208/blog/200946

Java validator整理的更多相关文章

  1. java笔记整理

    Java 笔记整理 包含内容     Unix Java 基础, 数据库(Oracle jdbc Hibernate pl/sql), web, JSP, Struts, Ajax Spring, E ...

  2. Java资料整理

    Java资料整理 原创 2017年08月25日 17:20:44 14211  1.LocalThread的应用场景,数据传输适合用LocalThread么 2.linux的基本命令    软链接.更 ...

  3. 自定义Java Validator

    自定义Java Validator 在项目中,针对汉字的长度计算,数据库和java的计算方式不一致,需要重新处理下java 的 Validator,使其满足项目 建立自定义的 validator an ...

  4. JAVA基础整理-集合篇(一)

    集合作为JAVA的基础知识,本来感觉自己理解的很清楚了,但是在最近的一次面试中还是答得不尽如人意!再次做一下整理,以便加深理解以及随时查阅. 首先,java.util包中三个重要的接口及特点:List ...

  5. Java数据结构整理(一)

    ava数据结构内容整理关键字: 数据结构 Collection:List.SetMap:HashMap.HashTable如何在它们之间选择一.Array , ArraysJava所有“存储及随机访问 ...

  6. 面试之Java知识整理

    1.面向对象都有哪些特性 继承.封装.多态性.抽象 2.Java中实现多态的机制是什么? 继承与接口 3.Java中异常分为哪些种类 3.1按照异常需要处理的时机分为编译时异常(CheckedExce ...

  7. Java细节整理——数组与内存控制

    重点:使用Java数组之前,必须对数组对象进行初始化. 当数组的所有元素都被分配了合适的内存空间,并指定了初始值时,数组的初始化完成.程序以后将不能重新改变数组对象在内存中的位置和大小. 知识点整理: ...

  8. java面试整理(会持续更新..)

    本人出道至今,经历了大大小小百余场战斗,,,下面整理的面试题有些有答案,有些没答案,那个谁说过:"要抱着怀疑的态度去编程,所以,即便有答案,也不一定正确,即便我本地正确,但是由于屏幕前的你和 ...

  9. Java基础整理

    一.Java中的遍历 1.在java开发中会碰到遍历List删除其中多个元素的情况,如果使用一般的for循环以及增强的for循环,代码会抛出异常ConcurrentModificationExcept ...

随机推荐

  1. HDU 3635 并查集+路径压缩+记录每个点移动次数

    题意: 给定n个点 oper个操作 每个点有1个龙珠 下面2种操作: T u v 把u点所有龙珠搬到v Q u  问u点当前所在城市 u点所在城市有几个龙珠 u点被移动几次 思路: 并查集可以求出 u ...

  2. PowerShell查询sql server

    function Invoke-SQL1: function Invoke-SQL { param( [string] $DBServer, [string] $Database, [string] ...

  3. HOG特征-理解篇

    网上去找关于HOG的资料,发现理解性的较少,并且较为冗长,为方便大家理解便自己写了篇,希望能对奋斗在特征提取第一线的同志们有所帮助: HOG即histogram of oriented gradien ...

  4. 全面解析java注解

    一.注解概述       1.学习注解能够读懂别人的代码,特别是框架相关的代码       2.让自己的编程更加简洁,代码更加清晰       3.让别人高看一眼,会使用自定义注解来解决问题     ...

  5. Apache Rewrite 服务器变量

    Apache提供给rewirte模块的环境变量大概分成5个类型. 第一部分: HTTP headers 部分参数 参数名称: HTTP_USER_AGENT 样例参考值: Mozilla/5.0 (W ...

  6. What is a heap?--reference

    A heap is a partially sorted binary tree. Although a heap is not completely in order, it conforms to ...

  7. iOS 图片加载框架- SDWebImage 解读

    在iOS的图片加载框架中,SDWebImage可谓是占据大半壁江山.它支持从网络中下载且缓存图片,并设置图片到对应的UIImageView控件或者UIButton控件.在项目中使用SDWebImage ...

  8. 你真的会用 SDWebImage?

    SDWebImage作为目前最受欢迎的图片下载第三方框架,使用率很高.但是你真的会用吗?本文接下来将通过例子分析如何合理使用SDWebImage. 使用场景:自定义的UITableViewCell上有 ...

  9. Android(java)学习笔记129:Tab标签的使用

    1.案例1---TabProject (1)首先是main.xml文件: <?xml version="1.0" encoding="utf-8"?> ...

  10. About gpref O(n2) --> O(1)

    http://www.ibm.com/developerworks/cn/linux/l-gperf.html 命令行处理和 gperf 的作用 命令行处理一直以来都是软件开发中最容易被忽视的领域.几 ...