zoukankan      html  css  js  c++  java
  • 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. }
  • 相关阅读:
    JVM内存区域类别
    ConcurrentHashMap初探
    一张图理解RACSignal的Subscription过程
    ObjC的Block中使用weakSelf/strongSelf @weakify/@strongify
    自己写简单CoreDataManager封装对CoreData操作
    [转]layoutSubviews总结
    [转]日期格式化(yyyy-MM-dd)中,为什么 M 多大写?
    Native App执行JS
    Mac下配置Maven
    Mac OS X中配置Apache
  • 原文地址:https://www.cnblogs.com/wenlj/p/4900977.html
Copyright © 2011-2022 走看看