springboot 日志打印完整json格式的请求参数

经常测试人员过来告诉你接口又又又又报错了, 有时小程序或其它客户端不好抓包,这时不如自己直接在后台日志中直接打印url 和json .但是springboot 的aop无法打印出入参的json ,这时首先想到的就是filter
中打印出入参, 但是会出现流只能读一次的尴尬情况.所以需要加一个wrapper 主要的功能能是让request可重复读. 增加如下2个类就可以实现功能了

新增一个filter

package com.bit.filter;

import com.bit.filter.wrapper.BodyReaderHttpServletRequestWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;

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

/**
 * 日志记录的filter
 */
@WebFilter(urlPatterns = "/*", filterName = "logFilter")
@Slf4j
public class LogFilter implements Filter {
     
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
     
        System.out.println("--------------logFilter 过滤器初始化------------");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
     
        // 防止流读取一次后就没有了, 所以需要将流继续写出去
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        ServletRequest requestWrapper = new BodyReaderHttpServletRequestWrapper(httpServletRequest);
        printRequest(requestWrapper);
        filterChain.doFilter(requestWrapper, servletResponse);
    }

    private void printRequest(ServletRequest servletRequest) {
     
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String uri = request.getRequestURI();
        String requestBody = "";
        String requestContentType = request.getHeader(HttpHeaders.CONTENT_TYPE);
        if (requestContentType != null) {
     
            //	只拦截 json 请求的参数
            if (requestContentType.startsWith(MediaType.APPLICATION_JSON_VALUE) || requestContentType.startsWith(MediaType.APPLICATION_XML_VALUE)) {
     
                requestBody = getRequestBody(request);
                log.info("请求开始 url ==={}", uri);
                log.info("请求开始 参数 ==={}", requestBody);
            }
        }
    }

    private String getRequestBody(HttpServletRequest request) {
     
        int contentLength = request.getContentLength();
        if (contentLength <= 0) {
     
            return "";
        }
        try {
     
            return IOUtils.toString(request.getReader());
        } catch (IOException e) {
     
            log.error("获取请求体失败", e);
            return "";
        }
    }

    @Override
    public void destroy() {
     
        System.out.println("--------------过滤器销毁------------");
    }

}

BodyReaderHttpServletRequestWrapper

package com.bit.filter.wrapper;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.Charset;

/**
 * @author mifei
 * @create 2020-06-23 13:16
 **/
public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
     
    private final byte[] body;

    public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
     
        super(request);
        String sessionStream = getBodyString(request);
        body = sessionStream.getBytes(Charset.forName("UTF-8"));
    }

    /**
     * 获取请求Body
     *
     * @param request
     * @return
     */
    public String getBodyString(final ServletRequest request) {
     
        StringBuilder sb = new StringBuilder();
        InputStream inputStream = null;
        BufferedReader reader = null;
        try {
     
            inputStream = cloneInputStream(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();
    }

    /**
     * Description: 复制输入流
     *
     * @param inputStream
     * @return
     */
    public InputStream cloneInputStream(ServletInputStream inputStream) {
     
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len;
        try {
     
            while ((len = inputStream.read(buffer)) > -1) {
     
                byteArrayOutputStream.write(buffer, 0, len);
            }
            byteArrayOutputStream.flush();
        } catch (IOException e) {
     
            e.printStackTrace();
        }
        InputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        return byteArrayInputStream;
    }

    @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 int read() throws IOException {
     
                return bais.read();
            }

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

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

            @Override
            public void setReadListener(ReadListener readListener) {
     
            }
        };
    }
}

参考

https://blog.csdn.net/shangrila_kun/article/details/89308766
springMVC拦截器从Request中获取Json格式并解决request的请求流只能读取一次的问题_菜鸟sdut的博客-CSDN博客_request中的数据获取一次就没有了
https://blog.csdn.net/sdut406/article/details/81369983

解决:Spring boot系统请求/响应参数打印_代码实现_春风化雨-CSDN博客_springboot 打印请求参数
https://blog.csdn.net/jiahao1186/article/details/91870776

你可能感兴趣的:(springboot)