javax.validation.Validator基础知识补充:
validator用来校验注解的生效,如:
@NotBlank(message = "地址名不能为空")
private String addressName;
当addressName这个值为null时,会报message = "地址名不能为空"的值:
简单demo:
//对Location对象进行校验
ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
Validator validator = validatorFactory.getValidator();
//因为:Location可能有很多字段都需要校验,所以校验后返回的信息是一个集合
Set<ConstraintViolation<Location>> sets = validator.validate(location);
//校验不通过的信息都存到了set集合中,从中可以拿到校验不通过的信息
if(null!=sets && sets.size()>1){
for (ConstraintViolation<Location> set : sets) {
String message = set.getMessage();//注解的message信息
System.out.println(message);
}
}
//所有的校验注解在javax.validation.constraints这个包下 如包下的NotNull注解,源码如下:
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(NotNull.List.class)
@Documented
@Constraint(
validatedBy = {}
)
public @interface NotNull {
String message() default "{javax.validation.constraints.NotNull.message}"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; @Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface List {
NotNull[] value();
}
}
//所以,我们也可以自定义注解 //例如:我们的接口只对VIP为白银的用户可用,自定义注解如下
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(
validatedBy = {CheckVIPValidator.class} //注解要生效,就要有一个类的方法让它生效
)
public @interface ViP { String message() default "只有白银用户才能使用"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; String value(); }
//使注解生效的类:
public class CheckVIPValidator implements ConstraintValidator<ViP, String> {
private String vip=null;
@Override
public void initialize(ViP constraintAnnotation) {
vip=constraintAnnotation.value();
} @Override
public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
if(s.equals(vip)){
return true;
}
return false;
}
} //下面是APO结合validator技术,本项目是基于springboot的一个简单项目,spring项目也可以: 先看项目结构:

各对象的数据:

自定义注解和其实现类:
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(
validatedBy = {CheckVIPValidator.class} //注解要生效,就要有一个类的方法让它生效
)
public @interface ViP { String message() default "只有白银用户才能使用"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; String value(); }
public class CheckVIPValidator implements ConstraintValidator<ViP, String> {
private String vip=null;
@Override
public void initialize(ViP constraintAnnotation) {
vip=constraintAnnotation.value();
} @Override
public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
if(s.equals(vip)){
return true;
}
return false;
}
}
//接口 @Controller
public class ValidatorController { @RequestMapping(value = "check/validator",method = RequestMethod.POST)
@ResponseBody
public CommonResponseDTO checkValidator(@RequestBody User user) throws Exception {
CommonResponseDTO beeboxCommonResponseDTO = new CommonResponseDTO();
return beeboxCommonResponseDTO;
}
} //请求对象:
public class User {
@NotNull(message = "名字不能为空")
private String name;
@ViP(value ="白银",message ="只有白银用户才能访问")
private String vip;
@Min(value = 18,message = "年龄需要大于18岁")
  @NotNull(message="年龄不能为空")
private Integer age; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getVip() {
return vip;
} public void setVip(String vip) {
this.vip = vip;
}
}
//返回对象:
public class CommonResponseDTO {
private String code;
private String desc; public String getCode() {
return code;
} public void setCode(String code) {
this.code = code;
} public String getDesc() {
return desc;
} public void setDesc(String desc) {
this.desc = desc;
}
}
//最重要的对象: 切面类:
package com.example.demo.aop; import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils; import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Set; /**
* 场景:使用AOP技术对接口(controller下的方法参数进行校验,对贴有校验注解如@NotNull @Min等做校验,不通过的话,就返回对应错误码和描述)
* 按照项目规范:请求参数只能是一个值,返回参数必须含有一个错误码字段和一个错误码描述字段
*
*
*
*
*/ @Component
@Aspect
@Order(1) //当有多个切面时,加上这个顺序,就可以控制前后顺序了
public class AOPAspect { /**
* //配置切入点,该方法无方法体,主要为方便同类中其他方法使用此处配置的切入点 * com.sample.service.impl..*.*(..)
* 整个表达式可以分为五个部分:
* 1、execution(): 表达式主体。
* 2、第一个*号:表示返回类型,*号表示所有的类型。
* 3、包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.sample.service.impl包、子孙包下所有类的方法。
* 4、第二个*号:表示类名,*号表示所有的类。
* 5、*(..):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数。
*/ @Pointcut("execution(* com.example.demo.controller.*.*(..))")
public void declareJoinPointerExpression() {} /**
* ProceedingJoinPoint 是 JoinPoint的子接口,有2个方法
* Object proceed() throws Throwable //执行目标方法
Object proceed(Object[] var1) throws Throwable //传入的新的参数去执行目标方法
*
* JoinPoint的几个参数:
* Signature getSignature(); //封装了方法相关的信息
* signature.getDeclaringType();//方法所在的字节码对象
* signature.getDeclaringTypeName(); 方法所在的类名(包.类这种形式)
* signature.getModifiers();//获取方法的修饰符的数字表示,如public修饰符返回1,private...
* signature.getName();//获取方法的名称
* //Signature的实现类是MethodSignature 可以获得方法的相关数据,如参数,返回值类型,方法等
* MethodSignature signature = (MethodSignature)joinPoint.getSignature();
Method method = signature.getMethod();//获取方法
Class returnType = signature.getReturnType();//获取返回值的类型
*joinPoint.getArgs();//获取方法的参数
*
* joinPoint.getKind();//返回的是JoinPoint对象里面的常量,如method-execution(方法的执行)
* joinPoint.getStaticPart();//获取的是JoinPoint里面的一个内部接口
* joinPoint.getTarget(); //获取被代理对象
* joinPoint.getThis(); //获取的是代理对象
*
* @param joinPoint
*/
@Before("declareJoinPointerExpression()")
public void beforeMethod(JoinPoint joinPoint){
System.out.println("增强前");
joinPoint.getThis(); }
@After("declareJoinPointerExpression()")
public void AferMethod(JoinPoint joinPoint){
System.out.println("增强后...");
}
//本次校验的场景是contorller的方法只有一个参数,并且放回值都有状态和描述2个字段
@Around("declareJoinPointerExpression()")
public Object aroundMethod(JoinPoint joinPoint) throws Throwable {
MethodSignature signature = (MethodSignature)joinPoint.getSignature(); //通过该对象可以获取方法返回值
Class returnType = signature.getReturnType();//方法返回类型
Object[] args = joinPoint.getArgs(); //本次实验只能有一个请求参数
if(null==args || args.length!=1){
return getReturnObject(returnType, "400", "参数数目不对");
}
Object arg = args[0];//获取请求参数
ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
Validator validator = validatorFactory.getValidator();
Set<ConstraintViolation> violations = validate(validator, arg);//校验参数,异常会封装到set集合
StringBuilder sb = new StringBuilder();//拼接异常数据
if(null!=violations || violations.size()>1){
sb.append("基础数据校验不通过:");
for (ConstraintViolation set : violations) {
String message = set.getMessage(); //异常数据信息
sb.append(message).append("</br>");
}
return getReturnObject(returnType,"400",sb.toString()); }else { ProceedingJoinPoint pjp= (ProceedingJoinPoint) joinPoint; //如果没有异常数据,就执行原来的方法
Object proceed = pjp.proceed();//执行原来方法
return proceed;
} } private Set<ConstraintViolation> validate(Validator validator,Object object,Class ... groups){
Set constraintViolations = validator.validate(object, groups);//校验不通过的数据会封装到set集合
return constraintViolations;
} /**
*
* @param clz 方法返回值的字节码对象
* @param errorCode 错误码
* @param errorMessage 错误信息
* @param <T> 返回值类型
* @return
*/
private <T> T getReturnObject(Class<T> clz,String errorCode,String errorMessage) {
if(clz.getName().equals("void")){ //没有返回值时
return null;
}
T t = null;
try {
t = clz.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
setFiledValue("code",errorCode,t); //设置错误码
setFiledValue("desc",errorMessage,t); //设置错误信息
return t; } /**
* 调用setXX方法设置属性
* @param fileName
* @param value
* @param obj
*/
private void setFiledValue(String fileName,Object value,Object obj) {
//该方式找不到对应字段不会报错
if(StringUtils.isEmpty(fileName)){
return;
}
//转成SetXXX方法名
char[] chars = fileName.toCharArray();
chars[0]=(char) (chars[0]-32); //首字母转大写
//拼接成方法名
String methodName="set"+String.copyValueOf(chars);
Class<?> clz = obj.getClass();
Method[] declaredMethods = clz.getDeclaredMethods();
for (Method method : declaredMethods) {
String name = method.getName();
boolean equals = method.getName().equals(methodName);
if(equals){
try {
method.invoke(obj,value);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} } } }

//接口调用后结果如下:

使用AOP和Validator技术对项目接口中的参数进行非空等校验的更多相关文章

  1. vue项目获取当前地址栏参数(非路由传参)

    项目中遇到一个需求,就是另一个管理系统带参直接单纯的跳转跳转到vue pc项目中的某个页面,后再初始化查询数据,参数以地址栏的形式传入 管理系统:打开新地址地址 let obj = { id: 21, ...

  2. [技术学习]js接口继承

    js是面向对象语言,但是js又缺乏了面向对象的诸多特性,比如继承,没有接口继承也没有父类继承,因此有时候需要人工来实现继承. 一.首先看下java中面向对象的继承: //定义类鸟类的飞行动作 inte ...

  3. 接口中定义变量必须为public static final的原因

    在interface里面的变量默认都是public static final 的,原因如下: 1.   接口是一种高度抽象的"模版",,而接口中的属性也就是’模版’的成员,就应当是 ...

  4. mybatis 接口中定义方法、映射文件、实体类之间的关系?

    一.定义实体类 ,注意需求 是一对多还是多对一.  这里用员工和部门  多对一的关系举例. package com.zs.entity; /* * /* * 多对一? * 多个员工 对应一个部门 一个 ...

  5. java中为什么接口中的属性都默认为static和final?

    1)为什么接口中的属性都默认为static和final?Sun公司当初为什么要把java的接口设计发明成这样?[新手可忽略不影响继续学习]答:马克-to-win:接口中如果可能定义非final的变量的 ...

  6. AOP在大规模软件开发项目中的应用(图)

    AOP在大规模软件开发项目中的应用(图) 本文的写作源于一个真实的大型软件开发项目,我们努力尝试在这个项目中推广应用AOP.在此我们将对曾经面临过的一些实际问题与困难进行分析,试图引发关于面向方面软件 ...

  7. 利用Microsoft.Practices.Unity的拦截技术,实现.NET中的AOP

    1.记住这个单词的意思:Interception(拦截) 2.首先说一下原理和背景 原理:所谓的AOP就是面向切面编程,这里不多说,百度搜索. 目的:个人认为是为了解耦,部分代码跟业务代码分离,业务代 ...

  8. vue项目webpack中Npm传递参数配置不同域名接口

    项目开发中,前端在配置后端api域名时很困扰,常常出现:本地开发环境: api-dev.demo.com测试环境: api-test.demo.com线上生产环境: api.demo.com, 这次是 ...

  9. 在vue-cli搭建的项目中在后台mock接口中支持req.body和req.cookies

    在<vue-cli搭建的项目中增加后台mock接口>中实现了后台mock,但是前端post的t数据都要在mock的后台接口中使用req的接收数据事件获取http协议body中的数据. re ...

随机推荐

  1. IDEA下Maven项目搭建踩坑记----1.pom,xml文件下${spring-version}不能用

    因为pom.xml文件是直接复制别人配好的web环境,所以在粘贴进去的之后有一部分没有粘贴到,因此出现爆红 解决方法:↓↓↓↓ 代码: <project.build.sourceEncoding ...

  2. Java面试题(多线程篇)

    多线程 35.并行和并发有什么区别? 1.并行是指两个或者多个事件在同一时刻发生:而并发是指两个或多个事件在同一时间间隔发生. 2.并行是在不同实体上的多个事件,并发是在同一实体上的多个事件. 3.在 ...

  3. JS获取时间(当前-过去-未来)

    /** * 获取时间格式为:1970-01-01 00:00 * @param {参数} params * 属性 类型 默认值 必填 说明 * date Date new Date() 否 Date对 ...

  4. 做seo如何选择一个好的标题

    http://www.wocaoseo.com/thread-86-1-1.html 我们常说人要红妆马配鞍,那么对于seo来说,网站的标题也是很重要的,如何写好标题呢?只要注意以下几点就行了. 首先 ...

  5. 都2020年了,还再问GET和POST的区别?【深度好文】

    最近看了一些同学的面经,发现无论什么技术岗位,还是会问到 get 和 post 的区别,而搜索出来的答案并不能让我们装得一手好逼,那就让我们从 HTTP 报文的角度来撸一波,从而搞明白他们的区别. 一 ...

  6. 使用 Visual Studio 2019 批量添加代码文件头

    应用场景介绍 在我们使用一些开源项目时,基本上都会在每个源代码文件的头部看到一段版权声明.一个项目或解决方案中源代码文件的个数少则几十,多则几千甚至更多,那么怎么才能给这么多文件方便地批量添加或者修改 ...

  7. Python爬虫实战点触验证码, 模拟登陆bilibili

    爬虫思路如下: 利用自动化爬虫工具 Selenium 模拟点击输入等操作来进行登录 分析页面,获取点触验证码的点触图片,通过将图片发送给超级鹰打码平台识别后获取坐标信息 根据超级鹰返回的数据,模拟坐标 ...

  8. Android项目智能机器人的实现,带有源代码,图灵智能机器人,详细讲解。。

    大家好,今天给大家推荐一个我利用图灵api制作的android项目,智能机器人,类似智能小冰,等一些会机器人. 下面看效果.女头像是系统自动给你回复的,男头像是你输入的内容.项目源代码是eclipse ...

  9. 02.Flink的单机wordcount、集群安装

    一.单机安装 1.准备安装包 将源码编译出的安装包拷贝出来(编译请参照上一篇01.Flink笔记-编译.部署)或者在Flink官网下载bin包 2.配置 前置:jdk1.8+ 修改配置文件flink- ...

  10. vue项目打包上线发现 360 浏览器不兼容?

    分享链接: 文档:解决vue 和 360 浏览器兼容问题.note链接:http://note.youdao.com/noteshare?id=41914c6dbb4238d765b26d59aa05 ...