SpringBoot 攔截器 統一日志 記錄用戶請求返回日志


你請求我接口,傳了什么參數,我返回了什么值給你,全部記下來。防止扯皮

需求:記錄每次用戶請求Controller的Body參數,

思路:在每個Controller 該當中記錄,容易漏記,如果在攔截器里面記的話,可以統一處理

問題:在postHandle 里面記,request.getInputStream() 取出來是空的,放在preHandle里面,就進不到 Controller 里面了。報:I/O error while reading input message; nested exception is java.io.IOException: Stream closed

原因:在攔截器已經讀取了請求體中的內容,這時候請求的流中已經沒有了數據,就是說HttpServletRequest請求體中的內容一旦讀取就不不存在了,所以直接讀取是不行的

方案:對httprequest進行修飾,自定義的包裝類來實現

添加 RequestLogFilter

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

 
@Component
@WebFilter(filterName = "requestLogFilter",urlPatterns = {"/*"}, 
initParams = {@WebInitParam(name = "ignoredUrl", value = ".css;.js;.jpg;.png;.gif;.ico;.html"),
@WebInitParam(name = "filterPath", value = "/user/login#/user/registerUser")}) public class RequestLogFilter implements OncePerRequestFilter { private Logger logger = LoggerFactory.getLogger(this.getClass()); @Override protected void doFilterInternal(HttpServletRequest servletRequest, HttpServletResponse servletResponse, FilterChain filterChain) throws ServletException, IOException { RequestLogWrapper requestWapper = null; if (servletRequest instanceof HttpServletRequest) { HttpServletRequest request = (HttpServletRequest) servletRequest; if (!request.getRequestURI().toLowerCase().contains("swagger")
&& !request.getRequestURI().toLowerCase().contains("upload")) { //排除swagger、上傳文件等接口 requestWapper
= new RequestLogWrapper(request); } } ResponseLogWrapper responseLogWrapper = new ResponseLogWrapper(servletResponse); //獲取請求中的流如何,將取出來的字符串,再次轉換成流,然后把它放入到新request對象中 // 在chain.doFiler方法中傳遞新的request對象 if (requestWapper == null) { filterChain.doFilter(servletRequest, servletResponse); } else { filterChain.doFilter(requestWapper, responseLogWrapper); } //打印返回響應日志 String result = new String(responseLogWrapper.getResponseData()); ServletOutputStream outputStream = servletResponse.getOutputStream(); outputStream.write(result.getBytes()); outputStream.flush(); outputStream.close(); String queryStr = StrUtil.isEmpty(servletRequest.getQueryString()) ? "" : "?" + servletRequest.getQueryString(); logger.info("{}{} Response =>\r\n{}", servletRequest.getRequestURI(), queryStr, result); } @Override public void destroy() { logger.info(">>>> RequestLogFilter destroy <<<<"); } }

 

 

添加 RequestLogWapper

import cn.hutool.core.util.StrUtil; 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;


public class RequestLogWrapper extends HttpServletRequestWrapper {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    private String requestBody;

    public String getRequestBody() {
        return requestBody;
    }

    public RequestLogWrapper(HttpServletRequest request) throws IOException {
        super(request);
        requestBody = getBodyString(request);
        String queryStr = StrUtil.isEmpty(request.getQueryString()) ? "" : "?" + request.getQueryString();
        logger.info("{}{}\r\n{}", request.getRequestURI(), queryStr, requestBody);
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(requestBody.getBytes(StandardCharsets.UTF_8));
        ServletInputStream servletInputStream = 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 byteArrayInputStream.read();
            }
        };
        return servletInputStream;
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    public String getBodyString(HttpServletRequest request) {
        StringBuilder sb = new StringBuilder();
        InputStream inputStream = null;
        BufferedReader reader = null;
        try {
            inputStream = request.getInputStream();
            reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
            String line = "";
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return sb.toString();
    }
}

 

ResponseLogWrapper

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


public class ResponseLogWrapper extends HttpServletResponseWrapper {


    private ByteArrayOutputStream buffer = null;//輸出到byte array
    private ServletOutputStream out = null;
    private PrintWriter writer = null;

    public ResponseLogWrapper(HttpServletResponse resp) throws IOException {
        super(resp);
        buffer = new ByteArrayOutputStream();// 真正存儲數據的流
        out = new WapperedOutputStream(buffer);
        writer = new PrintWriter(new OutputStreamWriter(buffer, this.getCharacterEncoding()));
    }

    /** 重載父類獲取outputstream的方法 */
    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        return out;
    }

    /** 重載父類獲取writer的方法 */
    @Override
    public PrintWriter getWriter() throws UnsupportedEncodingException {
        return writer;
    }

    /** 重載父類獲取flushBuffer的方法 */
    @Override
    public void flushBuffer() throws IOException {
        if (out != null) {
            out.flush();
        }
        if (writer != null) {
            writer.flush();
        }
    }

    @Override
    public void reset() {
        buffer.reset();
    }

    /** 將out、writer中的數據強制輸出到WapperedResponse的buffer里面,否則取不到數據 */
    public byte[] getResponseData() throws IOException {
        flushBuffer();
        return buffer.toByteArray();
    }

    /** 內部類,對ServletOutputStream進行包裝 */
    private class WapperedOutputStream extends ServletOutputStream {
        private ByteArrayOutputStream bos = null;

        public WapperedOutputStream(ByteArrayOutputStream stream) throws IOException {
            bos = stream;
        }

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

        @Override
        public void write(byte[] b) throws IOException {
            bos.write(b, 0, b.length);
        }

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

        @Override
        public void setWriteListener(WriteListener listener) {

        }
    }
}

 

 

 

參考資源:

https://www.jianshu.com/p/ba2d5101ad90

https://blog.csdn.net/qq_38132283/article/details/107685797


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM