spring boot+自定义 AOP 实现全局校验
最近公司重构项目,重构为最热的微服务框架 spring boot, 重构的时候遇到几个可以统一处理的问题,也是项目中经常遇到,列如:统一校验参数,统一捕获异常。。。
仅凭代码 去控制参数的校验,有时候是冗余的,但通过框架支持的 去控制参数的校验,是对于开发者很友好,先看下面的例子
- @NotEmpty(message="手机号不能为空")
- @Size(min=11,max=11,message="手机号码长度不正确")
- @Pattern(regexp=StringUtils.REGEXP_MOBILE,message="手机号格式不正确")
- private String mobile;
这是spring boot支持的 校验注解,然后我们在 contoller层 加上@Valid 注解 就可以达到校验的目的。这是一种框架自带的
本章 就展示一种 自定义的 AOP 校验,首先 写一个注解,注解里面可以写上 我们需要校验的规则, 比如长度,正则。。。
- @Documented
- @Target({ElementType.FIELD,ElementType.METHOD})
- @Retention(RetentionPolicy.RUNTIME)
- public @interface ValidateParam {
- int min() default 0;
- int max() default Integer.MAX_VALUE;
- String message() default "params is not null";
- String regexp();
- Class<?>[] groups() default { };
- Class<? extends Payload>[] payload() default { };
- boolean isNotNull() default true;
- }
然后定义一个AOP类
- package com.onecard.primecard.common.aop;
- import java.lang.reflect.Field;
- import java.lang.reflect.Method;
- import java.lang.reflect.ParameterizedType;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.regex.Pattern;
- import org.aspectj.lang.JoinPoint;
- import org.aspectj.lang.ProceedingJoinPoint;
- import org.aspectj.lang.annotation.Around;
- import org.aspectj.lang.annotation.Aspect;
- import org.aspectj.lang.annotation.Before;
- import org.aspectj.lang.annotation.Pointcut;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- import org.springframework.stereotype.Component;
- import com.jfcf.core.dto.ResultData;
- import com.onecard.core.support.util.StringUtils;
- import com.onecard.primecard.common.annotation.ValidateParam;
- import com.onecard.primecard.common.utils.ResultDataUtil;
- /**
- * 全局 切面类(校验参数)
- *
- * @author Administrator
- *
- */
- @Aspect
- @Component
- public class GobalHandlerAspect {
- private static Logger logger = LoggerFactory.getLogger(GobalHandlerAspect.class);
- @Pointcut("execution(* 包名.controller..*.*(..)) && execution(* 包名.controller..*.*(..))")
- public void checkAspect(){};
- @Before("checkAspect()")
- public void befor(JoinPoint joinPoint) throws Exception{
- //前置统一输出参数
- Object[] args = joinPoint.getArgs();
- if(args != null && args.length>0){
- Object obj = args[0];
- ParameterizedType pt = (ParameterizedType)obj.getClass().getGenericSuperclass();
- Class<?> classzz = (Class<?>) pt.getActualTypeArguments()[0];
- logger.info("【小X卡】-【请求实体入参】:"+classzz.newInstance().toString());
- }
- }
- @Around("checkAspect()")
- public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
- //校验参数
- Object[] args = joinPoint.getArgs();
- Object obj = null;
- if(args != null && args.length > 0){
- obj = args[0];
- Class classzz = obj.getClass();
- //没有顺序和秩序的数组
- Field[] fieldArray = classzz.getDeclaredFields();
- ArrayList<Field> fieldList = new ArrayList<Field>(Arrays.asList(fieldArray));
- String res = checkParam(fieldList,obj);
- if(StringUtils.isNotNull(res)){
- return ResultDataUtil.result(ResultData.STATUS_PARAM_ERROR, res);
- }
- }
- return joinPoint.proceed();
- }
- private String checkParam(ArrayList<Field> fieldList, Object obj) throws Exception {
- for(Field field : fieldList){
- ValidateParam validateParam = field.getAnnotation(ValidateParam.class);
- logger.info("【小X卡】获取注解值:"+validateParam.isNotNull()+"min="+validateParam.min()+"max="+validateParam.max());
- Method method = obj.getClass().getMethod("get"+getMethodName(field.getName()));
- logger.info("【小X卡】入参实体方法名称:"+method.getName());
- if(method != null){
- Object val = method.invoke(obj);
- logger.info("【小x卡】回调方法:"+val);
- if(validateParam != null && validateParam.isNotNull() == true){
- if(null == val || "".equals(val) ){
- return field.getName()+"必填参数为空";
- }
- }
- if(validateParam.min()==11 && validateParam.max() == 11){
- if(val.toString().length() != 11){
- return field.getName()+"请输入参数正确的长度";
- }
- }
- if(validateParam.regexp().equals(StringUtils.REGEXP_MOBILE)){
- if(!Pattern.matches(StringUtils.REGEXP_MOBILE, val.toString())){
- return field.getName()+"参数格式错误";
- }
- }
- }
- }
- return null;
- }
- /**
- * 方法首字母大写
- * @param fieldName
- * @return
- */
- private String getMethodName(String fieldName) {
- StringBuffer buffer = new StringBuffer();
- String firstLetter = fieldName.substring(0, 1).toUpperCase();
- return buffer.append(firstLetter).append(fieldName.substring(1, fieldName.length())).toString();
- }
- }
定义一个切点 @Pointcut, 用execution 表达式,去获取要校验的 某个类 和某个方法, 也就是连接点,然后 用定义一个通知,上面代码中有2个通知,一个前置通知@Before,一个环绕通知@Around,我们使用功能最强大的环绕通知。
通过上面的代码可以看出 首先获取参数,然后通过反射机制 获取 入参对象中的全部字段, 再去获取 我们在字段中加 我们自定义注解的字段,通过反射方法的回调,获取字段值,对值做判断, 返回校验结果。
spring boot+自定义 AOP 实现全局校验的更多相关文章
- Spring Boot 使用 Aop 实现日志全局拦截
前面的章节我们学习到 Spring Boot Log 日志使用教程 和 Spring Boot 异常处理与全局异常处理,本章我们结合 Aop 面向切面编程来实现全局拦截异常并记录日志. 在 Sprin ...
- 玩转Spring Boot 自定义配置、导入XML配置与外部化配置
玩转Spring Boot 自定义配置.导入XML配置与外部化配置 在这里我会全面介绍在Spring Boot里面如何自定义配置,更改Spring Boot默认的配置,以及介绍各配置的优先 ...
- Spring Boot 之:接口参数校验
Spring Boot 之:接口参数校验,学习资料 网址 SpringBoot(八) JSR-303 数据验证(写的比较好) https://qq343509740.gitee.io/2018/07/ ...
- Spring Boot 2 Webflux的全局异常处理
https://www.jianshu.com/p/6f631f3e00b9 本文首先将会回顾Spring 5之前的SpringMVC异常处理机制,然后主要讲解Spring Boot 2 Webflu ...
- 峰哥说技术:06-手撸Spring Boot自定义启动器,解密Spring Boot自动化配置原理
Spring Boot深度课程系列 峰哥说技术—2020庚子年重磅推出.战胜病毒.我们在行动 06 峰哥说技术:手撸Spring Boot自定义启动器,解密Spring Boot自动化配置原理 Sp ...
- Spring Boot使用AOP的正确姿势
一.为什么需要面向切面编程? 面向对象编程(OOP)的好处是显而易见的,缺点也同样明显.当需要为多个不具有继承关系的对象添加一个公共的方法的时候,例如日志记录.性能监控等,如果采用面向对象编程的方法, ...
- spring boot自定义线程池以及异步处理
spring boot自定义线程池以及异步处理@Async:什么是线程池?线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务.线程池线程都是后台线程.每个线程都使 ...
- Spring Boot自定义配置与加载
Spring Boot自定义配置与加载 application.properties主要用来配置数据库连接.日志相关配置等.除了这些配置内容之外,还可以自定义一些配置项,如: my.config.ms ...
- Spring Boot学习——AOP编程的简单实现
首先应该明白一点,AOP是一种编程范式,是一种程序设计思想,与具体的计算机编程语言无关,所以不止是Java,像.Net等其他编程语言也有AOP的实现方式.AOP的思想理念就是将通用逻辑从业务逻辑中分离 ...
随机推荐
- 严重:one or more listeners failed. Full details will be found in the appropriate container log file
one or more listeners failed. Full details will be found in the appropriate container log file 这句话 ...
- jmeter 之 beanshell sample
Lightweight Scripting for Java 官网:http://www.BeanShell.org/ 定时器: BeanShell Timer 前置处理器:BeanShell Pre ...
- Android studio 远程服务调用
https://blog.csdn.net/bond_zhe/article/details/50971021
- 冒泡排序(JAVA实现)
基本思想:在要排序的一组数中,对当前还未排好序的范围内的全部数,自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的往上冒. 即:每当两相邻的数比较后发现它们的排序与排序要求相反时,就将 ...
- httpappplication 和 httpmodule 的理解(转载,写的很好)
第一部分:转载自Artech IIS与ASP.NET管道 ASP.NET管道 以IIS 6.0为例,在工作进程w3wp.exe中,利用Aspnet_ispai.dll加载.NET运行时(如果.NET ...
- js某一元素在数组中的索引
第一种:数组遍历 function search(arr,dst){ var i = arr.length; while(i-=1){ if (arr[i] == dst){ return i; } ...
- 漫谈GUI开发—各种平台UI开发概况
前言: 在看这边文章前,可以建议看下:图形界面操作系统发展史——计算机界面发展历史回顾 从CS到BS,现在的前端开发,其实也是GUI开发范畴.现今 各平台的UI开发概况 HTML&CSS,Wi ...
- stm32 堆溢出
STM32 堆溢出 遇到的问题 最近在给旧项目添加了段代码,程序经常到某个状态就突然崩溃了,也不一定是在运行新代码的时候崩溃.检查了几遍代码,数组越界访问,除数为0,内存泄露等常见的问题都不存在. 原 ...
- Git使用和Vue项目
1.创建git排除文件,.gitignore 2.READEME.md 和 LICENSE开源协议 git init 创建仓库 , git status 查看文件状态 红色文件表示未提交. git ...
- tomcat+nginx实现
这里采用tomcat安装包 tomcat 版本说明: 9.0.17 nginx 版本说明: 1.14.2 jdk 版本说明: 1.8.0 创建目录 [root@web02 /]# m ...