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 
 1 package com.example;
 2
 3 import org.springframework.boot.SpringApplication;
 4 import org.springframework.boot.autoconfigure.SpringBootApplication;
 5 import org.springframework.boot.web.servlet.ServletComponentScan;
 6
 7 @SpringBootApplication
 8 @ServletComponentScan
 9 public class AopLoggingApplication {
10
11     public static void main(String[] args) {
12         SpringApplication.run(AopLoggingApplication.class, args);
13     }
14 }
SomeFilter  
 1 package com.example.filter;
 2
 3 import lombok.extern.slf4j.Slf4j;
 4 import org.springframework.web.filter.OncePerRequestFilter;
 5 import org.springframework.web.util.ContentCachingRequestWrapper;
 6
 7 import javax.servlet.FilterChain;
 8 import javax.servlet.ServletException;
 9 import javax.servlet.annotation.WebFilter;
10 import javax.servlet.http.HttpServletRequest;
11 import javax.servlet.http.HttpServletResponse;
12 import java.io.IOException;
13
14 @WebFilter
15 @Slf4j
16 public class SomeFilter  extends OncePerRequestFilter {
17     @Override
18     protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
19         log.debug("进入SomeFilter");
20         /**
21          * 因为请求体的流在进入aop时就被关闭了,从request拿到body会抛异常,stream closed.这里这样写可以在aop里面拿到请求体,具体参考org.springframework.web.filter.AbstractRequestLoggingFilter.
22          * 假如这个方法有更改request的操作 就把这段代码写在上面.
23          */
24         if(log.isDebugEnabled()){
25             httpServletRequest = new ContentCachingRequestWrapper(httpServletRequest, 1024);
26         }
27
28         filterChain.doFilter(httpServletRequest, httpServletResponse);
29     }
30 }
HttpLoggingAspect 
 1 package com.example.aspect;
 2
 3 import com.fasterxml.jackson.databind.ObjectMapper;
 4 import lombok.extern.slf4j.Slf4j;
 5 import org.aspectj.lang.JoinPoint;
 6 import org.aspectj.lang.ProceedingJoinPoint;
 7 import org.aspectj.lang.annotation.*;
 8 import org.springframework.beans.factory.annotation.Autowired;
 9 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
10 import org.springframework.stereotype.Component;
11 import org.springframework.web.context.request.RequestContextHolder;
12 import org.springframework.web.context.request.ServletRequestAttributes;
13 import org.springframework.web.util.ContentCachingRequestWrapper;
14 import org.springframework.web.util.WebUtils;
15
16 import javax.servlet.http.HttpServletRequest;
17 import java.io.UnsupportedEncodingException;
18 import java.util.Arrays;
19 @Component
20 @Aspect
21 @Slf4j
22 @ConditionalOnProperty(name = "web-logging", havingValue = "debug")
23 public class HttpLoggingAspect {
24
25     @Autowired
26     private ObjectMapper mapper;
27
28     @Pointcut("execution(public * com.example..controller.*.*(..))")//两个..代表所有子目录,最后括号里的两个..代表所有参数
29     public void logPointCut() {
30     }
31
32     @Before("logPointCut()")
33     public void doBefore(JoinPoint joinPoint) throws Throwable {
34         // 接收到请求,记录请求内容
35         ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
36         HttpServletRequest request = attributes.getRequest();
37
38         // 记录下请求内容
39         log.debug("┌──────────请求──────────────────");
40         log.debug("┃控制器{}->方法{}-->参数{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName(), mapper.writeValueAsString(Arrays.toString(joinPoint.getArgs())));
41         log.debug("┃{}-->{}-->{}", request.getRemoteAddr(), request.getMethod(), request.getRequestURL());
42         log.debug("┃parameter{}", mapper.writeValueAsString(request.getParameterMap()));// 格式化输出的json mapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
43         log.debug("┃body{}",getPayload(request));
44         log.debug("└──────────────────────────────");
45
46     }
47
48     @Around("logPointCut()")
49     public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
50         long startTime = System.currentTimeMillis();
51         Object ob = pjp.proceed();// ob 为方法的返回值
52         log.debug("┌──────────回复──────────────────");
53         log.debug("┃耗时{}ms" ,(System.currentTimeMillis() - startTime));
54         return ob;
55     }
56
57     @AfterReturning(returning = "ret", pointcut = "logPointCut()")// returning的值和doAfterReturning的参数名一致
58     public void doAfterReturning(Object ret) throws Throwable {
59         log.debug("┃返回" + ret);
60         log.debug("└──────────────────────────────");
61     }
62
63     private String getPayload(HttpServletRequest request) {
64         ContentCachingRequestWrapper wrapper =  WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class);
65         if (wrapper != null) {
66             byte[] buf = wrapper.getContentAsByteArray();
67             if (buf.length > 0) {
68                 try {
69                     int length = Math.min(buf.length, 1024);//最大只打印1024字节
70                     return new String(buf, 0, length, wrapper.getCharacterEncoding());
71                 } catch (UnsupportedEncodingException var6) {
72                     return "[unknown]";
73                 }
74             }
75         }
76         return "";
77     }
78 }

