springboot在使用 Servlet API中提供的javax.servlet.Filter 过滤器 对请求参数 和 响应参数 进行获取并记录日志方案

不多说 直接上代码

第一步

java 复制代码
package com.xxx.init.webFilter;

import com.alibaba.fastjson.JSONObject;
import com.xxx.api.constant.CommonConstant;
import com.xxx.api.entities.log.OperationLog;
import com.xxx.init.utils.JwtHelper;
import com.xxx.init.utils.RequestUtils;
import com.xxx.init.utils.WlUtils;
import com.xxx.init.webFilter.jsonWrapper.JsonParameterRequestWrapper;

import com.xxx.init.webFilter.jsonWrapper.ResponseWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * User:Json
 * Date: 2024/4/3
 * 日志操作
 **/
@WebFilter(urlPatterns = {"/*"}, filterName = "OperationLogFilter")
@Order(-100)
@Slf4j
public class OperationLogFilter implements Filter {

    @Value("${spring.application.name}")
    private String serviceName;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;

        if ("GET".equals(httpServletRequest.getMethod())) {
            chain.doFilter(request, response);
            return;
        }
        // 在请求到达 Servlet 前执行的逻辑
        boolean isDownload = false;
        // 检查响应头信息
        String contentDescription = httpServletRequest.getHeader("content-description");
        String contentTransferEncoding = httpServletRequest.getHeader("content-transfer-encoding");
        if (!StringUtils.isEmpty(contentDescription) &&
                !StringUtils.isEmpty(contentTransferEncoding)) {
            isDownload = true; // 设置为 true,表示需要下载
        }

        OperationLog operationLog = new OperationLog();
        operationLog.setOrg_id(0);
        operationLog.setTime(LocalDateTime.now());
        operationLog.setMethod(httpServletRequest.getMethod());
        operationLog.setRouter(httpServletRequest.getRequestURI());
        operationLog.setProtocol(httpServletRequest.getProtocol());
        operationLog.setIp(httpServletRequest.getRemoteAddr());
        operationLog.setService_name(serviceName);


        //获取请求类型为 Json的 数据 如果是form-data 类型的数据 目前没获取
        JsonParameterRequestWrapper jsonParameterRequestWrapper = null;
        if (WlUtils.isJsonReq(httpServletRequest)) {
            jsonParameterRequestWrapper = new JsonParameterRequestWrapper(httpServletRequest);
            operationLog.setRequest_data(getRequestJson(jsonParameterRequestWrapper));
        }

   
        ResponseWrapper responseWrapper = new ResponseWrapper(httpServletResponse);
        if (jsonParameterRequestWrapper == null) {
            chain.doFilter(request, responseWrapper);
        } else {
            chain.doFilter(jsonParameterRequestWrapper, responseWrapper);
        }

        String s = new String(responseWrapper.getContent(), "UTF-8");
        operationLog.setResponse_code(responseWrapper.getStatus());
        operationLog.setResponse_data(isDownload ? "文件下载" : s);
            // 在得到响应的数据之后,response的输出流中就无可用的数据,所以需要巴数据放回去
        ServletOutputStream outputStream = response.getOutputStream();
        outputStream.write(responseWrapper.getContent());
        outputStream.flush();
        outputStream.close();

    }


    private JSONObject getRequestJson(JsonParameterRequestWrapper jsonParameterRequestWrapper) throws IOException {

        String bodyMessage = jsonParameterRequestWrapper.getBodyMessage();
        JSONObject jsonObject = JSONObject.parseObject(bodyMessage);
        return jsonObject;
    }


    @Override
    public void destroy() {

    }
}

第二步:

java 复制代码
package com.xxx.init.webFilter.jsonWrapper;


import com.xxx.init.utils.StreamUtil;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
/**
 * User:Json
 * Date: 2024/4/7
 **/
public class JsonParameterRequestWrapper extends HttpServletRequestWrapper {
    //用于保存读取body中数据
    private  byte[] body;
    private String bodyMessage;
    public JsonParameterRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        //读取请求的数据保存到本类当中
        body = StreamUtil.readBytes(request.getReader(), "UTF-8");
        bodyMessage =  new String(body,"utf-8");
    }

    //覆盖(重写)父类的方法
    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }
    //覆盖(重写)父类的方法
    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream bais = new ByteArrayInputStream(body);
        return new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {

            }

            @Override
            public int read() throws IOException {
                return bais.read();
            }
        };
    }
    /**
     * 获取body中的数据
     * @return
     */
    public byte[] getBody() {
        return body;
    }
    /**
     * 把处理后的参数放到body里面
     * @param body
     */
    public void setBody(byte[] body) {
        this.body = body;
    }

    public String getBodyMessage() {
        return bodyMessage;
    }
}

第三步

java 复制代码
package com.xxx.init.webFilter.jsonWrapper;



import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.*;
import java.nio.charset.StandardCharsets;

/**
 * User:Json
 * Date: 2024/4/7
 **/
public class ResponseWrapper extends HttpServletResponseWrapper {
    private ByteArrayOutputStream byteArrayOutputStream;
    private ServletOutputStream servletOutputStream;

