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

SpringBoot如何配置獲取request中body的json格式參數

 更新時間:2022年06月30日 09:41:26   作者:Duktig丶  
這篇文章主要介紹了SpringBoot如何配置獲取request中body的json格式參數,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

背景

最近開發(fā)項目,因為有第三方調用我們的接口,我們使用SpringBoot以JavaBean的方式接收了我們預期的參數,參數接收也沒有什么異常。但是有一些需求問題需要溝通,需要拿到合作第三方傳入的所有參數,來進行參數核驗。

如何拿到請求的所有參數呢?正常的思路肯定是從request中獲取,如果是GET請求,參數在請求路徑中拼接;如果是POST請求,參數在request的請求體(body)中。

一番檢索,很容易拿到相關代碼。但是經過實操,發(fā)現并不能如期獲取到參數。經過思考,我的接口是POST請求,參數形式是json格式(使用了@RequestBody來修飾參數)。

具體過程參看如下分析

獲取請求中的參數(非json格式參數)

獲取方法

方法一

Enumeration<String> parameterNames = request.getParameterNames();
while (parameterNames.hasMoreElements()) {
    String paraName = parameterNames.nextElement();
    System.out.println(paraName + ": " + request.getParameter(paraName));
}

方法二

Map<String, String[]> map = request.getParameterMap();
Set<Map.Entry<String, String[]>> keSet = map.entrySet();
for (Iterator<Map.Entry<String, String[]>> itr = keSet.iterator(); itr.hasNext(); ) {
    Map.Entry<String, String[]> me = itr.next();
    Object ok = me.getKey();
    Object ov = me.getValue();
    String[] value = new String[1];
    if (ov != null) {
        value = (String[]) ov;
    } else {
        value[0] = ov.toString();
    }
    for (int k = 0; k < value.length; k++) {
        System.out.println(ok + "=" + value[k]);
    }
}

結論

經過測試以上兩個方法可以獲取GET請求的參數,以及參數格式為form-data、x-www-form-urlencoded的POST請求,但是json格式參數(postman中為raw)的參數不能獲得

根據代碼的簡介程度,選擇方法一,明顯更舒服一些。

以上結論經過postman實測.

獲取POST請求json格式的參數

以上方法已經可以獲取大多數情況下的請求的參數,但是明顯還不能滿足需求,需要獲取傳入json格式的參數。 

經過檢索推薦方法(參看后邊完整方法)

經過一番檢索,網上推薦的方法一般都是使用流來進行參數讀取,即使用getInputStream()和getReader():

Map<String, Object> params = new HashMap<>();
BufferedReader br = null;
try {
    try {
        br = request.getReader();
    } catch (IOException e) {
        e.printStackTrace();
    }
    String str;
    StringBuilder wholeStr = new StringBuilder();
    while ((str = Objects.requireNonNull(br).readLine()) != null) {
        wholeStr.append(str);
    }
    if (StrUtil.isNotEmpty(wholeStr.toString())) {
        params = JSON.parseObject(wholeStr.toString(), Map.class);
    }
} catch (IOException e) {
    e.printStackTrace();
}
System.out.println(params);

遇到的問題及解決思路

問題1 流不能多次被調用

但是又會遇到如下問題:

ERROR m.e.handler.GlobalExceptionHandler - getInputStream() has already been called for this request
java.lang.IllegalStateException: getInputStream() has already been called for this request
    at org.apache.catalina.connector.Request.getReader(Request.java:1212)
    at org.apache.catalina.connector.RequestFacade.getReader(RequestFacade.java:504)

根據報錯信息分析簡單來說,就是getInputStream()已經被調用了,不能再次調用??墒俏铱创a上,我也沒調用。經過一番檢索,原來@RequestBody注解配置后,默認會使用流來讀取數據。

具體原因:

  • 默認配置時,getInputStream()和getReader()一起使用會報錯,使用兩遍getInputStream(),第二遍會為空。
  • 當存在@RequestBody等注解時,springMVC已讀取過一遍流,默認單獨使用getInputStream()或getReader()都為空。

實測,不加@RequestBody注解,可以如期獲得請求中的json參數,但是又不得不加@RequestBody注解。這樣就需要新的思路

