一.引入依赖

        <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. ThinkPHP5 使用create 获取表单所有字段

    TP5没有 TP3的那个create创建表单字段,如果字段太多,写起来是非常麻烦 只需要在 框架里面 think/db/Query.php 里面加上函数 public function create( ...

  2. C#-StructLayoutAttribute(结构体布局)

    struct实例字段的内存布局(Layout)和大小(Size) 在C/C++中,struct类型中的成员的一旦声明,则实例中成员在内存中的布局(Layout)顺序就定下来了,即与成员声明的顺序相同, ...

  3. Django之tag标签和filter标签

    1.Django的tag常见的标签,可以做一些简单的功能 {%if%} 的使用主要用于做判断,还可以包含{%elif%} 这样的用法,最后要跟上{% endif %}.可以使用你的and,or,not ...

  4. dict 没有 key 的情况

    如何处理, 请参考下文,  主要是要理解思路, https://www.polarxiong.com/archives/Python-%E6%93%8D%E4%BD%9Cdict%E6%97%B6%E ...

  5. Terraform 多云管理工具

    1. 介绍   Terraform is a tool for building, changing, and versioning infrastructure safely and efficie ...

  6. uuid 了解

    什么是UUID? UUID是Universally Unique Identifier的缩写,它是在一定的范围内(从特定的名字空间到全球)唯一的机器生成的标识符.UUID具有以下涵义: 经由一定的算法 ...

  7. Hyper-V 手动导入虚机配置实例(转载)

    原文转载:http://blog.51cto.com/bobzy/980241 Hyper-V提供了很方便的虚机导入和导出功能.平时假如我们想导出虚机,先选中虚机,然后鼠标右键在出现菜单列表中选中“导 ...

  8. springboot: 集成jdbc

    1.pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www ...

  9. php-fpm设置与 phpMyadmin超时 操作SQL超时

    LNMP 一键安装包环境: Phpmyadmin   登录超时 (1440 秒未活动),请重新登录. vim /usr/local/php/etc/php.ini session.gc_maxlife ...

  10. 算法提高 P1001【大数乘法】

    当两个比较大的整数相乘时,可能会出现数据溢出的情形.为避免溢出,可以采用字符串的方法来实现两个大数之间的乘法.具体来说,首先以字符串的形式输入两个整数,每个整数的长度不会超过8位,然后把它们相乘的结果 ...