一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - SpringBoot攔截器讀取流后不能再讀取的問題

SpringBoot攔截器讀取流后不能再讀取的問題

2022-02-28 13:18YUNDONG丶 Java教程

這篇文章主要介紹了SpringBoot攔截器讀取流后不能再讀取的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

在SpringBoot的攔截器中通過流 ( request.getInputStream() ) 的方式讀取body中傳來的數據會導致controller接收不到值。

這個問題其實就是一個流讀取的問題,眾所周知在Java中input流只能讀取一次,主要原因是通標記的方法來判斷流是否讀取完畢(讀取位 -1就是流讀取完畢)

解決這個問題我能想到兩種方式

1.通過修改標記的方式 ( inputstream.markSupported() 方法可以判斷這個流是否支持 mark 和 reset 方法。他們分別是標記 和 重新定位流。)

2.將流賦值給一個 byte[] 數組,或者其他變量保存起來。下載讀取流時就調用這個數組就行。

第一種方法

再回到問題上來我們可以先使用第一種方法判斷 requet 中的inputStream 是否支持標記和重新定位。因為這種方式實現起來比較簡單。無需考慮太多。

?
1
2
3
4
5
6
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
         boolean b = request.getInputStream().markSupported();
         System.out.println(b);
    }
// 輸出結果為 false

上述代碼會返回一個 false 那么很明顯,request 中的 input 流是不支持標記和重新定位的。

第二種方法

我們再考慮第二種方法,我們需要一個變量保存這個流。并且還要保證再過濾器中和controller中都要拿到這個變量。直接定義一個全局變量獲取修改傳值方式,都是可以的。全局變量這種方式我就不演示了。

下面是改變傳值方式的 demo

?
1
2
3
4
5
6
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
        ServletInputStream inputStream1 = request.getInputStream();
        // 各種對 inputStream1 處理的操作...
        Object obejct = inputStream1;
        request.setAttribute("Params",obejct);
}

這樣就可以再controller那邊就可以直接獲取 Attribute 中的值。

但是!這樣有很大的局限性,例如: 我已經寫好了大多數的controller方法體。這時再改用這種方式傳值。對于開發人員是一種莫大的痛苦 -_- 于是通過不屑的百度查詢到另一種方法 一一一 改寫HttpServletRequestWrapper方法。為什么是這個方法?因為他實現了 HttpServletRequest 這個接口。也是我們攔截器接收的 request 要求的類型。首先我們先看一張圖。** 注意 filter 和 inteceptor 中間。 **

SpringBoot攔截器讀取流后不能再讀取的問題

通過上方這個圖我們可以知道,在 Filter 和 Inteceptor 中間有一層Servlet。而Servlet就是提交request的地方。所以我們要重寫HttpServletRequest方法只能在Servlet之前。也就是filter 中。下面就是直接上代碼了

1.重寫 HttpServletRequest

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package com.xqw.kyg.util;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.springframework.util.StreamUtils;
public class MyHttpServletRequestWrapper extends HttpServletRequestWrapper{
    private byte[] requestBody = null;//用于將流保存下來
    public MyHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        requestBody = StreamUtils.copyToByteArray(request.getInputStream());
    }
    @Override
    public ServletInputStream getInputStream() {
        final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody);
        return new ServletInputStream() {
            @Override
            public int read(){
                return bais.read();  // 讀取 requestBody 中的數據
            }
            @Override
            public boolean isFinished() {
                return false;
            }
            @Override
            public boolean isReady() {
                return false;
            }
            @Override
            public void setReadListener(ReadListener readListener) { }
        };
    }
    @Override
    public BufferedReader getReader() throws IOException{
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }
}

2.編寫Filter

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.xqw.kyg.filter;
import com.xqw.kyg.util.MyHttpServletRequestWrapper;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
@Component
public class HttpServletRequestReplacedFilter implements Filter {
    @Override
    public void destroy() {}
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {
        ServletRequest requestWrapper = null;
        if(request instanceof HttpServletRequest) {
            requestWrapper = new MyHttpServletRequestWrapper((HttpServletRequest) request);
        }
        if(requestWrapper == null) {
            chain.doFilter(request, response);
        } else {
            chain.doFilter(requestWrapper, response);
        }
    }
    @Override
    public void init(FilterConfig arg0) throws ServletException {}
}

到此代碼編寫就完成了。你現在可以在 過濾器 中讀取inputstream數據controller中也可以獲取到了。其實代碼并不是特別困難。主要是出現BUG能及時的想到原因,和提供解決方案。

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持服務器之家。

原文鏈接:https://blog.csdn.net/weixin_39933264/article/details/100181291

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 日本天堂视频在线观看 | 成成人看片在线 | 色综合综合 | chaopeng在线视频进入 | 爱情岛论坛亚洲一号路线 | 国产福利一区二区三区四区 | 99在线精品视频 | 免费真实播放国产乱子伦 | 99精品国产成人一区二区在线 | 国产视频一区二 | 国产午夜精品福利久久 | 欧美丰满大乳大屁在线观看股 | 免费看男人狂躁女人 | 免费标准高清看机机桶机机 | 精品久久久久免费极品大片 | 99国产成人精品2021 | 日本一区二区不卡久久入口 | 波多野结衣在线中文 | 精品国产在天天线在线麻豆 | 国产男女乱淫真视频全程播放 | 国产女主播在线播放一区二区 | 羞羞在线观看 | 成人激情 | 手机免费在线视频 | 美女污视频 | 无码区国产区在线播放 | 好大用力深一点女公交车 | 三级aaa黄特色 | 鸭子玩富婆流白浆视频 | 欧美人体高清在线观看ggogo | 加勒比成人 | 四虎欧美| 97青草 | 午夜国产精品福利在线观看 | 女教师的一级毛片 | 国产极品精频在线观看 | 色先锋av资源中文字幕 | 日本破处 | 成人欧美一区二区三区白人 | 特级非洲黑人一级毛片 | 日本一区二区三区在线 视频 |