测试用的TestController

 1 package com.example.controller;
 2
 3 import org.springframework.web.bind.annotation.GetMapping;
 4 import org.springframework.web.bind.annotation.PostMapping;
 5 import org.springframework.web.bind.annotation.RequestBody;
 6 import org.springframework.web.bind.annotation.RestController;
 7
 8 import java.util.Map;
 9
10 @RestController
11 public class TestController {
12     @GetMapping("/")
13     public String hello(String name) {
14         return "Spring boot " + name;
15     }
16
17     @PostMapping("/")
18     public Map<String, Object> hello(@RequestBody Map<String, Object> map){
19         return map;
20     }
21 }

配置文件application.properties

web-logging=debug #作为启动web日志的配置, 方便本地开发和上线
logging.level.com.example=debug

三.效果

1.=====================================================================

请求 GET http://localhost:8080?name=abc
回复Spring boot abc
日志
 1 2018-10-10 21:55:46.873 DEBUG 53764 --- [nio-8080-exec-2] com.example.filter.SomeFilter            : 进入SomeFilter
 2 2018-10-10 21:55:46.914 DEBUG 53764 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect     : ┌──────────请求──────────────────
 3 2018-10-10 21:55:46.929 DEBUG 53764 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect     : ┃控制器com.example.controller.TestController->方法hello-->参数"[abc]"
 4 2018-10-10 21:55:46.929 DEBUG 53764 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect     : ┃127.0.0.1-->GET-->http://localhost:8080/
 5 2018-10-10 21:55:47.087 DEBUG 53764 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect     : ┃parameter{"name":["abc"]}
 6 2018-10-10 21:55:47.087 DEBUG 53764 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect     : ┃body
 7 2018-10-10 21:55:47.087 DEBUG 53764 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect     : └──────────────────────────────
 8 2018-10-10 21:55:47.095 DEBUG 53764 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect     : ┌──────────回复──────────────────
 9 2018-10-10 21:55:47.095  INFO 53764 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect     : ┃耗时181ms
10 2018-10-10 21:55:47.096  INFO 53764 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect     : ┃返回Spring boot abc
11 2018-10-10 21:55:47.096 DEBUG 53764 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect     : └──────────────────────────────

2.=====================================================================

请求 POST http://localhost:8080 参数 json类型 {"name":"spring boot"}

回复

{"name":"spring boot"}

日志

2018-10-10 22:00:11.465 DEBUG 59444 --- [nio-8080-exec-2] com.example.filter.SomeFilter            : 进入SomeFilter
2018-10-10 22:00:11.659 DEBUG 59444 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect     : ┌──────────请求──────────────────
2018-10-10 22:00:11.671 DEBUG 59444 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect     : ┃控制器com.example.controller.TestController->方法hello-->参数"[{name=spring boot}]"
2018-10-10 22:00:11.672 DEBUG 59444 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect     : ┃127.0.0.1-->POST-->http://localhost:8080/
2018-10-10 22:00:11.696 DEBUG 59444 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect     : ┃parameter{}
2018-10-10 22:00:11.696 DEBUG 59444 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect     : ┃body{"name":"spring boot"}
2018-10-10 22:00:11.696 DEBUG 59444 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect     : └──────────────────────────────
2018-10-10 22:00:11.702 DEBUG 59444 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect     : ┌──────────回复──────────────────
2018-10-10 22:00:11.703  INFO 59444 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect     : ┃耗时44ms
2018-10-10 22:00:11.703  INFO 59444 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect     : ┃返回{name=spring boot}
2018-10-10 22:00:11.703 DEBUG 59444 --- [nio-8080-exec-2] com.example.aspect.HttpLoggingAspect     : └──────────────────────────────

