一.引入依赖

        <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. python笔记-12 redis缓存

    一.redis引入 1.简要概括redis 1.1 redis默认端口:6379 1.2 redis实现的效果:资源共享 1.3 redis实现的基本原理:不同的进程和一个公共的进程之间建立socke ...

  2. 【java基础】java中Object对象中的Hashcode方法的作用

    以下是关于HashCode的官方文档定义: hashcode方法返回该对象的哈希码值.支持该方法是为哈希表提供一些优点,例如,java.util.Hashtable 提供的哈希表. hashCode  ...

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

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

  4. test20181029 思考熊的马拉松

    题意 思考熊的马拉松 问题描述 今年,n只思考熊参加了校园马拉松比赛.马拉松的赛道是环形的,每圈的长度是A,完成比赛需要跑L圈. 比赛中,甲领先乙很长距离,绕过一圈或多圈后从后面追上了乙的现象叫做&q ...

  5. Python 函数-max()

    max( x, y, z, .... )max() 方法返回给定参数的最大值,参数可以为序列.返回给定参数的最大值.x.y.z数值表达式. 实例 #!/usr/bin/python print &qu ...

  6. oracle之 利用 controlfile trace文件重建控制文件

    一. 11g RAC 重建控制文件 1. --"create controlfile"命令生成到追踪文件中:alter database backup controlfile to ...

  7. Linux 利用busybox制作根文件系统

    busybox版本:1.17.3 官网下载路径:https://busybox.net/downloads/ 网盘下载路径:https://pan.baidu.com/s/1nvrEa73 密码:7y ...

  8. CRC全套~~~ 转载

    经测试CRC16-CCITT是可以了,其它暂时没有测试哦. 00 0E 00 01 00 01 20 17 12 26 20 19 16 01 00 00 01 01 00 00 00 00 00 0 ...

  9. 干净的 js测试页面

    <!DOCTYPE html><html lang="en" > <head> <meta charset="utf-8&quo ...

  10. 电脑桌面文件图标经常显示异常&&右键桌面文件属性不显示

    桌面图标经常失效,但文件可以正常点开使用. 右键桌面文件的属性,电脑无反应. 解决方法 ① cmd-sfc/scannow 此方法无效 ② 点击上图的运行疑难解答,最终找到问题,重启后解决! PS 型 ...