spring-boot 使用Aop通知打印控制器请求报文和返回报文
一、简介
开发过程中我们往往需要写许多例如:
@GetMapping("/id/get")
public Result getById( String id) throws Exception{
log.info("请求参数为:"+id);
verify(new VerifyParam("部门id", id));
Result result = new Result("通过id获取部门信息成功!", service.queryById(id));
log.info("返回报文为:"+result.toString());
return result;
}
打印请求参数以及返回参数的方法,而这些操作存在于每个方法之中,使得我们代码较为冗余,为此我们可以通过动态代理将打印参数和打印返回报文作为切面,使用切入点表达式将其切入至每个方法之中。
二、步骤
1、引入Aop相关的依赖:
<!--AOP相关的依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
引入依赖后spring-aop会加载其需要的依赖,spring默认使用aspectJ实现通知

其中aspectjweaver.jar中包含了解析aspectJ切入点表达式的文件,使用切入点表达式处理事务的时候也需要加入此依赖。
2、配置:
1)、创建配置类:
/**
* @功能描述:用于controller层操作的AOP类
* @author Administrator
*/
@Component // 将对象交由spring进行管理
@Aspect // 代表此类为一个切面类
public class ControllerAop { }
其中@Aspect 注解代表其为一个切面管理类,可以在其下定义切入点表达式,aspectJ框架会进行解析。
2)、定义切入点表达式:
@Pointcut("execution(public * com.hzt.manage.*.web.controller..*.*(..))") // 切入点表达式
public void privilege() {
}
其中,@Pointcut代表此方法为一个切入点表达式。其value值为切入点表达式,其中value可以省略其大致格式为:
@注解(表达标签+表达式格式)
的格式,Spring AOP支持的AspectJ切入点指示符如下:
1、 execution:用于匹配方法执行的连接点;
2、within:用于匹配指定类型内的方法执行;
3、this:用于匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能包括引入接口也类型匹配;
4、target:用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配;
5、args:用于匹配当前执行的方法传入的参数为指定类型的执行方法;
6、@within:用于匹配所以持有指定注解类型内的方法;
7、@target:用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解;
8、@args:用于匹配当前执行的方法传入的参数持有指定注解的执行;
9、@annotation:用于匹配当前执行方法持有指定注解的方法;
10、bean:Spring AOP扩展的,AspectJ没有对于指示符,用于匹配特定名称的Bean对象的执行方法;
11、reference pointcut:表示引用其他命名切入点,只有@ApectJ风格支持,Schema风格不支持。
args中定义了切入点表达式方法执行时候的参数:
@Pointcut(value="execution(public * com.hzt.manage.*.web.controller..*.*(..))&&args(param)",argNames="param") // 切入点表达式
public void privilege1(String param) {
}
我们重点介绍execution方法连接点的表达式,其大概结构为:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)
1、修饰符匹配(modifier-pattern?)(可省略)
2、返回值匹配(ret-type-pattern)可以为*表示任何返回值 ,如 (String) 代表只筛选返回String类型的切入点 ,全路径的类名等(不可省略)
3、类路径匹配(declaring-type-pattern?)如*.manage代表一级包为任意,二级包为manage的名称。*..manage代表所有manage包下的子类包。com..*.comtroller代表com包下所有的controller包等,*代表所有包都匹配。(不可省略)
4、方法名匹配(name-pattern)可以指定方法名 或者 *代表所有, get* 代表以get开头的所有方法,也可指定前缀*get代表任意后缀为get的方法(不可省略)
5、参数匹配((param-pattern))可以指定具体的参数类型,多个参数间用“,”隔开,各个参数也可以用“*”来表示匹配任意类型的参数,如(String)表示匹配一个String参数的方法;(*,String) 表示匹配有两个参数的方法,第一个参数可以是任意类型,而第二个参数是String类型;可以用(..)表示任意参数(不可省略)
6、异常类型匹配(throws-pattern?)
3、定义切面方法
@Around("privilege()")
public Object around(ProceedingJoinPoint pjd) throws Throwable {
// 获取方法名
String className = pjd.getSignature().getClass().getName();
// 获取执行的方法名称
String methodName = pjd.getSignature().getName();
/** 初始化日志打印 */
Logger log = LoggerFactory.getLogger(className);
// 定义返回参数
Object result = null;
// 记录开始时间
long start = System.currentTimeMillis();
// 获取方法参数
Object[] args = pjd.getArgs();
String params = "前端请求参数为:";
//获取请求参数集合并进行遍历拼接
for (Object object : args) {
params += object.toString() + ",";
}
params = params.substring(0, params.length() - 1);
//打印请求参数参数
log.info(className+"类的"+methodName + "的" + params);
// 执行目标方法
result = pjd.proceed();
// 打印返回报文
log.info("方法返回报文为:" + (result instanceof Result ? (Result) result : result));
// 获取执行完的时间
log.info(methodName + "方法执行时长为:" + (System.currentTimeMillis() - start));
return result;
}
5、@Around 环绕通知,如上代码所示便是环绕通知,其有ProceedingJoinPoint参数
其中 pjd.proceed();方法代表去执行目标方法,并获得一个Object类型的返回值,我们可以对返回值进行加工处理,如装饰加工等。
return的值为方法执行的结果。上述代码中首先获取类名、方法名、方法请求参数等,进行打印的拼接,并且记录方法执行的开始时间,并进行打印至日志。
然后执行方法,获取到方法返回结果,进行打印执行时间和执行结果。
最后返回执行结果。即使用Aop打印请求报文和返回报文的aop切面编码结束。
其中@Around代表其为一个环绕通知方法,其有以下几种类型:
1、@Before前置通知,拥有请求参数 JoinPoint ,用来连接当前连接点的连接细节,一般包括方法名和参数值。在方法执行前进行执行方法体,不能改变方法参数,也不能改变方法执行结果。
@Before(value = "privilege()")
public void before(JoinPoint joinPoint) { }
2、@After 后置通知:在目标方法执行之后,无论是否发生异常,都进行执行的通知。在后置通知中,不能访问目标方法的执行结果(因为有可能发生异常),不能改变方法执行结果。
@Before(value = "privilege()")
public void after(JoinPoint joinPoint) { }
3、@AfterReturning 返回通知,在目标方法执行结束时,才执行的通知,同后置方法相同。其能访问方法执行结果(因为正常执行)和方法的连接细节,但是不能改变方法执行结果。
@AfterReturning(value = "privilege()")
public void afterReturing(JoinPoint joinPoint,Object result) { }
result中存放的为方法的返回值。
4、@AfterThrowing 异常通知:在目标方法出现异常时才会进行执行的代码。 throwing属性代表方法体执行时候抛出的异常,其值一定与方法中Exception的值需要一致。
@AfterThrowing(value="privilege()",throwing="ex")
public void exce(JoinPoint joinPoint, Exception ex) { }
三、测试
编写一个Controller方法
@RestController
@RequestMapping("/api/v1/dept")
public class DeptController extends BaseController{
/** 日志记录类 */
private Logger log = LoggerFactory.getLogger(getClass());
/** 自家的service */
@Autowired
private DeptService service; /**
* @功能描述:根据id查询部门内容的方法
* @return Dept
*/
@GetMapping("/id/get")
public Result getById( String id) throws Exception{
verify(new VerifyParam("部门id", id));
return new Result("通过id获取部门信息成功!", service.queryById(id));
}
}
如此我们的controller层中的方法就大大的简洁了。
测试结果:
2018-04-10 22:59:27.468 INFO 1460 --- [nio-8088-exec-5] nProceedingJoinPoint$MethodSignatureImpl : getById的前端请求参数为:22
2018-04-10 22:59:27.470 INFO 1460 --- [nio-8088-exec-5] nProceedingJoinPoint$MethodSignatureImpl : 方法返回报文为:Result [result_code=suc, result_message=通过id获取部门信息成功!, data=Dept [id=22, no=22, name=22, manager=22, description=22, phone=22, createTime=Thu Apr 19 23:38:37 CST 2018, editTime=null]]
2018-04-10 22:59:27.470 INFO 1460 --- [nio-8088-exec-5] nProceedingJoinPoint$MethodSignatureImpl : getById方法执行时长为:2
如此便能很雅观简洁隐式的打印请求参数、返回结果和执行时间等!
spring-boot 使用Aop通知打印控制器请求报文和返回报文的更多相关文章
- spring Boot使用AOP统一处理Web请求日志记录
1.使用spring boot实现一个拦截器 1.引入依赖: <dependency> <groupId>org.springframework.boot</grou ...
- spring boot使用AOP统一处理web请求
为了保证服务的高可用,及时发现问题,迅速解决问题,为应用添加log是必不可少的. 但是随着项目的增大,方法增多,每个方法加单独加日志处理会有很多冗余 那在SpringBoot项目中如何统一的处理Web ...
- spring boot 中AOP的使用
一.AOP统一处理请求日志 也谈AOP 1.AOP是一种编程范式 2.与语言无关,是一种程序设计思想 面向切面(AOP)Aspect Oriented Programming 面向对象(OOP)Obj ...
- Spring Boot 使用 Aop 实现日志全局拦截
前面的章节我们学习到 Spring Boot Log 日志使用教程 和 Spring Boot 异常处理与全局异常处理,本章我们结合 Aop 面向切面编程来实现全局拦截异常并记录日志. 在 Sprin ...
- Spring Boot使用AOP的正确姿势
一.为什么需要面向切面编程? 面向对象编程(OOP)的好处是显而易见的,缺点也同样明显.当需要为多个不具有继承关系的对象添加一个公共的方法的时候,例如日志记录.性能监控等,如果采用面向对象编程的方法, ...
- Spring Boot学习——AOP编程的简单实现
首先应该明白一点,AOP是一种编程范式,是一种程序设计思想,与具体的计算机编程语言无关,所以不止是Java,像.Net等其他编程语言也有AOP的实现方式.AOP的思想理念就是将通用逻辑从业务逻辑中分离 ...
- spring boot使用AOP切面编程
spring boot使用AOP 1.在pom文件中添加依赖: <!--spring boot aop切面--> <dependency> <groupId>org ...
- 【spring boot】spring boot中使用@RestController不起作用,不返回json,依旧去找访问接口的请求地址对应的页面
问题描述: spring boot中使用@RestController不起作用,不返回json,依旧去找访问接口的请求地址对应的页面 表现结果: 1>使用postman测试接口,表现为返回是40 ...
- Spring Boot全局支持CORS(跨源请求)
import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet. ...
随机推荐
- Maven 手动添加selenium JAR 包到本地仓库
安装Maven后我们会在用户目录下发现.m2 文件夹.默认情况下,该文件夹下放置了Maven本地仓库.m2/repository. 在intellij中创建maven项目时,添加 selenium 依 ...
- js获取元素的滚动高度,和距离顶部的高度
jq: 获取浏览器显示区域(可视区域)的高度 : $(window).height(); 获取浏览器显示区域(可视区域)的宽度 : $(window).width(); 获取页面的文档高度 $(doc ...
- 防反编译的加壳工具-Virbox Protector
通过Virbox Protector可快速对您的软件进行加壳,可防调试,防挂钩,防反编译. 首先,你要有一个云平台(www.sense.com.cn)的帐号,登录后,只需将你的dll或者exe拖入到加 ...
- 笔记:Struts2 Action 非泛型集合元素类型转换
局部类型转换文件 局部类型转换文件的文件名应为 ActionName-conversion.properties,其中 ActionName 是需要替换为 Action 的类名称,后面的 conver ...
- 详解Tomcat线程池原理及参数释义
omcat线程池有如下参数: maxThreads, 最大线程数,tomcat能创建来处理请求的最大线程数 maxSpareTHreads, 最大空闲线程数,在最大空闲时间内活跃过,但现在处于空闲,若 ...
- 网络通信 --> Socket、TCP/IP、HTTP、FTP及网络编程
Socket.TCP/IP.HTTP.FTP及网络编程 聊聊Socket.TCP/IP.HTTP.FTP及网络编程
- 源码实现 --> itoa函数实现
itoa函数实现 itoa()函数的功能是将一个整数转换为一个字符串 例如12345,转换之后的字符串为"12345",-123转换之后为"-123",欢迎大家 ...
- 敏捷冲刺(Beta版本)
评分基准: 按时交 - 有分(计划安排-10分,敏捷冲刺-70分),检查的项目包括后文的三个个方面 冲刺计划安排(单独1篇博客,基本分5分,根据完成质量加分,原则上不超过满分10分) 七天的敏捷冲刺( ...
- Beta冲刺第七天
一.昨天的困难 没有困难. 二.今天进度 1.林洋洋:MD图片上传,修复权限问题,修复本地存储判空问题,修复协作申请没有过滤问题. 2.黄腾达:添加文件链接和邀请链接复制功能,协作树界面优化. 3.张 ...
- 201621123057 《Java程序设计》第13周学习总结
1. 本周学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. 2. 为你的系统增加网络功能(购物车.图书馆管理.斗地主等)-分组完成 为了让你的系统可以被多个用户通过网 ...