spring boot aop打印http请求回复日志包含请求体
一.引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
二.代码
AopLoggingApplication
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
@SpringBootApplication
@ServletComponentScan
public class AopLoggingApplication {
public static void main(String[] args) {
SpringApplication.run(AopLoggingApplication.class, args);
}
}
SomeFilter
package com.example.filter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter
@Slf4j
public class SomeFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
log.debug("进入SomeFilter");
/**
* 因为请求体的流一般在进入aop时就被关闭了,这里这样写可以在aop里面拿到请求体,具体参考org.springframework.web.filter.AbstractRequestLoggingFilter.
*/
if(log.isDebugEnabled()){
httpServletRequest = new ContentCachingRequestWrapper(httpServletRequest, 1024);
}
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
}
HttpLoggingAspect
package com.example.aspect;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.WebUtils;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
@Component
@Aspect
@Slf4j
@ConditionalOnProperty(name = "web-logging", havingValue = "debug")
public class HttpLoggingAspect {
@Autowired
private ObjectMapper mapper;
@Pointcut("execution(public * com.example..controller.*.*(..))")//两个..代表所有子目录,最后括号里的两个..代表所有参数
public void logPointCut() {
}
@Around("logPointCut()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
// 接收到请求,记录请求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// 记录下请求内容
log.debug("┌──────────请求──────────────────");
log.debug("┃控制器{}->方法{}-->参数{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName(), mapper.writeValueAsString(Arrays.toString(joinPoint.getArgs())));
log.debug("┃{}-->{}-->{}", request.getRemoteAddr(), request.getMethod(), request.getRequestURL());
log.debug("┃parameter{}", mapper.writeValueAsString(request.getParameterMap()));// 格式化输出的json mapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
log.debug("┃body{}",getPayload(request));
log.debug("└──────────────────────────────");
long startTime = System.currentTimeMillis();
Object ob = pjp.proceed();// ob 为方法的返回值
log.debug("┌──────────回复──────────────────");
log.debug("┃耗时{}ms" ,(System.currentTimeMillis() - startTime));
log.debug("┃返回" + mapper.writeValueAsString(ob));
log.debug("└──────────────────────────────");
return ob;
}
private String getPayload(HttpServletRequest request) {
ContentCachingRequestWrapper wrapper = WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class);
if (wrapper != null) {
byte[] buf = wrapper.getContentAsByteArray();
) {
try {
);//最大只打印1024字节
, length, wrapper.getCharacterEncoding());
} catch (UnsupportedEncodingException var6) {
return "[unknown]";
}
}
}
return "";
}
}
测试用的TestController
package com.example.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@RestController
public class TestController {
@GetMapping("/")
public String hello(String name) {
return "Spring boot " + name;
}
@PostMapping("/")
public Map<String, Object> hello(@RequestBody Map<String, Object> map){
return map;
}
}
配置文件application.properties
web-logging=debug #作为启动web日志的配置, 方便本地开发和上线 logging.level.com.example=debug
三.效果
1.=====================================================================
请求 GET http://localhost:8080?name=abc
回复Spring boot abc
日志
-- :: --- [nio--exec-] com.example.filter.SomeFilter : 进入SomeFilter
-- :: --- [nio--exec-] com.example.aspect.HttpLoggingAspect : ┌──────────请求──────────────────
-- :: --- [nio--exec-] com.example.aspect.HttpLoggingAspect : ┃控制器com.example.controller.TestController->方法hello-->参数"[abc]"
-- :: --- [nio--exec-] com.example.aspect.HttpLoggingAspect : ┃127.0.0.1-->GET-->http://localhost:8080/
-- :: --- [nio--exec-] com.example.aspect.HttpLoggingAspect : ┃parameter{"name":["abc"]}
-- :: --- [nio--exec-] com.example.aspect.HttpLoggingAspect : ┃body
-- :: --- [nio--exec-] com.example.aspect.HttpLoggingAspect : └──────────────────────────────
-- :: --- [nio--exec-] com.example.aspect.HttpLoggingAspect : ┌──────────回复──────────────────
-- :: --- [nio--exec-] com.example.aspect.HttpLoggingAspect : ┃耗时181ms
-- :: --- [nio--exec-] com.example.aspect.HttpLoggingAspect : ┃返回Spring boot abc
-- :: --- [nio--exec-] com.example.aspect.HttpLoggingAspect : └──────────────────────────────
2.=====================================================================
请求 POST http://localhost:8080 参数 json类型 {"name":"spring boot"}
回复
{"name":"spring boot"}
日志
-- :: --- [nio--exec-] com.example.filter.SomeFilter : 进入SomeFilter
-- :: --- [nio--exec-] com.example.aspect.HttpLoggingAspect : ┌──────────请求──────────────────
-- :: --- [nio--exec-] com.example.aspect.HttpLoggingAspect : ┃控制器com.example.controller.TestController->方法hello-->参数"[{name=spring boot}]"
-- :: --- [nio--exec-] com.example.aspect.HttpLoggingAspect : ┃127.0.0.1-->POST-->http://localhost:8080/
-- :: --- [nio--exec-] com.example.aspect.HttpLoggingAspect : ┃parameter{}
-- :: --- [nio--exec-] com.example.aspect.HttpLoggingAspect : ┃body{"name":"spring boot"}
-- :: --- [nio--exec-] com.example.aspect.HttpLoggingAspect : └──────────────────────────────
-- :: --- [nio--exec-] com.example.aspect.HttpLoggingAspect : ┌──────────回复──────────────────
-- :: --- [nio--exec-] com.example.aspect.HttpLoggingAspect : ┃耗时44ms
-- :: --- [nio--exec-] com.example.aspect.HttpLoggingAspect : ┃返回{name=spring boot}
-- :: --- [nio--exec-] com.example.aspect.HttpLoggingAspect : └──────────────────────────────
github: https://github.com/tungss/aop-logging.git
spring boot aop打印http请求回复日志包含请求体的更多相关文章
- Spring Boot AOP之对请求的参数入参与返回结果进行拦截处理
Spring Boot AOP之对请求的参数入参与返回结果进行拦截处理 本文链接:https://blog.csdn.net/puhaiyang/article/details/78146620 ...
- Spring Boot 2.X(十四):日志功能 Logback
Logback 简介 Logback 是由 SLF4J 作者开发的新一代日志框架,用于替代 log4j. 主要特点是效率更高,架构设计够通用,适用于不同的环境. Logback 分为三个模块:logb ...
- Spring Boot AOP解析
Spring Boot AOP 面向切面编程(AOP)通过提供另一种思考程序结构的方式来补充面向对象编程(OOP). OOP中模块化的关键单元是类,而在AOP中,模块化单元是方面. AOP(Aspec ...
- Spring boot AOP 记录请求日志
如何将所有的通过url的请求参数以及返回结果都输出到日志中? 如果在controller的类中每个方法名都写一个log输出肯定是不明智的选择. 使用spring的AOP功能即可完成. 1. 在pom. ...
- Spring Boot AOP 扫盲,实现接口访问的统一日志记录
AOP 是 Spring 体系中非常重要的两个概念之一(另外一个是 IoC),今天这篇文章就来带大家通过实战的方式,在编程猫 SpringBoot 项目中使用 AOP 技术为 controller 层 ...
- 玩转spring boot——AOP与表单验证
AOP在大多数的情况下的应用场景是:日志和验证.至于AOP的理论知识我就不做赘述.而AOP的通知类型有好几种,今天的例子我只选一个有代表意义的“环绕通知”来演示. 一.AOP入门 修改“pom.xml ...
- Spring Boot AOP
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是Spring框架中的一个重要内容,它通 ...
- redis分布式锁-spring boot aop+自定义注解实现分布式锁
接这这一篇redis分布式锁-java实现末尾,实现aop+自定义注解 实现分布式锁 1.为什么需要 声明式的分布式锁 编程式分布式锁每次实现都要单独实现,但业务量大功能复杂时,使用编程式分布式锁无疑 ...
- Spring Boot - AOP(面向切面)
AOP 全称 Aspect Oriented Programming(面向切面),AOP主要实现的目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分 ...
随机推荐
- k8s helm 私服chartmuseum minio s3 存储配置
1. 安装minio 使用docker 安装 参考项目 https://github.com/rongfengliang/mino-thumbor-openresty 备注: 因为是一个集成项目可能会 ...
- ubuntu :扩充虚拟机的磁盘容量
前言: 开始建立虚拟机的时候给的容量是20G,给了10G的交换空间,所以后来有点不够用了,现在安装软件会出现提示磁盘空间不足,所以需要扩充一下磁盘的容量. 步骤: 1.因为我用的是Vmware ...
- Cousera 无法播放视频 解决办法 widows 和 linux
查资料得知,Cousera无法播放课程视频原因在于DNS污染. 尽管通过FQ软件把视频看完了,在最后一课找到了这个解决办法,现在拿出来分享给大家: Windows: 请参照以下链接: http://j ...
- 以太坊客户端Geth命令用法
命令用法 geth [选项] 命令 [命令选项] [参数…] 命令: account 管理账户attach 启动交互式JavaScript环境(连接到节点)bug 上报bug Issuesconsol ...
- JDK 8 新特性
JDK 8, Oracle's implementation of Java SE 8. JDK 8 是 Oracle 对 Java SE 8 规范的实现. 本文分析 JDK 8 引入的新特性. 官方 ...
- 第六章 hbase shell 命令
hbase shell命令 描述 alter 修改列族(Column Family)模式 count 统计表中行的数量 create 创建表 ...
- 【洛谷】P1196 银河英雄传说(并查集)
题目描述 公元五八○一年,地球居民迁至金牛座α第二行星,在那里发表银河联邦创立宣言,同年改元为宇宙历元年,并开始向银河系深处拓展. 宇宙历七九九年,银河系的两大军事集团在巴米利恩星域爆发战争.泰山压顶 ...
- Angular.js中处理页面闪烁的方法详解
Angular.js中处理页面闪烁的方法详解 前言 大家在使用{{}}绑定数据的时候,页面加载会出现满屏尽是{{xxx}}的情况.数据还没响应,但页面已经渲染了.这是因为浏览器和angularjs渲染 ...
- java.lang.NoClassDefFoundError: org/jaxen/JaxenException解决方法
在使用dom4j的xpath时出现java.lang.NoClassDefFoundError: org/jaxen/JaxenException的异常,原因是dom4j引用了jaxen jar包,而 ...
- Jmeter如何监控服务器性能
1.jmeter只需要安装一些插件 ,就可以像loadrunner一样监控服务器CPU.内存等性能参数 1.下载需要的jmeter插件 如图上面两个是jmeter插件,可以再下面的链接中下载 ...