• 转载-Spring Boot之 Filter(示例:打印request、response日志)


    网上有很多采用spring filter机制打印request/response日志的博客, 大都不能很好工作, 下面这个博客写的不错.

    https://blog.csdn.net/jy02268879/article/details/84243950

    作者用到了下面两个第三方库, 其中 apache lang3 的 StringUtils 可以使用 Hutool 库代替.  jodd 库是一个非常优秀的工具包.

    • import jodd.io.StreamUtil;
    • import org.apache.commons.lang3.StringUtils;

    pom.xml 引入对应的 jodd-core 包.

                <dependency>
                    <groupId>org.jodd</groupId>
                    <artifactId>jodd-core</artifactId>
                    <version>${jodd.all.version}</version>
                </dependency>

    下面内容摘自  https://blog.csdn.net/jy02268879/article/details/84243950

    ===========================================

    Filter(过滤器)

    ===========================================
    一个请求可以被多个过滤器拦截到,会依次进入各个Filter中,放行后直至进入Servlet,Servlet处理请求结束后,回到各个Filter继续执行后面的代码,先执行的Filter,后执行完(Filter是个栈结构,先进后出)。

    例如:这里有5个filter: A,B,C,D,E

    执行filter的前置处理的顺利是A,B,C,D,E

    那么执行filter的后置处理的顺序是E,D,C,B,A

    一个请求进来以后的执行顺序:

    Filter前置处理---->Interceptor(拦截器)前置处理---->正常的controller处理---->Interceptor后置处理---->Filter后置处理

    ===========================================
    一.用@WebFilter注册过滤器

    ===========================================

    ---------------------------------------------------------
     1.实现filter接口,或者继承filter的实现类, 

    ---------------------------------------------------------

    RequestFilter.java 继承OncePerRequestFilter确保一次请求只通过一次该filter

    换言之一次请求不会通过两次RequestFilter,一次请求不会重复执行自定义RequestFilter中的doFilterInternal方法

    package com.sid.util.LogRequestResponse;
     
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.core.annotation.Order;
    import org.springframework.web.filter.OncePerRequestFilter;
     
    import javax.servlet.*;
    import javax.servlet.annotation.WebFilter;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.BufferedReader;
    import java.io.IOException;
     
    /**
     * @program: springboot
     * @description:
     * @author: Sid
     * @date: 2018-11-19 09:21
     * @since: 1.0
     **/
    @Order(0)
    /**
     * 注册过滤器
     * */
    @WebFilter(filterName = "RequestResponseLogFilter", urlPatterns = "/*")
    public class RequestFilter extends OncePerRequestFilter {
        private static final Logger logger = LoggerFactory.getLogger(RequestFilter.class);
     
        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
            String path = request.getQueryString();
            String servletPath = request.getServletPath();
            String url = request.getRequestURI();
            RequestWrapper requestWrapper = null;
     
     
            StringBuilder sb = new StringBuilder();
            if (request instanceof HttpServletRequest) {
                requestWrapper = new RequestWrapper(request);
                    BufferedReader bufferedReader = requestWrapper.getReader();
                    String line;
                    while ((line = bufferedReader.readLine()) != null) {
                        sb.append(line);
                    }
            }
     
            ResponseWrapper responseWrapper=new ResponseWrapper( response);
     
            if (null == requestWrapper) {
                filterChain.doFilter(request, response);
            } else {
                filterChain.doFilter(requestWrapper, responseWrapper);
            }
            logger.info("========================》  url:" + url + " & queryString:" + path+" & servletPath:"+servletPath);
            logger.info("========================》request uri: {}",request.getRequestURI());
            logger.info("========================》request ContentType: {}",request.getContentType());
            logger.info("========================》request param: {}",sb.toString());
     
            logger.info("========================》response status: {}",response.getStatus());
            logger.info("========================》response ContentType: {}",response.getContentType());
     
     
            String result=new String(responseWrapper.getResponseData());
            ServletOutputStream outputStream = response.getOutputStream();
            outputStream.write(result.getBytes());
            outputStream.flush();
            outputStream.close();
            // 打印response
            logger.info("========================》response return data: {} 	" + result);
     
        }
     
    } 



    ---------------------------------------------------------
     2.在spring-boot启动类上加注解@ServletComponentScan
     ---------------------------------------------------------
     

    @SpringBootApplication
    @ServletComponentScan
    public class App {
        public static void main(String[] args) {
            SpringApplication.run(App.class, args);
        }
    }


     ===========================================
     二、用FilterRegistrationBean注册过滤器

    ===========================================

    RequestFilterConfiguration.java

    package com.sid.util.LogRequestResponse;
     
    import org.springframework.boot.web.servlet.FilterRegistrationBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
     
    /**
     * @program: springboot
     * @description:
     * @author: Sid
     * @date: 2018-11-19 13:48
     * @since: 1.0
     **/
    @Configuration
    public class RequestFilterConfiguration {
        @Bean
        public FilterRegistrationBean authFilterRegistrationBean() {
            FilterRegistrationBean registration = new FilterRegistrationBean();
            registration.setFilter(new RequestFilter()); //设置自定义的Filter
            registration.addUrlPatterns("/*");  //设置过滤路径
            registration.setName("RequestFilter"); //设置过滤器名称
            registration.setOrder(1);   //设置过滤器顺序
            //registration.addInitParameter("paramName", "paramValue");  //设置初始化参数 这里不用
            return registration;
        }
    } 


    ----------------------------------------------------
    RequestWrapper的实现

    ----------------------------------------------------

    package com.sid.util.LogRequestResponse;
     
    import jodd.io.StreamUtil;
    import org.apache.commons.lang3.StringUtils;
     
    import java.io.*;
    import java.nio.charset.Charset;
    import java.util.Enumeration;
     
    import javax.servlet.ReadListener;
    import javax.servlet.ServletInputStream;
    import javax.servlet.ServletRequest;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletRequestWrapper;
     
     
    /**
     * @program: springboot
     * @description:
     * @author: Sid
     * @date: 2018-11-19 12:54
     * @since: 1.0
     **/
    public class RequestWrapper extends HttpServletRequestWrapper {
        private final byte[] body;
     
        /**
         * 这个必须加,复制request中的bufferedReader中的值
         * @param request
         * @throws IOException
         */
        public RequestWrapper(HttpServletRequest request) throws IOException {
            super(request);
            body = getBodyString(request);
        }
     
        /**
         * 获取请求Body
         *
         * @param request
         * @return
         */
        public byte[] getBodyString(final ServletRequest request) throws IOException {
            String contentType = request.getContentType();
            String bodyString ="";
     
            if (StringUtils.isNotBlank(contentType) && (contentType.contains("multipart/form-data") || contentType.contains("x-www-form-urlencoded"))){
     
                Enumeration<String> pars=request.getParameterNames();
     
                while(pars.hasMoreElements()){
     
                    String n=pars.nextElement();
     
                    bodyString+=n+"="+request.getParameter(n)+"&";
     
                }
     
                bodyString=bodyString.endsWith("&")?bodyString.substring(0, bodyString.length()-1):bodyString;
     
                return bodyString.getBytes(Charset.forName("UTF-8"));
     
            }else {
     
                return StreamUtil.readBytes(request.getReader(), "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 listener) {
     
                }
     
                @Override
                public int read() throws IOException {
                    return bais.read();
                }
            };
        }
    } 

    ----------------------------------------------------
    ResponseWrapper的实现

    ----------------------------------------------------

    package com.sid.util.LogRequestResponse;
     
    import javax.servlet.WriteListener;
    import javax.servlet.http.HttpServletResponseWrapper;
     
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.OutputStreamWriter;
    import java.io.PrintWriter;
    import java.io.UnsupportedEncodingException;
     
    import javax.servlet.ServletOutputStream;
    import javax.servlet.http.HttpServletResponse;
     
    /**
     * @program: springboot
     * @description:
     * @author: Sid
     * @date: 2018-11-19 11:55
     * @since: 1.0
     **/
    public class ResponseWrapper extends HttpServletResponseWrapper {
        /**
         * This class implements an output stream in which the data is written into a byte array.
         * The buffer automatically grows as data is written to it. The data can be retrieved using toByteArray() and toString().
         Closing a ByteArrayOutputStream has no effect. The methods in this class can be called after the stream has been closed without generating an IOException.
         */
        private ByteArrayOutputStream buffer = null;//输出到byte array
        private ServletOutputStream out = null;
        private PrintWriter writer = null;
     
        public ResponseWrapper(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) {
     
            }
        }
    } 
  • 相关阅读:
    poj 1860 Currency Exchange(最短路径的应用)
    poj 2965 The Pilots Brothers' refrigerator
    zoj 1827 the game of 31 (有限制的博弈论)
    poj 3295 Tautology (构造法)
    poj 1753 Flip Game(枚举)
    poj 2109 (贪心)
    poj 1328(贪心)
    Qt 对单个控件美化
    Qt 4基础
    Bash Shell
  • 原文地址:https://www.cnblogs.com/harrychinese/p/SpringBoot_Filter.html
Copyright © 2020-2023  润新知