解決思路

寫filter繼承HttpServletRequestWrapper,緩存InputStream,覆蓋getInputStream()和getReader()方法,使用ByteArrayInputStream is = new ByteArrayInputStream(body.getBytes());讀取InputStream。

實現方法

1.定義增強類,繼承繼承HttpServletRequestWrapper

將請求體中的流copy一份,覆寫getInputStream()和getReader()方法供外部使用。每次調用覆寫后的getInputStream()方法都是從復制出來的二進制數組中進行獲取,這個二進制數組在對象存在期間一直存在,這樣就實現了流的重復讀取。

public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
    private byte[] body;
    public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        body = HttpHelper.getBodyString(request).getBytes(StandardCharsets.UTF_8);
    }
    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }
    @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) {
            }
        };
    }
    public void setInputStream(byte[] body) {
        this.body = body;
    }
}

2.構建過濾器

@Slf4j
@WebFilter(filterName = "RequestWrapperFilter", urlPatterns = "/api/test/test2")
public class RequestWrapperFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException
            , IOException {
        ServletRequest requestWrapper = null;
        if (request instanceof HttpServletRequest) {
            requestWrapper = new BodyReaderHttpServletRequestWrapper((HttpServletRequest) request);
        }
        if (null == requestWrapper) {
            log.error("過濾器包裝request失敗!將返回原來的request");
            chain.doFilter(request, response);
        } else {
            log.info("過濾器包裝request成功");
            chain.doFilter(requestWrapper, response);
        }
    }
    @Override
    public void destroy() {
    }
}

注意事項:

  • 使用@WebFilter注解的urlPatterns屬性,可指定過濾哪一個接口方法。
  • 過濾器類最好不要交由Spring管理,否則每一個接口都會進行過濾(實測)。例如:不要添加@Component注解. 3.編寫工具類方便調用
/**
 * description:http輔助工具類
 *
 * @author RenShiWei
 * Date: 2021/5/7 22:11
 **/
