• ServletRequest中getReader()和getInputStream()只能调用一次的解决办法


    转载:http://blog.sina.com.cn/s/blog_870cd7b90101fg58.html

    最近使用spring mvc做项目,数据格式是json,有一个功能是实现记录请求的参数,而请求的参数是整个RequestBody,Controller里是用过@RequestBody获取的。实现方法是通过一个Filter读取整个RequestBody并记录。但是这时就遇到一个问题,ServletRequest的getReader()和getInputStream()两个方法只能被调用一次,而且不能两个都调用。那么如果Filter中调用了一次,在Controller里面就不能再调用了。查看了下ServletRequest的说明,如下:

    Java代码
    1. public ServletInputStream getInputStream() throws IOException;
    2. public BufferedReader getReader() throws IOException;



    两个方法都注明方法只能被调用一次,由于RequestBody是流的形式读取,那么流读了一次就没有了,所以只能被调用一次。既然是因为流只能读一次的原因,那么只要将流的内容保存下来,就可以实现反复读取了。

    实现方法:先将RequestBody保存为一个byte数组,然后通过Servlet自带的HttpServletRequestWrapper类覆盖getReader()和getInputStream()方法,使流从保存的byte数组读取。然后再Filter中将ServletRequest替换为ServletRequestWrapper。代码如下:

    BodyReaderHttpServletRequestWrapper类包装ServletRequest,将流保存为byte[],然后将getReader()和getInputStream()方法的流的读取指向byte[]

    Java代码
    1. import java.io.BufferedReader;
    2. import java.io.ByteArrayInputStream;
    3. import java.io.IOException;
    4. import java.io.InputStreamReader;
    5. import javax.servlet.ServletInputStream;
    6. import javax.servlet.http.HttpServletRequest;
    7. import javax.servlet.http.HttpServletRequestWrapper;
    8. import jodd.JoddDefault;
    9. import jodd.io.StreamUtil;
    10. public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
    11. private final byte[] body;
    12. public BodyReaderHttpServletRequestWrapper(HttpServletRequest request)
    13. throws IOException {
    14. super(request);
    15. body = StreamUtil.readBytes(request.getReader(), JoddDefault.encoding);
    16. }
    17. @Override
    18. public BufferedReader getReader() throws IOException {
    19. return new BufferedReader(new InputStreamReader(getInputStream()));
    20. }
    21. @Override
    22. public ServletInputStream getInputStream() throws IOException {
    23. final ByteArrayInputStream bais = new ByteArrayInputStream(body);
    24. return new ServletInputStream() {
    25. @Override
    26. public int read() throws IOException {
    27. return bais.read();
    28. }
    29. };
    30. }
    31. }



    在Filter中将ServletRequest替换为ServletRequestWrapper

    Java代码
      1. public class HttpServletRequestReplacedFilter implements Filter {
      2. @Override
      3. public void init(FilterConfig filterConfig) throws ServletException {
      4. //Do nothing
      5. }
      6. @Override
      7. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {
      8. ServletRequest requestWrapper = null;
      9. if(request instanceof HttpServletRequest) {
      10. requestWrapper = new BodyReaderHttpServletRequestWrapper((HttpServletRequest) request);
      11. }
      12. if(null == requestWrapper) {
      13. chain.doFilter(request, response);
      14. } else {
      15. chain.doFilter(requestWrapper, response);
      16. }
      17. }
      18. @Override
      19. public void destroy() {
      20. //Do nothing
      21. }
      22. }
  • 相关阅读:
    js压缩、混淆和加密 Alan
    与、或、异或运算 Alan
    Hello world Alan
    abstract class和interface有什么区别?
    接口是否可继承接口? 抽像类是否可实现(implements)接口? 抽像类是否可继承实体类(concrete class)?
    启动一个线程是用run()还是start()?
    数组有没有length()这个方法? String有没有length()这个方法?
    swtich是否能作用在byte上,是否能作用在long上,是否能作用在String上?
    当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法?
    简要谈一下您对微软.NET 构架下remoting和webservice两项技术的理解以及实际中的应用。
  • 原文地址:https://www.cnblogs.com/wenlj/p/4900977.html
Copyright © 2020-2023  润新知