最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

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

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

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

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

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

上面的getParameterMap(),只能夠獲取到GET請(qǐng)求的參數(shù),如果是POST方法傳的JSON那就沒法獲取到,那如何獲取呢,POST的請(qǐng)求是在請(qǐng)求體body中,而POST請(qǐng)求中的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());

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

image-20201219133609844

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

image-20201219134042794

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

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

image-20201219135249418

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

image-20201219135426586

從源碼我們可以看到

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

image-20201219140007286

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

image-20201219140830451

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

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

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) {
            }
        };
    }
}

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

image-20201219141929107

有一點(diǎn)需要注意的

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

image-20201219142124831

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

相關(guān)文章

  • Java內(nèi)存模型詳解

    Java內(nèi)存模型詳解

    JMM全稱Java Memory Model, 中文翻譯Java內(nèi)存模型,一種符合內(nèi)存模型規(guī)范的,屏蔽了各種硬件和操作系統(tǒng)的訪問差異的,本詳細(xì)介紹了Java內(nèi)存模型,感興趣的同學(xué)可以參考一下
    2023-04-04
  • 基于序列化存取實(shí)現(xiàn)java對(duì)象深度克隆的方法詳解

    基于序列化存取實(shí)現(xiàn)java對(duì)象深度克隆的方法詳解

    本篇文章是對(duì)序列化存取實(shí)現(xiàn)java對(duì)象深度克隆的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • Java中用戶線程與守護(hù)線程的使用區(qū)別

    Java中用戶線程與守護(hù)線程的使用區(qū)別

    這篇文章主要介紹了Java中用戶線程與守護(hù)線程的使用區(qū)別,Java語言中無論是線程還是線程池,默認(rèn)都是用戶線程,因此用戶線程也被成為普通線程,下文關(guān)于其與守護(hù)線程的區(qū)別詳情,需要的小伙伴可以參考一下
    2022-05-05
  • Java xml出現(xiàn)錯(cuò)誤 javax.xml.transform.TransformerException: java.lang.NullPointerException

    Java xml出現(xiàn)錯(cuò)誤 javax.xml.transform.TransformerException: java.

    這篇文章主要介紹了Java xml出現(xiàn)錯(cuò)誤 javax.xml.transform.TransformerException: java.lang.NullPointerException的相關(guān)資料,需要的朋友可以參考下
    2016-11-11
  • MyBatis使用注解開發(fā)和無主配置文件開發(fā)的情況

    MyBatis使用注解開發(fā)和無主配置文件開發(fā)的情況

    這篇文章主要介紹了MyBatis使用注解開發(fā)和無主配置文件開發(fā)的情況,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03
  • 詳解IDEA中SpringBoot整合Servlet三大組件的過程

    詳解IDEA中SpringBoot整合Servlet三大組件的過程

    這篇文章主要介紹了詳解IDEA中SpringBoot整合Servlet三大組件的過程,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • Java異常處理Guava?Throwables類使用實(shí)例解析

    Java異常處理Guava?Throwables類使用實(shí)例解析

    這篇文章主要為大家介紹了Java異常處理神器Guava?Throwables類使用深入詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • Java服務(wù)中的大文件上傳和下載優(yōu)化技巧分享

    Java服務(wù)中的大文件上傳和下載優(yōu)化技巧分享

    在Java服務(wù)中處理大文件的上傳和下載是一項(xiàng)常見但復(fù)雜的任務(wù),為了提供優(yōu)秀的用戶體驗(yàn)和高效的系統(tǒng)性能,我們將探索多種策略和技術(shù),并在每一點(diǎn)上都提供代碼示例以便實(shí)戰(zhàn)應(yīng)用,需要的朋友可以參考下
    2023-10-10
  • RocketMQ消息過濾與查詢的實(shí)現(xiàn)

    RocketMQ消息過濾與查詢的實(shí)現(xiàn)

    這篇文章主要介紹了RocketMQ消息過濾與查詢的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Java中的ReadWriteLock讀寫鎖詳解

    Java中的ReadWriteLock讀寫鎖詳解

    這篇文章主要介紹了Java中的ReadWriteLock讀寫鎖詳解,ReadWriteLock也是一個(gè)接口,提供了readLock和writeLock兩種鎖的操作機(jī)制,一個(gè)資源可以被多個(gè)線程同時(shí)讀,或者被一個(gè)線程寫,但是不能同時(shí)存在讀和寫線程,需要的朋友可以參考下
    2023-12-12

最新評(píng)論

苍梧县| 安乡县| 平潭县| 兴隆县| 克什克腾旗| 西丰县| 遂平县| 五峰| 平武县| 武胜县| 大荔县| 枝江市| 仙游县| 富源县| 马山县| 鄂伦春自治旗| 南充市| 翁源县| 梁山县| 宁晋县| 乳山市| 宝兴县| 吴旗县| 商河县| 师宗县| 浑源县| 偃师市| 张家川| 全南县| 江油市| 民勤县| 福州市| 罗甸县| 延吉市| 连江县| 平阳县| 湄潭县| 朝阳区| 鄂托克前旗| 五河县| 明光市|