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

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

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

背景

最近開(kāi)發(fā)項(xiàng)目,因?yàn)橛械谌秸{(diào)用我們的接口,我們使用SpringBoot以JavaBean的方式接收了我們預(yù)期的參數(shù),參數(shù)接收也沒(méi)有什么異常。但是有一些需求問(wèn)題需要溝通,需要拿到合作第三方傳入的所有參數(shù),來(lái)進(jìn)行參數(shù)核驗(yàn)。

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

一番檢索,很容易拿到相關(guān)代碼。但是經(jīng)過(guò)實(shí)操,發(fā)現(xiàn)并不能如期獲取到參數(shù)。經(jīng)過(guò)思考,我的接口是POST請(qǐng)求,參數(shù)形式是json格式(使用了@RequestBody來(lái)修飾參數(shù))。

具體過(guò)程參看如下分析

獲取請(qǐng)求中的參數(shù)(非json格式參數(shù))

獲取方法

方法一

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

結(jié)論

經(jīng)過(guò)測(cè)試以上兩個(gè)方法可以獲取GET請(qǐng)求的參數(shù),以及參數(shù)格式為form-data、x-www-form-urlencoded的POST請(qǐng)求,但是json格式參數(shù)(postman中為raw)的參數(shù)不能獲得。

根據(jù)代碼的簡(jiǎn)介程度,選擇方法一,明顯更舒服一些。

以上結(jié)論經(jīng)過(guò)postman實(shí)測(cè).

獲取POST請(qǐng)求json格式的參數(shù)

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

經(jīng)過(guò)檢索推薦方法(參看后邊完整方法)

經(jīng)過(guò)一番檢索,網(wǎng)上推薦的方法一般都是使用流來(lái)進(jìn)行參數(shù)讀取,即使用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);

遇到的問(wèn)題及解決思路

問(wèn)題1 流不能多次被調(diào)用

但是又會(huì)遇到如下問(wèn)題:

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)

根據(jù)報(bào)錯(cuò)信息分析簡(jiǎn)單來(lái)說(shuō),就是getInputStream()已經(jīng)被調(diào)用了,不能再次調(diào)用。可是我看代碼上,我也沒(méi)調(diào)用。經(jīng)過(guò)一番檢索,原來(lái)@RequestBody注解配置后,默認(rèn)會(huì)使用流來(lái)讀取數(shù)據(jù)。

具體原因:

  • 默認(rèn)配置時(shí),getInputStream()和getReader()一起使用會(huì)報(bào)錯(cuò),使用兩遍getInputStream(),第二遍會(huì)為空。
  • 當(dāng)存在@RequestBody等注解時(shí),springMVC已讀取過(guò)一遍流,默認(rèn)單獨(dú)使用getInputStream()或getReader()都為空。

實(shí)測(cè),不加@RequestBody注解,可以如期獲得請(qǐng)求中的json參數(shù),但是又不得不加@RequestBody注解。這樣就需要新的思路

解決思路

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

實(shí)現(xiàn)方法

1.定義增強(qiáng)類(lèi),繼承繼承HttpServletRequestWrapper

將請(qǐng)求體中的流copy一份,覆寫(xiě)getInputStream()和getReader()方法供外部使用。每次調(diào)用覆寫(xiě)后的getInputStream()方法都是從復(fù)制出來(lái)的二進(jìn)制數(shù)組中進(jìn)行獲取,這個(gè)二進(jìn)制數(shù)組在對(duì)象存在期間一直存在,這樣就實(shí)現(xiàn)了流的重復(fù)讀取。

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.構(gòu)建過(guò)濾器

@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("過(guò)濾器包裝request失敗!將返回原來(lái)的request");
            chain.doFilter(request, response);
        } else {
            log.info("過(guò)濾器包裝request成功");
            chain.doFilter(requestWrapper, response);
        }
    }
    @Override
    public void destroy() {
    }
}

注意事項(xiàng):

  • 使用@WebFilter注解的urlPatterns屬性,可指定過(guò)濾哪一個(gè)接口方法。
  • 過(guò)濾器類(lèi)最好不要交由Spring管理,否則每一個(gè)接口都會(huì)進(jìn)行過(guò)濾(實(shí)測(cè))。例如:不要添加@Component注解. 3.編寫(xiě)工具類(lèi)方便調(diào)用
/**
 * description:http輔助工具類(lèi)
 *
 * @author RenShiWei
 * Date: 2021/5/7 22:11
 **/
public class HttpHelper {
    /**
     * description:從request獲取body的json數(shù)據(jù)
     *
     * @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數(shù)據(jù),并格式化成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啟動(dòng)類(lèi)上添加@ServletComponentScan注解

使用

@RestController
@RequestMapping("/api/test")
public class TestController {
    @GetMapping("/test1")
    @AnonymousAccess
    public ResponseEntity<String> test1(HttpServletRequest request) {
        System.out.println("---GET請(qǐng)求 getParameterNames 入?yún)?--");
        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請(qǐng)求 getParameterMap 入?yún)?--");
        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測(cè)試

GET請(qǐng)求

POST的JSON格式參數(shù)(其他方式結(jié)果與GET請(qǐng)求結(jié)果一致)

結(jié)果

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

相關(guān)文章

最新評(píng)論

全州县| 彭州市| 简阳市| 滨海县| 措美县| 姚安县| 枣强县| 孟连| 化德县| 固安县| 哈巴河县| 静乐县| 宁夏| 泰州市| 和田县| 陆川县| 牡丹江市| 冀州市| 通城县| 汉沽区| 双牌县| 黄骅市| 鹤山市| 临猗县| 莱阳市| 墨脱县| 齐齐哈尔市| 宁津县| 土默特左旗| 农安县| 屏南县| 自治县| 德惠市| 南城县| 拉萨市| 宁晋县| 济宁市| 四会市| 平远县| 西峡县| 凤冈县|