Java SpringBoot+Mybatis-Flex+Logback实现打印日志

先看效果

javascript 复制代码
2025-08-26 09:52:19.834 [http-nio-10003-exec-10] INFO  c.x.c.logging.RequestLoggingFilter - HTTP请求: {headers={content-length=213, host=192.168.31.149:10003, content-type=application/json, connection=keep-alive, accept-encoding=gzip, deflate, br, user-agent=Apifox/1.0.0 (https://apifox.com), accept=*/*}, 调用方式=POST, 客户端IP=192.168.31.149, 接口路径=/test/exam/addData, body={
  "classificationId": 232,
  "examRecordId": 1223,
  "userId": 234
}, 传递参数=null}

2025-08-26 10:00:48.678 [http-nio-10003-exec-2] WARN  com.zaxxer.hikari.pool.PoolBase - HikariPool-1 - Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl@2871c902 (No operations allowed after connection closed.). Possibly consider using a shorter maxLifetime value.
2025-08-26 10:00:48.737 [http-nio-10003-exec-2] INFO  c.x.c.logging.RequestLoggingFilter - HTTP请求: {headers={host=192.168.31.149:10003, connection=keep-alive, accept-encoding=gzip, deflate, br, user-agent=Apifox/1.0.0 (https://apifox.com), accept=*/*}, 调用方式=GET, 客户端IP=192.168.31.149, 接口路径=/test/banner/list, 传递参数=null}

一、配置Maven依赖

XML 复制代码
<dependencies>
    <!-- Spring Boot Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- MyBatis-Flex -->
    <dependency>
        <groupId>com.mybatis-flex</groupId>
        <artifactId>mybatis-flex-spring-boot-starter</artifactId>
        <version>1.8.6</version>
    </dependency>
    
    <!-- Logback JSON输出 -->
    <dependency>
        <groupId>ch.qos.logback.contrib</groupId>
        <artifactId>logback-json-classic</artifactId>
        <version>0.1.5</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback.contrib</groupId>
        <artifactId>logback-jackson</artifactId>
        <version>0.1.5</version>
    </dependency>
    
    <!-- 用于获取请求体 -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
    </dependency>
</dependencies>

二、配置properties资源包

生产环境等相关自己按需要配置

javascript 复制代码
#logging
logging.level.com.mybatisflex:INFO

三、新增:src/main/resources/logback-spring.xml

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="ch.qos.logback.contrib.json.classic.JsonLayout">
                <jsonFormatter class="ch.qos.logback.contrib.jackson.JacksonJsonFormatter">
                    <prettyPrint>true</prettyPrint>
                </jsonFormatter>
                <timestampFormat>yyyy-MM-dd' 'HH:mm:ss.SSS</timestampFormat>
                <appendLineSeparator>true</appendLineSeparator>
            </layout>
        </encoder>
    </appender>

    <appender name="PLAIN_CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- 针对请求日志使用JSON格式 -->
    <logger name="com.xiaoqiu.RequestLoggingFilter" level="INFO">
        <appender-ref ref="CONSOLE" />
    </logger>

    <!-- MyBatis-Flex SQL日志 -->
    <logger name="com.mybatis" level="INFO" />

    <!-- 根日志记录器 -->
    <root level="INFO">
        <appender-ref ref="PLAIN_CONSOLE" />
    </root>
</configuration>

四、新增:com/你的包路径/config/requestLoggingFilter

java 复制代码
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

@Component
public class RequestLoggingFilter extends OncePerRequestFilter {

    private static final Logger logger = LoggerFactory.getLogger(RequestLoggingFilter.class);

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        // 包装请求和响应以支持多次读取
        ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request);
        ContentCachingResponseWrapper wrappedResponse = new ContentCachingResponseWrapper(response);

        try {
            filterChain.doFilter(wrappedRequest, wrappedResponse);
        } finally {
            // 记录请求信息
            logRequest(wrappedRequest);
            // 记录响应信息(可选)
            logResponse(wrappedResponse);
            // 将响应内容写回客户端
            wrappedResponse.copyBodyToResponse();
        }
    }

    private void logRequest(ContentCachingRequestWrapper request) {
        Map<String, Object> logData = new HashMap<>();

        // 基本信息
        logData.put("调用方式", request.getMethod());
        logData.put("接口路径", request.getRequestURI());
        logData.put("传递参数", request.getQueryString());
        logData.put("客户端IP", request.getRemoteAddr());

        // 请求头
        Map<String, String> headers = new HashMap<>();
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            headers.put(headerName, request.getHeader(headerName));
        }
        logData.put("headers", headers);

        // 请求参数
        Map<String, String[]> params = request.getParameterMap();
        if (!params.isEmpty()) {
            logData.put("请求参数", params);
        }

        // 请求体(JSON)
        byte[] content = request.getContentAsByteArray();
        if (content.length > 0) {
            try {
                String body = new String(content, request.getCharacterEncoding());
                logData.put("body", body);
            } catch (UnsupportedEncodingException e) {
                logger.warn("无法解析请求正文", e);
            }
        }

        logger.info("客户端请求: {}", logData);
    }

    private void logResponse(ContentCachingResponseWrapper response) {
        // 可选的响应日志记录逻辑
    }
}