一.引入依赖

        <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请求回复日志包含请求体的更多相关文章

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

    Spring Boot AOP之对请求的参数入参与返回结果进行拦截处理   本文链接:https://blog.csdn.net/puhaiyang/article/details/78146620 ...

  2. Spring Boot 2.X(十四):日志功能 Logback

    Logback 简介 Logback 是由 SLF4J 作者开发的新一代日志框架,用于替代 log4j. 主要特点是效率更高,架构设计够通用,适用于不同的环境. Logback 分为三个模块:logb ...

  3. Spring Boot AOP解析

    Spring Boot AOP 面向切面编程(AOP)通过提供另一种思考程序结构的方式来补充面向对象编程(OOP). OOP中模块化的关键单元是类,而在AOP中,模块化单元是方面. AOP(Aspec ...

  4. Spring boot AOP 记录请求日志

    如何将所有的通过url的请求参数以及返回结果都输出到日志中? 如果在controller的类中每个方法名都写一个log输出肯定是不明智的选择. 使用spring的AOP功能即可完成. 1. 在pom. ...

  5. Spring Boot AOP 扫盲,实现接口访问的统一日志记录

    AOP 是 Spring 体系中非常重要的两个概念之一(另外一个是 IoC),今天这篇文章就来带大家通过实战的方式,在编程猫 SpringBoot 项目中使用 AOP 技术为 controller 层 ...

  6. 玩转spring boot——AOP与表单验证

    AOP在大多数的情况下的应用场景是:日志和验证.至于AOP的理论知识我就不做赘述.而AOP的通知类型有好几种,今天的例子我只选一个有代表意义的“环绕通知”来演示. 一.AOP入门 修改“pom.xml ...

  7. Spring Boot AOP

    AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是Spring框架中的一个重要内容,它通 ...

  8. redis分布式锁-spring boot aop+自定义注解实现分布式锁

    接这这一篇redis分布式锁-java实现末尾,实现aop+自定义注解 实现分布式锁 1.为什么需要 声明式的分布式锁 编程式分布式锁每次实现都要单独实现,但业务量大功能复杂时,使用编程式分布式锁无疑 ...

  9. Spring Boot - AOP(面向切面)

    AOP 全称 Aspect Oriented Programming(面向切面),AOP主要实现的目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分 ...

随机推荐

  1. 使用C#和Java发送邮件(转载)

    using System.Net.Mail; using System.Net; public class EmailEntity { private MailMessage mm; /// < ...

  2. linux下如何添加一个用户并且让用户获得root权限【转载】

    原文:http://www.cnblogs.com/johnw/p/5499442.html 1.添加用户,首先用adduser命令添加一个普通用户,命令如下: #adduser tommy //添加 ...

  3. oracle 之 手动建库

    1.-- 查看服务器 ORA 环境变量情况[oracle@orastb ~]$ env|grep ORAORACLE_BASE=/u01/app/oracleORACLE_HOME=/u01/app/ ...

  4. DS05--查找

    一.学习总结 1.查找的思维导图 2.查找学习体会 2.1 关联容器和顺序容器 c++中有两种类型的容器:顺序容器和关联容器,顺序容器主要有:vector.list.deque等.其中vector表示 ...

  5. 关于PIPELINE,也许你应该知道

    所谓流水线(pipeline)设计,通常来说是流水生产线. 同样,组合逻辑路径可以看作是一条生产线,路径上的每个逻辑单元都可以看作是一个阶段,都会产生时延. 如果不采用流水设计,前后级组合逻辑依次工作 ...

  6. Windows下安装HBase

    本文转载自:http://blog.csdn.net/kangkanglou/article/details/30748139 本文主要参照Hbase官网:http://hbase.apache.or ...

  7. 【kubernetes】kubectl logs connection refused

    因为启动dashboard报CrashLoopBackOff错误,尝试使用logs去查看日志,结果报错,错误如下: [root@localhost ~]# kubectl -s http://192. ...

  8. css3的transition属性的使用

    transition是将某个属性从一个属性值在指定的时间内平滑过渡到另一个属性值来实现动画效果.这个属性一般搭配:hover来使 下面看一个例子:鼠标放在div上,0.2s后将div元素的背景色用一秒 ...

  9. 【BZOJ】2938 [POI2000]病毒(AC自动机)

    题目 传送门:QWQ 传送到洛谷QWQ 分析 夏爷爷传送门 代码 #include <bits/stdc++.h> using namespace std; ; ][], fail[N*] ...

  10. 利用docker 最新漏洞渗透--提取root 权限

    一.事出 近期乌云漏洞平台等科技新闻,爆出Docker虚拟化 端口漏洞,本着热爱开源,实践动手的精神,我也去尝试了下,漏洞严重性确实很高,可以拿到root 登陆账户. 二.还原 2.1 通过扫描,我们 ...