Request多次调用InpuStream

本文介绍了一种在Spring MVC框架中实现可重复读取HTTP请求Body的方法,通过自定义包装类和过滤器,解决了Request中getReader()和getInputStream()只能调用一次的问题,适用于需要多次读取请求数据的场景。
摘要由CSDN通过智能技术生成
Request中getReader()和getInputStream()只能调用一次,构建可重复读取inputStream的request
  1. 添加RepeatedlyReadRequestWrapper 类并继承 HttpServletRequestWrapper 包装类
package net.dotclouds.requestconfig;

import org.apache.commons.lang3.StringUtils;

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;
import java.nio.charset.Charset;

/**
 * Created by mayn on 2018/8/7.
 */
public class RepeatedlyReadRequestWrapper extends HttpServletRequestWrapper {
    private final byte[] body;

    public RepeatedlyReadRequestWrapper(HttpServletRequest request)
            throws IOException {
        super(request);
        body = 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();
            }
        };
    }

    /**
     * 通过BufferedReader和字符编码集转换成byte数组
     * @param br
     * @param encoding
     * @return
     * @throws IOException
     */
    private byte[] readBytes(BufferedReader br, String encoding) throws IOException{
        String str = null,retStr="";
        while ((str = br.readLine()) != null) {
            retStr += str;
        }
        if (StringUtils.isNotBlank(retStr)) {
            return retStr.getBytes(Charset.forName(encoding));
        }
        return null;
    }
}

  1. 添加 RepeatedlyReadFilter 实现 filter 过滤器接口方法,当客户端的请求先 过滤 进入SpringMvc Dispatch 路由前先包装下
package net.dotclouds.filter;

import net.dotclouds.requestconfig.RepeatedlyReadRequestWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
 * 复制请求数据包body
 * 以提供 拦截器下 可数次获取Body数据包
 * @author huanglj
 * @createTime 2018/8/7 11:24
 * @version v1.0
 */
public class RepeatedlyReadFilter implements Filter {
    private Logger log = LoggerFactory.getLogger(getClass());

    public void init(FilterConfig filterConfig) throws ServletException {

    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        log.debug("========复制request.getInputStream流=======");
        ServletRequest requestWrapper = null;
        if (request instanceof HttpServletRequest) {
            requestWrapper = new RepeatedlyReadRequestWrapper((HttpServletRequest) request);
        }
        if (null == requestWrapper) {
            chain.doFilter(request, response);
        } else {
            chain.doFilter(requestWrapper, response);
        }
    }
    public void destroy() {

    }
}

  1. 配置过滤器与拦截器 WebMvcConfig
package net.dotclouds.interceptor;

import net.dotclouds.filter.RepeatedlyReadFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.*;

/**
 * Created by Administrator on 2017/4/17.
 */
@Configuration
@EnableWebMvc
@ComponentScan
public class MyWebAppConfigurer extends WebMvcConfigurerAdapter {

    static final private String FAVICON_URL = "/favicon.ico";
    static final private String PROPERTY_APP_ENV = "application.environment";
    static final private String PROPERTY_DEFAULT_ENV = "dev";
    /**
     * 发现如果继承了WebMvcConfigurationSupport,则在yml中配置的相关内容会失效。
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/").addResourceLocations("/**");
        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
    }
    /**
     * 配置servlet处理
     */
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        MyInterceptor myInterceptor = new MyInterceptor();
        //配置拦截器
        registry.addInterceptor(myInterceptor).addPathPatterns("/**");
        super.addInterceptors(registry);
    }
    @Bean
    public FilterRegistrationBean repeatedlyReadFilter() {
    	//过滤器
        FilterRegistrationBean registration = new FilterRegistrationBean();
        RepeatedlyReadFilter repeatedlyReadFilter = new RepeatedlyReadFilter();
        registration.setFilter(repeatedlyReadFilter);
        registration.addUrlPatterns("/*");
        registration.setOrder(1);
        return registration;
    }
}
  1. 添加拦截器 MyInterceptor 继承 HandlerInterceptorAdapter 拦截适配器
package net.dotclouds.interceptor;

import com.alibaba.fastjson.JSON;
import net.dotclouds.common.CloudBasisEnum;
import net.dotclouds.model.ResultStatus;
import net.dotclouds.requestconfig.RepeatedlyReadRequestWrapper;
import net.dotclouds.util.EncryptionUtil;
import net.dotclouds.util.MapUtil;
import net.dotclouds.util.ResultHelperUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StopWatch;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import net.dotclouds.common.Constants;

import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.*;
import java.nio.charset.Charset;
import java.util.Map;

/**
 * Created by Administrator on 2017/4/14.
 */
public class MyInterceptor implements HandlerInterceptor{

