zoukankan      html  css  js  c++  java
  • 解决spring http输入流和输出流只能读取一次

    1.需求:给某些请求接口记录日志,记录请求的数据和响应的数据和请求所花费的时间。这里采用非侵入式编程,也业务代码进行解耦。按照spring AOP 的编程思想。

    2.编程设计:在spring 拦截器中植入日志代码。因为其刚好满足非侵入,且能捕获到请求和响应的数据。

    3.了解spring 拦截器和过滤器的运行原理

      先执行过滤器,然后执行拦截器。

    4. 分析:当在拦截器中获取请求的输入流和响应的输出流的时候发现,只能读取一次,拦截器在具体的业务代码之前执行,导致请求的输入流被拦截器使用,到controller 的时候将获取不到数据。当响应的数据流被拦截器的postHandler 使用之后,输出到客户端没有响应的数据。

      流程:先创建过滤器,过滤器是链式执行,配置的web.xml 的中。

      WrapperFilter  在web.xml 中的配置

      <filter>
        <filter-name>sosWrapperFilter</filter-name>
        <filter-class>com.xiao.handler.filter.WrapperFilter</filter-class>
      </filter>
      <filter-mapping>
        <filter-name>sosWrapperFilter</filter-name>
    <!-- 过滤的url地址 -->
    <url-pattern>/myTest/*</url-pattern> </filter-mapping>

     增加一个拦截器配置,配置需要过滤器的请求地址,走 spring mvc的拦截器,拦截的是请求地址(不包含上下文 eg:http://localost:8080/xiao)

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
           xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
           xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
                http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
                http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd
                http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
    
        <mvc:interceptors>
            <mvc:interceptor>
                <mvc:mapping path="/test/*"/>
                <bean class="com.xiao.interceptor.SosOrderInterceptor"/>
            </mvc:interceptor>
        </mvc:interceptors>
    
        
    </beans>

     开始编写过滤器,拦截器

    过滤器

    /**
     *
     * @describ  request 请求过滤器增强
     * @date 2019-03-06
     * @author coder_xiao
     */
    public class WrapperFilter implements  Filter  {
    
        private static Log log = LogFactory.getLog(WrapperFilter.class);
    
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
    
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            CacheContentRequestWrapper requestWrapper=null;
            CacheContentResponseWrapper responseWrapper=null;
            HttpServletRequest request=(HttpServletRequest)servletRequest;
            HttpServletResponse response=(HttpServletResponse) servletResponse;
            try {
                    requestWrapper = new CacheContentRequestWrapper(request);
                    responseWrapper = new CacheContentResponseWrapper(response);
           }catch (Exception e){
                log.error("获取requestWrapper失败!",e);
           }finally {
                if((requestWrapper!=null)&&(responseWrapper!=null)) {
                    filterChain.doFilter(requestWrapper, responseWrapper);
                    responseWrapper.reWriteResponse(responseWrapper,(HttpServletResponse) servletResponse);
                }else{
                    filterChain.doFilter(servletRequest, servletResponse);
                }
            }
    
        }
    
        @Override
        public void destroy() {
    
        }
    }

    拦截器

    public class SosOrderInterceptor implements HandlerInterceptor {
    
        private final static Log logger = LogFactory.getLog(SosOrderInterceptor.class);
    
    
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
            BufferedReader  bufferedInput=null;
            String  data=null;
            try{
                String urlPath=request.getRequestURI();
                String contentType=request.getContentType();
                Boolean typeIndex=contentType==null?false:contentType.indexOf("application/json")>-1;
                Boolean createIndex=urlPath.indexOf("createOrder")>-1;
                Boolean buildIndex=urlPath.indexOf("buildDraftOrder")>-1;
                Boolean urlIndex=(urlPath.indexOf("createSosOrder")+urlPath.indexOf("buildDraftSosOrder"))>-2;
                //POST 请求 contentType=application/json
                if(typeIndex&&urlIndex) {
                    //支持mark and reset 为使流复用
                    CacheContentRequestWrapper  contentRequestWrapper= new CacheContentRequestWrapper(request);
                    data = contentRequestWrapper.getBodyString();
                    String requestId=UUIDUtil.uuid();
                    request.setAttribute("requestId",requestId);
                    BuildAudit audit=BeanTool.getBean(BuildAudit.class);
                    //创建订单
                    if (createIndex) {
                        logger.info("开始调用创建订单");
                        audit.buildData(data,"1","1","创建订单",requestId);
                    }
                    //创建草稿
                    if (buildIndex) {
                        logger.info("创建草稿单!");
                        audit.buildData(data,"2","1","创建草稿单",requestId);
                    }
                }
            }catch (Exception e){
                e.printStackTrace();
                logger.error(e);
            }finally {
                if(bufferedInput!=null) {
                    bufferedInput.close();
                }
            }
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object o, ModelAndView modelAndView) throws Exception {
            logger.info("postHandle");
            try{
                String urlPath=request.getRequestURI();
                String contentType=request.getContentType();
                Boolean typeIndex=contentType==null?false:contentType.indexOf("application/json")>-1;
                Boolean createIndex=urlPath.indexOf("createOrder")>-1;
                Boolean buildIndex=urlPath.indexOf("buildDraftOrder")>-1;
                Boolean urlIndex=(urlPath.indexOf("createSosOrder")+urlPath.indexOf("buildDraftOrder"))>-2;
                String requestId=  request.getAttribute("requestId")==null?null:request.getAttribute("requestId").toString();
                if(typeIndex&&urlIndex) {
                    CacheContentResponseWrapper cacheResponse =(CacheContentResponseWrapper)((WebStatFilter.StatHttpServletResponseWrapper) response).getResponse();
                    String data=new String(cacheResponse.getResponseData(),"UTF-8");
                    BuildAudit audit=BeanTool.getBean(BuildAudit.class);
                    //创建订单
                    if (createIndex) {
                        audit.buildData(data,"1","2",null,requestId);
                    }
                    //创建草稿
                    if (buildIndex) {
                        audit.buildData(data,"2","2",null,requestId);
                    }
                    //草稿单转正
                    if (urlPath.indexOf("buildDraftSosOrder") > -1) {
    
                    }
                }
            }catch (Exception e){
                logger.error(e);
            }
        }
    
    
    
        @Override
        public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
            logger.info("afterCompletion");
            try{
    
            }catch (Exception ex){
                logger.error(ex);
            }
        }

    两个缓存器

    package com.lacesar.handler.wrapper;
    
    import java.io.BufferedReader;
    import java.io.ByteArrayInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    
    import javax.servlet.ReadListener;
    import javax.servlet.ServletInputStream;
    import javax.servlet.ServletRequest;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletRequestWrapper;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    
    /**
     * @description 包装spring 的 HttpServletRequestWrapper
     */
    public class CacheContentRequestWrapper extends HttpServletRequestWrapper {
    
        private static Log log = LogFactory.getLog(CacheContentRequestWrapper.class);
    
        /**
         * 存储body数据的容器
         */
        private final byte[] body;
    
        private String requestId;
    
        public CacheContentRequestWrapper(HttpServletRequest request) throws IOException {
            super(request);
            // 将body数据存储起来
            String bodyStr = getBodyString(request);
            body = bodyStr.getBytes("UTF-8");
        }
    
        /**
         * 获取请求Body
         *
         * @param request request
         * @return String
         */
        public String getBodyString(final ServletRequest request) {
            try {
                return inputStream2String(request.getInputStream());
            } catch (IOException e) {
                log.error("", e);
                throw new RuntimeException(e);
            }
        }
    
        /**
         * 获取请求Body
         *
         * @return String
         */
        public String getBodyString() {
            if (body != null) {
                final InputStream inputStream = new ByteArrayInputStream(body);
                return inputStream2String(inputStream);
            } else {
                return null;
            }
        }
    
        /**
         * 将inputStream里的数据读取出来并转换成字符串
         *
         * @param inputStream inputStream
         * @return String
         */
        private String inputStream2String(InputStream inputStream) {
            StringBuilder sb = new StringBuilder();
            BufferedReader reader = null;
    
            try {
                reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
                String line;
                while ((line = reader.readLine()) != null) {
                    sb.append(line);
                }
            } catch (IOException e) {
                log.error("", e);
                throw new RuntimeException(e);
            } finally {
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (IOException e) {
                        log.error("", e);
                    }
                }
            }
    
            return sb.toString();
        }
    
        public BufferedReader getReader() throws IOException {
            return new BufferedReader(new InputStreamReader(getInputStream()));
        }
    
        public ServletInputStream getInputStream() throws IOException {
    
            final ByteArrayInputStream inputStream = new ByteArrayInputStream(body);
    
            return new ServletInputStream() {
                public int read() throws IOException {
                    return inputStream.read();
                }
    
                public boolean isFinished() {
                    return false;
                }
    
                public boolean isReady() {
                    return false;
                }
    
                public void setReadListener(ReadListener readListener) {
                }
            };
        }
    
        public String getRequestId() {
            return requestId;
        }
    
        public void setRequestId(String requestId) {
            this.requestId = requestId;
        }
    }
    package com.lacesar.handler.wrapper;
    
    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.WriteListener;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpServletResponseWrapper;
    
    public class CacheContentResponseWrapper extends HttpServletResponseWrapper {
        private ByteArrayOutputStream buffer = null;
        private ServletOutputStream out = null;
        private PrintWriter writer = null;
    
        public CacheContentResponseWrapper(HttpServletResponse resp) throws IOException {
            super(resp);
            buffer = new ByteArrayOutputStream();
            out = new WapperedOutputStream(buffer);
            writer = new PrintWriter(new OutputStreamWriter(buffer, "UTF-8"));
        }
    
        /**
         * 重新写入response 数据
         *
         * @param wrapperResponse
         * @param response
         */
        public void reWriteResponse(CacheContentResponseWrapper wrapperResponse, HttpServletResponse response) {
            String result = null;
            try {
                result = new String(wrapperResponse.getResponseData(), "UTF-8");
                //解决可能在运行的过程中页面只输出一部分
                response.setContentLength(-1);
                response.setCharacterEncoding("UTF-8");
                PrintWriter out = null;
                out = response.getWriter();
                if (out != null) {
                    out.write(result);
                    out.flush();
                    out.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public ServletOutputStream getOutputStream() throws IOException {
            return out;
        }
    
        public PrintWriter getWriter() throws UnsupportedEncodingException {
            return writer;
        }
    
        public void flushBuffer() throws IOException {
            if (out != null) {
                out.flush();
            }
            if (writer != null) {
                writer.flush();
            }
        }
    
        public void reset() {
            buffer.reset();
        }
    
        public byte[] getResponseData() throws IOException {
            flushBuffer();
            return buffer.toByteArray();
        }
    
        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);
            }
    
            public boolean isReady() {
                return false;
            }
    
            public void setWriteListener(WriteListener writeListener) {
    
            }
        }
    }
  • 相关阅读:
    Silverlight“.NET研究” 2.5D RPG游戏技巧与特效处理:(七)动画特写 狼人:
    Silverlight 2.5D RPG游戏“.NET研究”技巧与特效处理:(六)流光追影 狼人:
    WPF中使用amCh“.NET研究”arts绘制股票K线图 狼人:
    验证.N“.NET研究”ET强命称的思路和实例 狼人:
    ASP.NET“.NET研究”下用URLRewriter重写二级域名 狼人:
    spring初始化在ServletContextListener实现类中获取spring注入对象
    执行原因【菜鸟笔记】Ubuntu系统shellscript中 关于for循环以及declare出错的原因
    jqueryfunctionchrome浏览器不支持 onmouseleave事件的解决
    异步线程C#异步委托的使用
    android删除android拦截短信并删除该条短信
  • 原文地址:https://www.cnblogs.com/blogxiao/p/10506115.html
Copyright © 2011-2022 走看看