springboot+aop切点记录请求和响应信息
本篇主要分享的是springboot中结合aop方式来记录请求参数和响应的数据信息;这里主要讲解两种切入点方式,一种方法切入,一种注解切入;
首先创建个springboot测试工程并通过maven添加如下依赖:
<!-- AOP -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!--阿里 FastJson依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.44</version>
</dependency>
先来说方法的切点方式,需要创建个名为LogAspect的组件类,然后用@Aspect注解修饰组件类,再通过设置方法切入点方式做公共日志记录,如下创建切入点:
//切点入口 Controller包下面所有类的所有方法
private final String pointcut = "execution(* com.platform.Controller..*(..))";
//切点
@Pointcut(value = pointcut)
public void log() {
}
这里的execution( com.platform.Controller..(..))主要的意思是:切入点入口是Controller包下面所有类的所有方法;
再来通过@Around环绕注解方法里面做请求参数和响应信息的记录,如下代码:
@Around(value = "log()")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Object result = null;
StringBuilder sbLog = new StringBuilder("\n");
try {
sbLog.append(String.format("类名:%s\r\n", proceedingJoinPoint.getTarget().getClass().getName()));
MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
sbLog.append(String.format("方法:%s\r\n", methodSignature.getMethod().getName()));
Object[] args = proceedingJoinPoint.getArgs();
for (Object o : args) {
sbLog.append(String.format("参数:%s\r\n", JSON.toJSON(o)));
}
long startTime = System.currentTimeMillis();
result = proceedingJoinPoint.proceed();
long endTime = System.currentTimeMillis();
sbLog.append(String.format("返回:%s\r\n", JSON.toJSON(result)));
sbLog.append(String.format("耗时:%ss", endTime - startTime));
} catch (Exception ex) {
sbLog.append(String.format("异常:%s", ex.getMessage()));
} finally {
logger.info(sbLog.toString());
}
return result;
}
此刻主要代码就完成了,再来我们配置下日志的记录方式;
首先在 resources目录增加名为logback-spring.xml的文件,其配置信息如:
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Author:shenniu003
~ Copyright (c) 2018.
-->
<configuration debug="false" scan="true" scanPeriod="1 seconds">
<springProperty scope="context" name="appname" source="logging.logback.appname"/>
<springProperty scope="context" name="logLevel" source="logging.logback.level"/>
<springProperty scope="context" name="logPath" source="logging.logback.path"/>
<property name="logPathAll" value="${logPath}/${appname}.log"/>
<contextName>logback</contextName>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<!-- <filter class="ch.qos.logback.classic.filter.ThresholdFilter" >
<level>WARN</level>
</filter>-->
<encoder>
<pattern>%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logPathAll}</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${logPathAll}.%d{yyyy-MM-dd}.zip</fileNamePattern>
</rollingPolicy>
<encoder>
<pattern>%date %level [%thread] %logger{36} [%file : %line] %msg%n
</pattern>
</encoder>
</appender>
<root level="${logLevel}">
<appender-ref ref="console"/>
<appender-ref ref="file"/>
</root>
</configuration>
然后application.yml的配置信息如:
logging:
config: classpath:logback-spring.xml
logback:
level: info #info ,debug
path: /home/app/data/applogs/weblog
appname: web
此刻日志和公共的aop记录类都完成了,我们需要创建个测试用例,其代码如:
@PostMapping("/addUser")
public ResponseEntity<MoStudent> addUser(@RequestBody MoStudent moStudent) throws Exception {
moStudent.setNumber(UUID.randomUUID().toString());
// throw new Exception("错误了");
return new ResponseEntity<>(moStudent, HttpStatus.OK);
}
最后,通过postman模拟post请求,能够得到如下的日志结果:
上面的方式切入点是所有方法,所有方法都记录日志可能有是不是需求想要的,此时可以通过注解的方式来标记想记录日志的方法;
先来创建个日志注解:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogAnnotation {
/**
* 描述
*
* @return
*/
String des() default "";
}
同样再来创建注解的切入点:
//匹配方法上包含此注解的方法
private final String annotationPointCut = "@annotation(com.platform.Aop.LogAnnotation)";
//注解切点
@Pointcut(value = annotationPointCut)
public void logAnnotation() {
}
再通过@Around注解绑定具体的操作方法:
@Around(value = "logAnnotation()")
public Object aroundAnnotation(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Object result = null;
StringBuilder sbLog = new StringBuilder("\n");
try {
sbLog.append(String.format("类名:%s\r\n", proceedingJoinPoint.getTarget().getClass().getName()));
MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
Method method = methodSignature.getMethod();
LogAnnotation logAnnotation = method.getAnnotation(LogAnnotation.class);
if (logAnnotation != null && !logAnnotation.des().isEmpty()) {
sbLog.append(String.format("说明:%s\r\n", logAnnotation.des()));
}
sbLog.append(String.format("方法:%s\r\n", method.getName()));
Object[] args = proceedingJoinPoint.getArgs();
for (Object o : args) {
sbLog.append(String.format("参数:%s\r\n", JSON.toJSON(o)));
}
long startTime = System.currentTimeMillis();
result = proceedingJoinPoint.proceed();
long endTime = System.currentTimeMillis();
sbLog.append(String.format("返回:%s\r\n", JSON.toJSON(result)));
sbLog.append(String.format("耗时:%ss", endTime - startTime));
} catch (Exception ex) {
sbLog.append(String.format("异常:%s", ex.getMessage()));
} finally {
logger.info(sbLog.toString());
}
return result;
}
这个方法里需要注意的是注解方式相比第一种其实就多了如下几行代码:
Method method = methodSignature.getMethod();
LogAnnotation logAnnotation = method.getAnnotation(LogAnnotation.class);
if (logAnnotation != null && !logAnnotation.des().isEmpty()) {
sbLog.append(String.format("说明:%s\r\n", logAnnotation.des()));
}
下面是注解测试用例:
@LogAnnotation(des = "注解记录日志")
@PostMapping("/addUser01")
public ResponseEntity<MoStudent> addUser01(@RequestBody MoStudent moStudent) throws Exception {
moStudent.setNumber(UUID.randomUUID().toString());
return new ResponseEntity<>(moStudent, HttpStatus.OK);
}
如下是LogAspect.java的所有代码:
/*
* Author:shenniu003
* Copyright (c) 2018.
*/
package com.platform.Aop;
import com.alibaba.fastjson.JSON;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
* Created by Administrator on 2018/11/5.
* springboot+aop切点记录请求和响应信息
*/
@Component
@Aspect
public class LogAspect {
//切点入口 Controller包下面所有类的所有方法
private final String pointcut = "execution(* com.platform.Controller..*(..))";
//匹配方法上包含此注解的方法
private final String annotationPointCut = "@annotation(com.platform.Aop.LogAnnotation)";
private Logger logger = LoggerFactory.getLogger(LogAspect.class);
//切点
@Pointcut(value = pointcut)
public void log() {
}
@Around(value = "log()")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Object result = null;
StringBuilder sbLog = new StringBuilder("\n");
try {
sbLog.append(String.format("类名:%s\r\n", proceedingJoinPoint.getTarget().getClass().getName()));
MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
sbLog.append(String.format("方法:%s\r\n", methodSignature.getMethod().getName()));
Object[] args = proceedingJoinPoint.getArgs();
for (Object o : args) {
sbLog.append(String.format("参数:%s\r\n", JSON.toJSON(o)));
}
long startTime = System.currentTimeMillis();
result = proceedingJoinPoint.proceed();
long endTime = System.currentTimeMillis();
sbLog.append(String.format("返回:%s\r\n", JSON.toJSON(result)));
sbLog.append(String.format("耗时:%ss", endTime - startTime));
} catch (Exception ex) {
sbLog.append(String.format("异常:%s", ex.getMessage()));
} finally {
logger.info(sbLog.toString());
}
return result;
}
//注解切点
@Pointcut(value = annotationPointCut)
public void logAnnotation() {
}
@Around(value = "logAnnotation()")
public Object aroundAnnotation(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Object result = null;
StringBuilder sbLog = new StringBuilder("\n");
try {
sbLog.append(String.format("类名:%s\r\n", proceedingJoinPoint.getTarget().getClass().getName()));
MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
Method method = methodSignature.getMethod();
LogAnnotation logAnnotation = method.getAnnotation(LogAnnotation.class);
if (logAnnotation != null && !logAnnotation.des().isEmpty()) {
sbLog.append(String.format("说明:%s\r\n", logAnnotation.des()));
}
sbLog.append(String.format("方法:%s\r\n", method.getName()));
Object[] args = proceedingJoinPoint.getArgs();
for (Object o : args) {
sbLog.append(String.format("参数:%s\r\n", JSON.toJSON(o)));
}
long startTime = System.currentTimeMillis();
result = proceedingJoinPoint.proceed();
long endTime = System.currentTimeMillis();
sbLog.append(String.format("返回:%s\r\n", JSON.toJSON(result)));
sbLog.append(String.format("耗时:%ss", endTime - startTime));
} catch (Exception ex) {
sbLog.append(String.format("异常:%s", ex.getMessage()));
} finally {
logger.info(sbLog.toString());
}
return result;
}
}

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
-
上一篇
聊一聊泛型的可空性(kotlin)
什么?泛型本身也可以是nullable?上来就抛这么个问题实在是不够友好~ 首先回顾,什么是泛型?Oracle Java Tutorials Introduced in J2SE 5.0, this long-awaited enhancement to the type system allows a type or method to operate on objects of various types while providing compile-time type safety. It adds compile-time type safety to the Collections Framework and eliminates the drudgery of casting. 泛型的本质是参数化类型,也就是说操作的数据类
-
下一篇
java8学习:lambda表达式(2)
内容来自《 java8实战 》,本篇文章内容均为非盈利,旨为方便自己查询、总结备份、开源分享。如有侵权请告知,马上删除。书籍购买地址:java8实战 紧接上一篇内容,上一篇内容讲了lambda的使用,自定义函数式接口和它自带的函数式接口,这一篇将讲述lambda的类型检查,方法引用和构造器引用等内容 上一篇内容提到过,lambda表达式可以为函数式接口生成一个实例,类似匿名内部类的功能,但是lambda本身并不包含他在实现哪个函数式接口的信息 下面来看一下lambda的类型检查 上一篇文章中说到的,lambda的传入参数可写可不写,如下 Predicate<Integer> predicate = (i) -> i == 3; 那么她是怎么知道i值是Integer类型的呢? 为了说明这个情况,我们可以参考下面代码 @NoArgsConstructor @AllArgsConstructor @Data public class Apple { private String color; private Integer weight; } public class Ja...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- CentOS6,CentOS7官方镜像安装Oracle11G
- Dcoker安装(在线仓库),最新的服务器搭配容器使用
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- SpringBoot2全家桶,快速入门学习开发网站教程