    private Logger log = LoggerFactory.getLogger(getClass());

    private static ThreadLocal<StopWatch> stopWatchLocal = new ThreadLocal<StopWatch>();

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{
        StopWatch stopWatch = new StopWatch(handler.toString());
        stopWatchLocal.set(stopWatch);
        stopWatch.start(handler.toString());
        String urlString = request.getRequestURL().toString();
        //校验是否包含此路径
        if(!urlString.contains("/login")
                &&!urlString.contains("/logoff")
                &&urlString.contains("/v")){
            // 校验session是否已经登录
            HttpSession session = request.getSession();
            Object name = session.getAttribute(Constants.Other.CUSTOMER_MODEL);
            //TODO 测试
            System.out.println("获取Session:"+JSON.toJSONString(name)+"_周期为:"+session.getMaxInactiveInterval());
            // 用户已经登录 判断后端用户
            if(name != null){
                return true;
            } else {
                boolean checkSgin = checkSgin(request,response);
                if(checkSgin)
                    return true;
            }
            returnJson(response);
            return false;
        }
        RepeatedlyReadRequestWrapper requestWrapper;
        if (request instanceof RepeatedlyReadRequestWrapper) {
            // 签名处理过程 start....
            requestWrapper = (RepeatedlyReadRequestWrapper) request;
            log.info("请求Body: {} ", getBodyString(requestWrapper));
            // 签名处理过程 end....
        }
        //checkSgin(request,response);
        return true;
    }

    public  void postHandle(HttpServletRequest request, HttpServletResponse var2, Object var3, ModelAndView var4) throws Exception{
        RepeatedlyReadRequestWrapper requestWrapper;
        if (request instanceof RepeatedlyReadRequestWrapper) {
            // 签名处理过程 start....
            requestWrapper = (RepeatedlyReadRequestWrapper) request;
            log.info("再次请求Body: {} ", getBodyString(requestWrapper));
            // 签名处理过程 end....
        }
    }

    public void afterCompletion(HttpServletRequest var1, HttpServletResponse var2, Object var3, Exception var4) throws Exception{
    }

    private void returnJson(HttpServletResponse response) throws Exception{
        PrintWriter writer = null;
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        try {
            ResultStatus result = new ResultStatus();
            ResultHelperUtil.setFail(result, CloudBasisEnum.LOGIN_OVERTIME.getMsg());
            writer = response.getWriter();
            writer.write(JSON.toJSONString(result));
        } catch (IOException e) {
            log.error("response error",e);
        } finally {
            if (writer != null)
                writer.close();
        }
    }

    public boolean checkSgin(HttpServletRequest request,HttpServletResponse response) throws IOException {
        BufferedReader reader = request.getReader();
        String sgin = "";
        String sginTime = "";
        StringBuilder sub = new StringBuilder();
        String str = "";
        while ((str=reader.readLine())!=null){
            sub.append(str);
        }
        if(StringUtils.isNoneBlank(str)){
            Map<String,Object> map = JSON.parseObject(str, Map.class);
             sgin = MapUtil.getStringValue(map,"sgin");
             sginTime = MapUtil.getStringValue(map,"sginTime");
        }

        if(StringUtils.isBlank(sgin)||StringUtils.isBlank(sginTime))
            return false;
        if(StringUtils.isBlank(sgin)
                ||StringUtils.isBlank(sginTime)
                ||!EncryptionUtil.unSgin(sgin,sginTime)){
            PrintWriter writer = null;
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/json; charset=utf-8");
            try {
                ResultStatus result = new ResultStatus();
                result.setCode(CloudBasisEnum.NOT_JURISDICTION.getCode());
                result.setMsg(CloudBasisEnum.NOT_JURISDICTION.getMsg());
                writer = response.getWriter();
                writer.write(JSON.toJSONString(result));
            } catch (IOException e) {
                log.error("response error",e);
            } finally {
                if (writer != null)
                    writer.close();
            }
            return false;
        }
        return true;
    }

    /**
     * 获取请求Body
     *
     * @param request
     *
     * @return
     */
    public static 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();
                    inputStream = null;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (reader != null) {
                try {
                    reader.close();
                    reader = null;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return sb.toString();
    }

    public static InputStream cloneInputStream(ServletInputStream inputStream) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len;
        InputStream byteArrayInputStream = null;
        try {
            while ((len = inputStream.read(buffer)) > -1) {
                byteArrayOutputStream.write(buffer, 0, len);
            }
            byteArrayOutputStream.flush();
            byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != byteArrayOutputStream) {
                    byteArrayOutputStream.close();
                    byteArrayOutputStream = null;
                }
            } catch (Exception e){
                e.printStackTrace();
            }
        }
        return byteArrayInputStream;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值