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 ...
随机推荐
- C++学习笔记(十七):RTTI
这个知识点被遗漏了,可以结合之前的这篇文章看类型转换这个知识点. RTTI(Run-Time Type Information,运行时类型信息)即程序能够使用基类的指针或引用来检查这些指针或引用所指的 ...
- Css基础-介绍及语法
css 文件后缀.css 基础语法: selector { property:value } 例如: h1 {color:red;font-size:14px;} color:字体颜色 font-s ...
- js与java通信
js 调用java中的接口并传递参数给客户端处理方式: webView.addJavascriptInterface(new NewsDetail() , "newsDetail" ...
- const和readonly差别
我们都知道,const和static readonly的确非常像:通过类名而不是对象名进行訪问,在程序中仅仅读等等.在多数情况下能够混用.二者本质的差别在于,const的值是在编译期间确定的,因此仅仅 ...
- VK Cup 2015 - Finals, online mirror D. Restructuring Company 并查集
D. Restructuring Company Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/5 ...
- SqlServer按照指定顺序对字段进行排序
最近的一个项目,使用存储过程对报表进行分析,其中有一些名称需要根据指定顺序显示,而其名称对应的编号并不是按照要求的顺序排列的.通过上网查找资料,发现sql 中的charindex函数可以帮助解决这个问 ...
- IOS debug网络PonyDebugger 实践篇
引言: PonyDebugger是一个很给力的iOS调试工具,它的监视器安装在Chrome浏览器下做为插件使用,通过监视器和PonyDebugger的iOS SDK相辅相成,可以很好的监视App的运 ...
- Docker容器案例:应用 Mysql
原创 杜亦舒 前阶段体验 Mysql 的新版本 5.7.13,由于机器里已经有 Mysql了,再安装另一个版本会有一些麻烦,为了简单,便使用 Docker 容器来安装 可能有人会认为没必要,在一台 ...
- Supervised Learning-Regression
假设我们有一张房子属性及其价格之间的关系表(如下图所示) ,根据这些数据如何估计其他房子的价格?我们的第一个反应肯定是参考属性相似的房子的价格.在属性较少时这个方法还行得通,属性太复杂时就不那么简单了 ...
- js之createTextRange方法
createTextRange()方法作用: 主要是用来对一些文本对象进行操作.比如你有一大段文字,都在同一个P标签内,但是你只希望通过JS改变其中的一小部分,这时就可以用createTextRang ...