首页 > 其他分享 >【转载】过滤器+spring拦截器处理服务请求日志打印

【转载】过滤器+spring拦截器处理服务请求日志打印

时间:2023-02-08 10:58:29浏览次数:48  
标签:body 拦截器 return spring request throws serviceAccessLog 日志 public

思路:通过拦截器拦截 HttpServletRequest请求,从请求对象中获取请求流,解析请求参数,封装对象打印请求参数日志

痛点:Request body只能读取一次,因为是流。想想看,java中的流也是只能读一次,因为读完之后,position就到末尾了。

解决思路:第一次读的时候,把流数据暂存起来。后面需要的时候,直接把暂存的数据返回出去。

一、自定义请求包装类

import jodd.io.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;



public class BodyReaderRequestWrapper extends HttpServletRequestWrapper {
    /**
     * 用于保存读取body中数据
     */
    private  byte[] body;

    public BodyReaderRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        //读取请求的数据保存到本类当中
        body = StreamUtil.readBytes(request.getReader());
    }

    /**
     * 覆盖(重写)父类的方法
     * @return
     * @throws IOException
     */
    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    /**
     * 覆盖(重写)父类的方法
     * @return
     * @throws IOException
     */
    @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;
    }
}

二.过滤器 重新包装 ServletRequest

public class AccessLogServiceFilter implements  Filter {
    /**
     * 做一层过滤重新包装,解决Request body只能读取一次的问题
     * @param request
     * @param servletResponse
     * @param filterChain
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        ServletRequest requestWrapper= null;
        //文件上传请求不做包装处理
        if(request instanceof HttpServletRequest && !ServletFileUpload.isMultipartContent((HttpServletRequest)request)){
            requestWrapper = new BodyReaderRequestWrapper((HttpServletRequest) request);
        }

        if(null == requestWrapper){
            filterChain.doFilter(request,servletResponse);
        }else{
            filterChain.doFilter(requestWrapper,servletResponse);
        }
    }
}

三.定义拦截器 做日志打印

@Slf4j
public class AccessLogServiceInterceptor implements HandlerInterceptor {

    private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) throws Exception {

        //请求包装
        if (req instanceof BodyReaderRequestWrapper){
            BodyReaderRequestWrapper request = (BodyReaderRequestWrapper) req;

            ServiceAccessLog serviceAccessLog = new ServiceAccessLog();
            serviceAccessLog.setRequestPath(request.getRequestURI());
            serviceAccessLog.setRequestMethod(request.getMethod());
            serviceAccessLog.setRequestTime(simpleDateFormat.format(new Date()));


            String contentType = request.getContentType();
            if (MediaType.APPLICATION_FORM_URLENCODED_VALUE.equals(contentType) || MediaType.APPLICATION_JSON_VALUE.equals(contentType)) {
                serviceAccessLog.setRequestBody(new String(request.getBody(), StandardCharsets.UTF_8));
            }else {
                writeBasicLog(req,serviceAccessLog);
            }
            //日志打印
            writeAccessLog(serviceAccessLog);
        }
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //响应参数打印 暂时不加
    }

    private void writeBasicLog(HttpServletRequest req,ServiceAccessLog serviceAccessLog ){
        serviceAccessLog.setRequestBody(req.getQueryString());
    }

    /**
     * 打印日志
     *
     * @param serviceAccessLog
     */
    private void writeAccessLog(ServiceAccessLog serviceAccessLog) {
        log.info(serviceAccessLog.toString());
    }

日志实体对象

/**
* 日志实体对象
*/
public class ServiceAccessLog {
    private String requestPath;
    private String requestMethod;
    private String requestBody;
    private String requestTime;
}

到此问题解决............

 

转载自 https://www.jianshu.com/p/9b6b194b9706

标签:body,拦截器,return,spring,request,throws,serviceAccessLog,日志,public
From: https://www.cnblogs.com/cplinux/p/17100942.html

相关文章