    /**
     * Constructs a response adaptor wrapping the given response.
     * @param response The response to be wrapped
     * @throws IllegalArgumentException if the response is null
     */
    public ResponseWrapper(HttpServletResponse response) throws IOException {
        super(response);
        byteArrayOutputStream = new ByteArrayOutputStream();
        servletOutputStream = new MyServletOutputStream(byteArrayOutputStream);
    }

    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        return servletOutputStream;
    }

    @Override
    public PrintWriter getWriter() throws IOException {
        return new PrintWriter(new OutputStreamWriter(byteArrayOutputStream, StandardCharsets.UTF_8));
    }

    @Override
    public void flushBuffer() {
        if (servletOutputStream != null) {
            try {
                servletOutputStream.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public byte[] getContent() {
        flushBuffer();
        // response中的数据
        return byteArrayOutputStream.toByteArray();
    }

    class MyServletOutputStream extends ServletOutputStream {
        // 把response输出流中的数据写入字节流中
        private ByteArrayOutputStream byteArrayOutputStream;

        public MyServletOutputStream(ByteArrayOutputStream byteArrayOutputStream) {
            this.byteArrayOutputStream = byteArrayOutputStream;
        }

        @Override
        public boolean isReady() {
            return false;
        }

        @Override
        public void setWriteListener(WriteListener listener) {
        }

        @Override
        public void write(int b) throws IOException {
            byteArrayOutputStream.write(b);
        }
    }
}

第五步:

java 复制代码
package com.xxx.init.utils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
/**
 * User:Json
 * Date: 2024/4/7
 **/
public class StreamUtil {

    public static byte[] readStream(InputStream stream,int length) throws IOException {
        byte[]streamData=null;
        List<Integer> lengths = new ArrayList<Integer>();
        List<byte[]> buffers = new ArrayList<byte[]>();
        int l = 0;  int totalLength = 0;  byte[] buffer = null; //
        while (totalLength < length && l != -1) { //
            buffer = new byte[length];
            l = stream.read(buffer);
            if (l != -1) {
                lengths.add(new Integer(l));
                buffers.add(buffer);
                totalLength+=l;
            }
        }
        if(totalLength==0) {
            return null;
        }
        l=0;
        streamData = new byte[totalLength];
        length =buffers.size();
        int blength=0;
        byte[] bbuffer=null;
        for (int i = 0; i < length; i++) {
            blength = ((Integer) lengths.get(i)).intValue();
            bbuffer = (byte[]) buffers.get(i);
            System.arraycopy(bbuffer, 0, streamData, l,blength);
            l=l+blength;
        }
        stream=null; lengths=null; buffers=null;	buffer=null;
        return streamData;
    }

    public static byte[] readBytes(BufferedReader bufferedReader, String charset) throws IOException{
        StringBuffer sb = new StringBuffer();
        String s;
        while ((s = bufferedReader.readLine()) != null) {
            sb.append(s);
        }
        if(sb.length() == 0){
            return "".getBytes(charset);
        }
        return sb.toString().getBytes(charset);
    }

}

第六步:

java 复制代码
package com.xxx.init.utils;

import javax.servlet.http.HttpServletRequest;

/**
 * User:Json
 * Date: 2024/4/7
 **/
public class WlUtils {

    /**
     * 判断是否是JSON请求
     * @param request
     * @return
     */
    public static Boolean isJsonReq(HttpServletRequest request){
        String header = request.getHeader("content-type");
        return header != null && header.toLowerCase().contains("json");
    }
}

测试

完美收工

相关推荐
Gain_chance9 小时前
34-学习笔记尚硅谷数仓搭建-DWS层最近一日汇总表建表语句汇总
数据仓库·hive·笔记·学习·datagrip
qq_124987075311 小时前
基于SSM的动物保护系统的设计与实现(源码+论文+部署+安装)
java·数据库·spring boot·毕业设计·ssm·计算机毕业设计
Coder_Boy_11 小时前
基于SpringAI的在线考试系统-考试系统开发流程案例
java·数据库·人工智能·spring boot·后端
Gain_chance11 小时前
35-学习笔记尚硅谷数仓搭建-DWS层最近n日汇总表及历史至今汇总表建表语句
数据库·数据仓库·hive·笔记·学习
2301_8187320611 小时前
前端调用控制层接口,进不去,报错415,类型不匹配
java·spring boot·spring·tomcat·intellij-idea
汤姆yu15 小时前
基于springboot的尿毒症健康管理系统
java·spring boot·后端
暮色妖娆丶15 小时前
Spring 源码分析 单例 Bean 的创建过程
spring boot·后端·spring
biyezuopinvip16 小时前
基于Spring Boot的企业网盘的设计与实现(任务书)
java·spring boot·后端·vue·ssm·任务书·企业网盘的设计与实现
JavaGuide16 小时前
一款悄然崛起的国产规则引擎,让业务编排效率提升 10 倍!
java·spring boot
figo10tf17 小时前
Spring Boot项目集成Redisson 原始依赖与 Spring Boot Starter 的流程
java·spring boot·后端