一、简介

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

  @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. Python基本知识

    python是一门编程语言,这是我们学习python首先要了解的内容,那么编程语言又是什么,我们为什么需要编程语言 我们讲的话是汉语,英语或者其他语言,计算机也可以讲话,但是他只会说0,1,也只能看懂 ...

  2. bat脚本:Java一键编译(Javac java)

    bat脚本:Java一键编译(Javac java) D:    是指D盘 javat是要编译的.java文件所在的文件夹 也就是D:\javat bat代码: :start COLOR 0A cls ...

  3. Http最常见的错误代码

    1XX 表示消息 2XX 表示成功 3XX 表示重定向 4XX 表示请求错误 5XX 表示服务器端错误 我们最常见的就是: 404(页面找不到),这个错误代码是由于我们输入的网址不对造成的,浏览器找不 ...

  4. ListIterator

    1,ListIterator与Iterator Iterator的功能:next(),hasNext(),remove() 功能太少,因此出现了ListIterator,他的功能要比Iterator多 ...

  5. 走进webpack(1)--环境拆分及模块化

    初级的文章和demo已经基本完成了,代码也已经上传到了我的github上,如果你对webpack的使用并不是十分了解,那么建议你回头看下走近系列,里面包括了当前项目中使用频繁的插件,loader的讲解 ...

  6. 大数据 --> 分布式服务框架Zookeeper

    分布式服务框架 Zookeeper Zookeeper系列 分布式服务框架 Zookeeper -- 管理分布式环境中的数据

  7. c++ --> static关键字总结

    static关键字总结 C++的static有两种用法:面向过程程序设计中的static和面向对象程序设计中的static.前者应用于普通变量和函数,不涉及类:后者主要说明static在类中的作用. ...

  8. Eclipse中的所有快捷键列表

    Eclipse中的所有快捷键列表: Ctrl+1 快速修复(最经典的快捷键,就不用多说了) Ctrl+D: 删除当前行 Ctrl+Alt+↓ 复制当前行到下一行(复制增加) Ctrl+Alt+↑ 复制 ...

  9. java开源安全框架-------Apache Shiro--第二天

    身份验证 即在应用中谁能证明他就是他本人.一般提供如他们的身份ID一些标志信息来表明他就是他本人,如提供身份证.用户名.密码来证明 在shiro中,用户需要提供principals(身份)和crede ...

  10. Mybatis学习笔记一

    Mybatis介绍 MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为M ...