public class HttpHelper {
    /**
     * description:從request獲取body的json數據
     *
     * @param request /
     * @return /
     * @author RenShiWei
     * Date: 2021/5/7 22:44
     */
    public static String getBodyString(ServletRequest request) {
        StringBuilder sb = new StringBuilder();
        ServletInputStream inputStream = null;
        BufferedReader reader = null;
        try {
            inputStream = request.getInputStream();
            reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
            String line = "";
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return sb.toString();
    }
    /**
     * description:從request獲取body的json數據,并格式化成map形式
     *
     * @param request /
     * @return /
     * @author RenShiWei
     * Date: 2021/5/7 22:44
     */
    @SuppressWarnings("all")
    public static Map<String, Object> getBodyMap(ServletRequest request) {
        Map<String, Object> params = new HashMap<>();
        String bodyString = getBodyString(request);
        if (StrUtil.isNotEmpty(bodyString)) {
            params = JSON.parseObject(bodyString, Map.class);
        }
        return params;
    }
}

4.在SpringBoot啟動類上添加@ServletComponentScan注解

使用

@RestController
@RequestMapping("/api/test")
public class TestController {
    @GetMapping("/test1")
    @AnonymousAccess
    public ResponseEntity<String> test1(HttpServletRequest request) {
        System.out.println("---GET請求 getParameterNames 入參---");
        try {
            request.setCharacterEncoding("utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        Enumeration<String> parameterNames = request.getParameterNames();
        while (parameterNames.hasMoreElements()) {
            String paraName = parameterNames.nextElement();
            System.out.println(paraName + ": " + request.getParameter(paraName));
        }
        System.out.println("---GET請求 getParameterMap 入參---");
        Map<String, String[]> map = request.getParameterMap();
        Set<Map.Entry<String, String[]>> keSet = map.entrySet();
        for (Iterator<Map.Entry<String, String[]>> itr = keSet.iterator(); itr.hasNext(); ) {
            Map.Entry<String, String[]> me = itr.next();
            Object ok = me.getKey();
            Object ov = me.getValue();
            String[] value = new String[1];
            if (ov != null) {
                value = (String[]) ov;
            } else {
                value[0] = ov.toString();
            }
            for (int k = 0; k < value.length; k++) {
                System.out.println(ok + "=" + value[k]);
            }
        }
        return ResponseEntity.ok(null);
    }
    @PostMapping("/test2")
    @AnonymousAccess
    public ResponseEntity<String> test2(@RequestBody TestParam testParam, HttpServletRequest request) {
        String body = HttpHelper.getBodyString(request);
        Map<String, Object> bodyMap = HttpHelper.getBodyMap(request);
        System.out.println("body: " + body);
        System.out.println("bodyMap: " + bodyMap);
        return ResponseEntity.ok(null);
    }
}

postman測試

GET請求

POST的JSON格式參數(其他方式結果與GET請求結果一致)

結果

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

相關文章

  • 淺談Java分布式架構下如何實現分布式鎖

    淺談Java分布式架構下如何實現分布式鎖

    這篇文章主要介紹了淺談Java分布式架構下如何實現分布式鎖,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-07-07
  • java 如何判斷是否可以ping通某個地址

    java 如何判斷是否可以ping通某個地址

    這篇文章主要介紹了java 如何判斷是否可以ping通某個地址,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • springboot中使用自定義兩級緩存的方法

    springboot中使用自定義兩級緩存的方法

    這篇文章主要介紹了springboot中使用自定義兩級緩存的方法,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-05-05
  • Java數據結構和算法之鏈表詳解

    Java數據結構和算法之鏈表詳解

    鏈表是一種物理存儲單元上非連續(xù)、非順序的存儲結構,java代碼實現單鏈表,插入,刪除和遍歷等功能,這篇文章主要給大家介紹了關于Java數據結構和算法之鏈表的相關資料,需要的朋友可以參考下
    2024-01-01
  • mybatis-plus中BaseMapper入門使用

    mybatis-plus中BaseMapper入門使用

    本文主要介紹了mybatis-plus中BaseMapper入門使用,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • Idea配置maven-tomcat-plugin插件實現項目部署

    Idea配置maven-tomcat-plugin插件實現項目部署

    今天小編就為大家分享一篇關于Idea配置maven-tomcat-plugin插件實現項目部署,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-02-02
  • Java 中Timer和TimerTask 定時器和定時任務使用的例子

    Java 中Timer和TimerTask 定時器和定時任務使用的例子

    這篇文章主要介紹了Java 中Timer和TimerTask 定時器和定時任務使用的例子,非常具有實用價值,需要的朋友可以參考下
    2017-05-05
  • JDK1.8下載、安裝和環(huán)境配置超詳細教程(最新最完整)

    JDK1.8下載、安裝和環(huán)境配置超詳細教程(最新最完整)

    jdk1.8是一款功能強大的Java語音軟件開發(fā)工具包,JDK是學好Java的第一步,本文重點給大家介紹JDK1.8下載、安裝和環(huán)境配置教程,需要的朋友可以參考下
    2022-11-11
  • Java多線程下解決數據安全問題

    Java多線程下解決數據安全問題

    這篇文章主要介紹了Java多線程下解決數據安全問題,本文使用代碼進行講解,可供大家學習參考
    2021-08-08
  • Java之如何正確地對包裝類進行裝箱與拆箱

    Java之如何正確地對包裝類進行裝箱與拆箱

    在這篇文章中給大家繼續(xù)講解包裝類的裝箱和拆箱問題。你可能會很好奇,做java開發(fā),怎么還裝起箱子來了?那么就請大家?guī)е苫笸驴窗?/div> 2023-04-04

最新評論

紫阳县| 收藏| 宣汉县| 仙桃市| 辽阳县| 平阳县| 新兴县| 定边县| 内乡县| 左贡县| 类乌齐县| 丰镇市| 家居| 木里| 土默特左旗| 特克斯县| 革吉县| 莲花县| 黔南| 仁布县| 海门市| 泽普县| 延长县| 毕节市| 衡阳县| 阳东县| 永春县| 泾川县| 东莞市| 白水县| 南乐县| 朔州市| 宿松县| 茂名市| 调兵山市| 云安县| 甘泉县| 托里县| 获嘉县| 松滋市| 惠东县|