github: https://github.com/tungss/aop-logging.git

原文地址:https://www.cnblogs.com/startnow/p/9769537.html

时间: 2024-10-11 21:35:19

spring boot aop打印http请求回复日志包含请求体的相关文章

Spring Boot AOP之对请求的参数入参与返回结果进行拦截处理

Spring Boot AOP之对请求的参数入参与返回结果进行拦截处理 本文链接:https://blog.csdn.net/puhaiyang/article/details/78146620 本文链接:https://blog.csdn.net/puhaiyang/article/details/78146620 spring Aop切面中的@Before @Around等执行顺序与请求参数统一解码 https://www.cnblogs.com/newAndHui/p/11771035.h

Spring Boot AOP解析

Spring Boot AOP 面向切面编程(AOP)通过提供另一种思考程序结构的方式来补充面向对象编程(OOP). OOP中模块化的关键单元是类,而在AOP中,模块化单元是方面. AOP(Aspect Oriented Program) 面向切面编程 在面向切面编程的思想里面,把功能分为核心业务功能和周边功能. 核心业务,比如登陆,增加数据,删除数据都叫核心业务 周边功能,比如性能统计,日志,事务管理等等 周边功能在 Spring Boot 的面向切面编程AOP思想里,即被定义为切面 在面向切

spring boot aop日志管理(MongoDB)

aop拦截的是controller层请求,正常的请求用@Before来拦截, 异常的请求用@AfterThrowing来拦截 1.引用aop jar包 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> <version>2.0.3.RELEASE</version>

spring boot aop

这里要做就是利用aop 来打印请求的日志,返回结果,简单的异常处理 一:使用@Aspect注解创建切面,类名是 RquestAspect import javax.servlet.http.HttpServletRequest; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.as

Spring Boot如何让某个Controller支持跨源请求,以及如何让Controller类某个成员方法支持跨源请求

在前面我们已经讨论了Spring Boot 如何全局支持跨源请求.如果你想了解可以查看这篇文章 下面我们讨论另一种场景.有些时候,你需要让你的应用在大部分的时候,仅仅支持当前域名下的请求.而仅仅在极其特殊的几个场合下,才支持跨源请求.这个时候,你需要把跨源请求仅仅缩小在几个Controller上,或者Controller类的几个成员方法上.这个时候你需要用到如下的注解:@CrossOrigin(origins = "*", maxAge = 3600) .把这个注解放到 Control

Spring Boot快速入门(二):http请求

原文地址:https://lierabbit.cn/articles/4 一.准备 postman:一个接口测试工具 创建一个新工程 选择web 不会的请看Spring Boot快速入门(一):Hello Spring Boot 二.开始 新建java类RequestCtrl 1.添加一个all方法,使用@RequestMapping注解,可以处理所有的http请求 @RestController//这是一个控制器并只返回数据不寻找视图 public class RequestCtrl { @R

Spring Boot中实现logback多环境日志配置

在Spring Boot中,可以在logback.xml中的springProfile标签中定义多个环境logback.xml: <springProfile name="production"> <root level="DEBUG"> <appender-ref ref="STDOUT"/> </root> </springProfile> <springProfile nam

Spring Boot AOP 简易操作日志管理

AOP (Aspect Oriented Programming) 面向切面编程. 业务有核心业务和边缘业务. 比如用户管理,菜单管理,权限管理,这些都属于核心业务. 比如日志管理,操作记录管理,这些都是边缘业务,可以统一的提出来. 尝试使用SpringBoot +AOP 提出操作记录业务. github aop_demo package com.lick.aspect.lang.annotation; import com.lick.aspect.lang.enums.BusinessType

Spring Boot AOP Demo

什么是AOP? AOP面向切面,切面将那些与业务无关,却被业务模块共同调用的逻辑提取并封装起来,减少了系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性. 实现策略JAVA SE动态代理 CGLib 相关注解 @Aspect(方面) @Pointcut(切入点) @Before(之前) @After(之后) pom.xml <!--引用AOP--> <dependency> <groupId>org.springframework.boot</gro