欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot過濾器如何獲取POST請求的JSON參數(shù)

 更新時間:2021年08月28日 11:09:17   作者:Lpepsi  
這篇文章主要介紹了SpringBoot過濾器如何獲取POST請求的JSON參數(shù)操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

SpringBoot過濾器獲取POST請求的JSON參數(shù)

項目中需要將每個請求的路徑和請求參數(shù)以及響應(yīng)結(jié)果,都記錄在日志中,這樣在出現(xiàn)問題時可以快速定位是哪里出現(xiàn)了問題。

想到了使用過濾器來實現(xiàn)這個功能

當請求來到過濾器時,會有一個Request參數(shù),通過該參數(shù)就能獲取到請求路徑和請求參數(shù),以及相關(guān)內(nèi)容

parameterMap = httpRequest.getParameterMap();
String requestMethod = httpRequest.getMethod();
String remoteAddr = httpRequest.getRemoteAddr();
int remotePort = httpRequest.getRemotePort();

上面的getParameterMap(),只能夠獲取到GET請求的參數(shù),如果是POST方法傳的JSON那就沒法獲取到,那如何獲取呢,POST的請求是在請求體body中,而POST請求中的body參數(shù)是已流形式存在的

所以我們可以通過獲取到輸入流來獲取body

ServletInputStream inputStream = httpRequest.getInputStream();
InputStreamReader reader = new InputStreamReader(inputStream,StandardCharsets.UTF_8);
BufferedReader bfReader = new BufferedReader(reader);
StringBuilder sb = new StringBuilder();
String line;
while ((line = bfReader.readLine()) != null){
sb.append(line);
}
System.out.println(sb.toString());

通過上面的方法,我們確實能在過濾器中獲取到POST的JSON參數(shù)了,但是按照上面的方法實現(xiàn)的過濾器,我們會發(fā)現(xiàn),當請求經(jīng)過過濾器來到Controller的時候,請求參數(shù)不見了

image-20201219133609844

可以看到,過濾器確實拿到JSON參數(shù),但是接著報了一個request body missing的異常,也就是請求來到Controller時,參數(shù)沒有了,這是為啥呢?我們先去源碼看看,Controller平時是怎么拿到請求參數(shù)的吧

image-20201219134042794

根據(jù)DeBug,可以看到SpringBoot處理請求的最主要的兩個方法是上圖紅框的doServicedoDisparch方法,上面就是通過反射去獲取參數(shù)名去匹配等

來到invokeForRequest方法,這里面的getMethodArgumentValues,就是SpringBoot獲取請求參數(shù)的入口,進入入口后

image-20201219135249418

再經(jīng)過上面的紅框,就能看到SpringBoot獲取POST請求JSON的參數(shù)的真面目了

image-20201219135426586

從源碼我們可以看到

SpringBoot也是通過獲取request的輸入流來獲取參數(shù),這樣上面的疑問就能解開了,為什么經(jīng)過過濾器來到Controller請求參數(shù)就沒了,這是因為 InputStream read方法內(nèi)部有一個,postion,標志當前流讀取到的位置,每讀取一次,位置就會移動一次,如果讀到最后,InputStream.read方法會返回-1,標志已經(jīng)讀取完了,如果想再次讀取,可以調(diào)用inputstream.reset方法,position就會移動到上次調(diào)用mark的位置,mark默認是0,所以就能從頭再讀了。但是呢 是否能reset又是由markSupported決定的,為true能reset,為false就不能reset,從源碼可以看到,markSupported是為false的,而且一調(diào)用reset就是直接異常

image-20201219140007286

所以這也就代表,InputStream只能被讀取一次,后面就讀取不到了。因此我們在過濾器的時候,已經(jīng)將InputStream讀取過了一次,當來到Controller,SpringBoot讀取InputStream的時候自然是什么都讀取不到了

image-20201219140830451

既然InputStream只能讀取一次,那我們可以把InputStream給保存下來,然后完整的傳下去SpringBoot就可以讀取到了,這里就需要用到HttpServletRequest的包裝類HttpServletRequestWrapper了,該類可以自定義一些方法

我們創(chuàng)建一個類并繼承這個包裝類

public class RequestWrapper extends HttpServletRequestWrapper {
    private final byte[] body;
    public RequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        //保存一份InputStream,將其轉(zhuǎn)換為字節(jié)數(shù)組
        body = StreamUtils.copyToByteArray(request.getInputStream());
    }
	//轉(zhuǎn)換成String
    public String getBodyString(){
        return new String(body,StandardCharsets.UTF_8);
    }
    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }
	//把保存好的InputStream,傳下去
    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream bais = new ByteArrayInputStream(body);
        return new ServletInputStream() {
            @Override
            public int read() throws IOException {
                return bais.read();
            }
            @Override
            public boolean isFinished() {
                return false;
            }
            @Override
            public boolean isReady() {
                return false;
            }
            @Override
            public void setReadListener(ReadListener readListener) {
            }
        };
    }
}

通過保存一份流,就可實現(xiàn)在過濾器中能拿到JSON參數(shù),同時Controller也不會丟失參數(shù)

image-20201219141929107

有一點需要注意的

在過濾器放行的時候,放行的是包裝類和而不是原來的Request

image-20201219142124831

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Spring Schedule Task動態(tài)改寫Cron配置方式

    Spring Schedule Task動態(tài)改寫Cron配置方式

    這篇文章主要介紹了Spring Schedule Task動態(tài)改寫Cron配置方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Java如何批量執(zhí)行datax腳本

    Java如何批量執(zhí)行datax腳本

    這篇文章主要介紹了Java如何批量執(zhí)行datax腳本問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-02-02
  • Java從JDK源碼角度對Object進行實例分析

    Java從JDK源碼角度對Object進行實例分析

    這篇文章主要介紹了Java從JDK源碼角度對Object進行實例分析,具有一定借鑒價值,需要的朋友可以參考下。
    2017-12-12
  • Maven中兩個命令clean 和 install的使用

    Maven中兩個命令clean 和 install的使用

    Maven是一個項目管理和自動構(gòu)建工具,clean命令用于刪除項目中由先前構(gòu)建生成的target目錄,install命令用于將打包好的jar包安裝到本地倉庫中,供其他項目依賴使用,下面就來詳細的介紹一下這兩個命令
    2024-09-09
  • Spring Security  整體架構(gòu)操作流程

    Spring Security  整體架構(gòu)操作流程

    這篇文章主要介紹了Spring Security  整體架構(gòu)操作流程,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2024-07-07
  • 集群環(huán)境中使用ehcache_動力節(jié)點Java學(xué)院整理

    集群環(huán)境中使用ehcache_動力節(jié)點Java學(xué)院整理

    這篇文章主要為大家詳細介紹了集群環(huán)境中使用ehcache的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • Java如何用時間戳重命名上傳的文件

    Java如何用時間戳重命名上傳的文件

    這篇文章主要介紹了Java如何用時間戳重命名上傳的文件問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • 學(xué)習(xí)不同 Java.net 語言中類似的函數(shù)結(jié)構(gòu)

    學(xué)習(xí)不同 Java.net 語言中類似的函數(shù)結(jié)構(gòu)

    這篇文章主要介紹了學(xué)習(xí)不同 Java.net 語言中類似的函數(shù)結(jié)構(gòu),函數(shù)式編程語言包含多個系列的常見函數(shù)。但開發(fā)人員有時很難在語言之間進行切換,因為熟悉的函數(shù)具有不熟悉的名稱。函數(shù)式語言傾向于基于函數(shù)范例來命名這些常見函數(shù)。,需要的朋友可以參考下
    2019-06-06
  • Mybatis-plus使用selectList查詢數(shù)據(jù)為null的問題及解決辦法

    Mybatis-plus使用selectList查詢數(shù)據(jù)為null的問題及解決辦法

    這篇文章主要介紹了Mybatis-plus使用selectList查詢數(shù)據(jù)為null的問題及解決方法,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-07-07
  • 常用的Java數(shù)據(jù)結(jié)構(gòu)知識點匯總

    常用的Java數(shù)據(jù)結(jié)構(gòu)知識點匯總

    這篇文章主要介紹了常用的Java數(shù)據(jù)結(jié)構(gòu)知識點匯總,數(shù)據(jù)結(jié)構(gòu)分線性數(shù)據(jù)結(jié)構(gòu)和非線性數(shù)據(jù)結(jié)構(gòu),下面對此作詳細介紹,需要的小伙伴可以參考一下,希望對你的學(xué)習(xí)或工作有所幫助
    2022-03-03

最新評論