Java validator整理
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>
限制:
- 只能对Spring代理的类和方法进行验证,不能在内部调用中起效。
- 返回的信息类中没有参数名,提示不直观
基于这两个问题,我们可以自己写拦截器作校验
自定义校验器
实现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整理的更多相关文章
- java笔记整理
Java 笔记整理 包含内容 Unix Java 基础, 数据库(Oracle jdbc Hibernate pl/sql), web, JSP, Struts, Ajax Spring, E ...
- Java资料整理
Java资料整理 原创 2017年08月25日 17:20:44 14211 1.LocalThread的应用场景,数据传输适合用LocalThread么 2.linux的基本命令 软链接.更 ...
- 自定义Java Validator
自定义Java Validator 在项目中,针对汉字的长度计算,数据库和java的计算方式不一致,需要重新处理下java 的 Validator,使其满足项目 建立自定义的 validator an ...
- JAVA基础整理-集合篇(一)
集合作为JAVA的基础知识,本来感觉自己理解的很清楚了,但是在最近的一次面试中还是答得不尽如人意!再次做一下整理,以便加深理解以及随时查阅. 首先,java.util包中三个重要的接口及特点:List ...
- Java数据结构整理(一)
ava数据结构内容整理关键字: 数据结构 Collection:List.SetMap:HashMap.HashTable如何在它们之间选择一.Array , ArraysJava所有“存储及随机访问 ...
- 面试之Java知识整理
1.面向对象都有哪些特性 继承.封装.多态性.抽象 2.Java中实现多态的机制是什么? 继承与接口 3.Java中异常分为哪些种类 3.1按照异常需要处理的时机分为编译时异常(CheckedExce ...
- Java细节整理——数组与内存控制
重点:使用Java数组之前,必须对数组对象进行初始化. 当数组的所有元素都被分配了合适的内存空间,并指定了初始值时,数组的初始化完成.程序以后将不能重新改变数组对象在内存中的位置和大小. 知识点整理: ...
- java面试整理(会持续更新..)
本人出道至今,经历了大大小小百余场战斗,,,下面整理的面试题有些有答案,有些没答案,那个谁说过:"要抱着怀疑的态度去编程,所以,即便有答案,也不一定正确,即便我本地正确,但是由于屏幕前的你和 ...
- Java基础整理
一.Java中的遍历 1.在java开发中会碰到遍历List删除其中多个元素的情况,如果使用一般的for循环以及增强的for循环,代码会抛出异常ConcurrentModificationExcept ...
随机推荐
- PowerDesigner 物理数据模型(PDM)
PowerDesigner 物理数据模型(PDM) 说明 数据库脚本sqldatabasegeneration存储 目录(?)[+] 一. PDM 介绍 物理数据模型(Physical ...
- 邮件Mail
邮件开发准备: 准备工作, 环境搭建: 1. 本地搭建一个邮件服务器 -à 易邮服务器,eyoumailserversetup.exe 2. 新建邮箱账号 张三给李四发邮件. 步骤1: 新建域名: 工 ...
- Win8.1激活
激活查询:在桌面状态下输入“Win+R”,进入运行栏目,输入slmgr.vbs -dlv 显示:最为详尽的激活信息,包括:激活ID.安装ID.激活截止日期 http://www.nruan.com/w ...
- Codeforces Round #325 (Div. 2) B. Laurenty and Shop 前缀和
B. Laurenty and Shop Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/586/p ...
- hdu 4044 GeoDefense (树形dp | 多叉树转二叉树)
题目链接:hdu-4044 题意 这是一个塔防游戏,地图是一个n个编号为1-n的节点的树, 节点1是敌人的基地,其他叶子节点都是你的基地. 敌人的基地会源源不断地出来怪兽,为了防止敌人攻进你的基 ...
- AIR 移动设备上的存储控制
File.documentsDirectory, File.userDirectory, File.desktopDirectory 等.可以保存大的数据,如图片,视屏,和临时文件.访问这些文件的全选 ...
- 9个使用前必须再三小心的Linux命令
Linux shell/terminal 命令非常强大,即使一个简单的命令就可能导致文件夹.文件或者路径文件夹等被删除.在一些情况下,Linux 甚至不会询问你而直接执行命令,导致你丢失各种数据信 ...
- UNIX标准化及实现之基本系统数据类型
历史上,某些UNIX系统变量已与某些C数据类型联系在一起.例如,历史上主.次设备号一直存放在一个16位的短整型中,8位表示主设备号,另外8位表示次设备号.但是,很多较大的系统需要用多于256个值来表示 ...
- C#_delegate - combine function
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Dele ...
- Getting started: A skeleton application
Getting started: A skeleton application In order to build our application, we will start with theZen ...