一、简介

  开发过程中我们往往需要写许多例如:

  @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通知打印控制器请求报文和返回报文的更多相关文章

  1. spring Boot使用AOP统一处理Web请求日志记录

    1.使用spring boot实现一个拦截器 1.引入依赖: <dependency>   <groupId>org.springframework.boot</grou ...

  2. spring boot使用AOP统一处理web请求

    为了保证服务的高可用,及时发现问题,迅速解决问题,为应用添加log是必不可少的. 但是随着项目的增大,方法增多,每个方法加单独加日志处理会有很多冗余 那在SpringBoot项目中如何统一的处理Web ...

  3. spring boot 中AOP的使用

    一.AOP统一处理请求日志 也谈AOP 1.AOP是一种编程范式 2.与语言无关,是一种程序设计思想 面向切面(AOP)Aspect Oriented Programming 面向对象(OOP)Obj ...

  4. Spring Boot 使用 Aop 实现日志全局拦截

    前面的章节我们学习到 Spring Boot Log 日志使用教程 和 Spring Boot 异常处理与全局异常处理,本章我们结合 Aop 面向切面编程来实现全局拦截异常并记录日志. 在 Sprin ...

  5. Spring Boot使用AOP的正确姿势

    一.为什么需要面向切面编程? 面向对象编程(OOP)的好处是显而易见的,缺点也同样明显.当需要为多个不具有继承关系的对象添加一个公共的方法的时候,例如日志记录.性能监控等,如果采用面向对象编程的方法, ...

  6. Spring Boot学习——AOP编程的简单实现

    首先应该明白一点,AOP是一种编程范式,是一种程序设计思想,与具体的计算机编程语言无关,所以不止是Java,像.Net等其他编程语言也有AOP的实现方式.AOP的思想理念就是将通用逻辑从业务逻辑中分离 ...

  7. spring boot使用AOP切面编程

    spring boot使用AOP 1.在pom文件中添加依赖: <!--spring boot aop切面--> <dependency> <groupId>org ...

  8. 【spring boot】spring boot中使用@RestController不起作用,不返回json,依旧去找访问接口的请求地址对应的页面

    问题描述: spring boot中使用@RestController不起作用,不返回json,依旧去找访问接口的请求地址对应的页面 表现结果: 1>使用postman测试接口,表现为返回是40 ...

  9. Spring Boot全局支持CORS(跨源请求)

    import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet. ...

随机推荐

  1. 部署在eclipse上的Tomcat上的publish和clean的区别

    publish:就是把自己的web应用发布到tomcat服务器上没这样才能通过浏览器查看浏览 clean: 就是先清除掉原先编译到tomcat上的程序(多个.class文件),之后再发布. 如:我建了 ...

  2. 笔记:Spring Cloud Feign Hystrix 配置

    在 Spring Cloud Feign 中,除了引入了用户客户端负载均衡的 Spring Cloud Ribbon 之外,还引入了服务保护与容错的工具 Hystrix,默认情况下,Spring Cl ...

  3. NumPy入门

    import numpy as np 数组与标量之间的运算作用于数组的每一个元素.

  4. 使用Mifare卡加密数据 笔记

    Mifare 是最常用的射频卡,具体介绍网上太多,我就不说了.,很多城市的最早的地铁公交卡都是用这种卡,后来被破解后都换成智能卡了. 但是由于技术成熟,使用方便,成本低,现在很多小区门禁卡,停车卡,食 ...

  5. poj1183 反正切函数

    poj1183 反正切函数 第一道poj的题更博,类似于博主这种英文水平,也就切一切这种中文题了吧! 题目大意:给你正整数a,求满足条件的 b 和 c,使得 $\frac {1}{a}=\frac { ...

  6. 在VS2017下配置OpenGL

    这个方法适合初学者使用,较为简单方便. 第一,你的VS2017一定要安装了C/C++开发组件 可以打开Visual Studio Installer来查看 另外,确定你有安装NuGet包管理器,在单个 ...

  7. 201621123060《JAVA程序设计》第十三周学习总结

    1. 本周学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. 2. 为你的系统增加网络功能(购物车.图书馆管理.斗地主等)-分组完成 为了让你的系统可以被多个用户通过网 ...

  8. 结合Socket实现DDoS攻击

    一.实验说明 1. 实验介绍 通过上一节实验的SYN泛洪攻击结合Socket实现DDoS攻击. 2. 开发环境 Ubuntu Linux Python 3.x版本 3. 知识点 本次实验将涉及以下知识 ...

  9. python 实现cm批量上传

    import requests import json import time import random url = 'http://cm.admin.xxxx.com/customer/aj_ad ...

  10. 2017-2018-1 我爱学Java 第一周 作业

    构建之法 成员及分工 内容简介 作者简介 分章学习及问题 第一章 概论 第二章 个人技术和流程 第三章 软件工程师的成长 第四章 两人合作 第五章 团队和流程 第六章 敏捷流程 第七章 实战中的软件工 ...