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

SpringBoot通過請求對象獲取輸入流無數(shù)據(jù)

 更新時間:2022年03月18日 09:01:01   作者:蔣固金  
這篇文章主要介紹了使用SpringBoot通過請求對象獲取輸入流無數(shù)據(jù),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

請求對象獲取輸入流無數(shù)據(jù)問題

昨天下午在開發(fā)的時候遇到了奇怪的事情,在SpringBoot的Controller里面直接使用HttpServletRequest的getInputStream()方法的時候獲得的輸入流無數(shù)據(jù),通過getContentLength()獲得內(nèi)容長度的時候又是有值的,由于昨天比較晚了就沒有研究,今天花了點時間查一下原因。

出現(xiàn)這種情況,首先懷疑輸入流已經(jīng)被使用了,由于請求輸入流是不帶緩存的,使用一次后流就無效了,通常觸發(fā)解析輸入流就是調(diào)用了getParameter()等方法,經(jīng)過檢查代碼確認(rèn)沒有做過相關(guān)處理,所以懷疑SpringBoot底層做了處理。

查了一下SpringBoot的自動裝配配置,在WebMvcAutoConfiguration中初始化了一個OrderedHiddenHttpMethodFilter,默認(rèn)這個過濾器是生效的,相關(guān)代碼如下:

@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
@ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled", matchIfMissing = true)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
? ? return new OrderedHiddenHttpMethodFilter();
}

OrderedHiddenHttpMethodFilter繼承了OrderedHiddenHttpMethodFilter,而OrderedHiddenHttpMethodFilter又繼承了HiddenHttpMethodFilter,在該類的doFilterInternal()方法中發(fā)現(xiàn)有對參數(shù)做處理,相關(guān)代碼如下:

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
? ? throws ServletException, IOException {
? ? HttpServletRequest requestToUse = request;
? ? if ("POST".equals(request.getMethod()) &&?
? ? request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) {
? ? ? ? String paramValue = request.getParameter(this.methodParam);
? ? ? ? if (StringUtils.hasLength(paramValue)) {
? ? ? ? ? ? String method = paramValue.toUpperCase(Locale.ENGLISH);
? ? ? ? ? ? if (ALLOWED_METHODS.contains(method)) {
? ? ? ? ? ? ? ? requestToUse = new HttpMethodRequestWrapper(request, method);
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? filterChain.doFilter(requestToUse, response);
}

至此就可以定位問題的所在了,找到了問題下面就來看看如何解決。

方案一:禁用默認(rèn)的過濾器

SpringBoot在自動裝配的時候注入了OrderedHiddenHttpMethodFilter,如果我們不需要該功能,在配置文件中顯示的將其設(shè)置為false。配置如下:

spring.mvc.hiddenmethod.filter.enabled=false

方案二:使用@RequestBody注解

在需要獲取請求輸入流的方法上添加字節(jié)數(shù)組的參數(shù),并添加@RequestBody注解,示例代碼如下:

@RequestMapping("/**")
public 返回值 方法名(@RequestBody byte[] body) {
? ?// ...
}

方案三:自定義HiddenHttpMethodFilter過濾器

參考代碼如下:

@Bean
public HiddenHttpMethodFilter hiddenHttpMethodFilter() {
? ? return new OrderedHiddenHttpMethodFilter(){
? ? ? ? @Override
? ? ? ? protected void doFilterInternal(HttpServletRequest request,
? ? ? ? ? ? HttpServletResponse response, FilterChain filterChain)
? ? ? ? ? ? throws ServletException, IOException {
? ? ? ? ? ? filterChain.doFilter(request, response);
? ? ? ? }
? ? };

request輸入流重復(fù)可讀

自定義類繼承 HttpServletRequestWrapper

/**
?* @describe 目的是讓其輸入流可重復(fù)讀
?* @author czx
?* @date 2020年5月15日22:53:35
?*/
@Slf4j
public class RequestWrapper extends HttpServletRequestWrapper {
? ? /**
? ? ?* 存儲body數(shù)據(jù)的容器
? ? ?*/
? ? private final byte[] body;
?
? ? public RequestWrapper(HttpServletRequest request) throws IOException {
? ? ? ? super(request);
?
? ? ? ? // 將body數(shù)據(jù)存儲起來
? ? ? ? String bodyStr = getBodyString(request);
? ? ? ? body = bodyStr.getBytes(Charset.defaultCharset());
? ? }
?
? ? /**
? ? ?* 獲取請求Body
? ? ?*
? ? ?* @param request request
? ? ?* @return String
? ? ?*/
? ? public String getBodyString(final ServletRequest request) {
? ? ? ? try {
? ? ? ? ? ? return inputStream2String(request.getInputStream());
? ? ? ? } catch (IOException e) {
? ? ? ? ? ? log.error("", e);
? ? ? ? ? ? throw new RuntimeException(e);
? ? ? ? }
? ? }
?
? ? /**
? ? ?* 獲取請求Body
? ? ?*
? ? ?* @return String
? ? ?*/
? ? public String getBodyString() {
? ? ? ? final InputStream inputStream = new ByteArrayInputStream(body);?
? ? ? ? return inputStream2String(inputStream);
? ? }
?
? ? /**
? ? ?* 將inputStream里的數(shù)據(jù)讀取出來并轉(zhuǎn)換成字符串
? ? ?*
? ? ?* @param inputStream inputStream
? ? ?* @return String
? ? ?*/
? ? private String inputStream2String(InputStream inputStream) {
? ? ? ? StringBuilder sb = new StringBuilder();
? ? ? ? BufferedReader reader = null;
?
? ? ? ? try {
? ? ? ? ? ? reader = new BufferedReader(new InputStreamReader(inputStream, Charset.defaultCharset()));
? ? ? ? ? ? String line;
? ? ? ? ? ? while ((line = reader.readLine()) != null) {
? ? ? ? ? ? ? ? sb.append(line);
? ? ? ? ? ? }
? ? ? ? } catch (IOException e) {
? ? ? ? ? ? log.error("", e);
? ? ? ? ? ? throw new RuntimeException(e);
? ? ? ? } finally {
? ? ? ? ? ? if (reader != null) {
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? reader.close();
? ? ? ? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ? ? ? log.error("", e);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
?
? ? ? ? return sb.toString();
? ? }
?
? ? @Override
? ? public BufferedReader getReader() throws IOException {
? ? ? ? return new BufferedReader(new InputStreamReader(getInputStream()));
? ? }
?
? ? @Override
? ? public ServletInputStream getInputStream() throws IOException {
?
? ? ? ? final ByteArrayInputStream inputStream = new ByteArrayInputStream(body);?
? ? ? ? return new ServletInputStream() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public int read() throws IOException {
? ? ? ? ? ? ? ? return inputStream.read();
? ? ? ? ? ? }
?
? ? ? ? ? ? @Override
? ? ? ? ? ? public boolean isFinished() {
? ? ? ? ? ? ? ? return false;
? ? ? ? ? ? }
?
? ? ? ? ? ? @Override
? ? ? ? ? ? public boolean isReady() {
? ? ? ? ? ? ? ? return false;
? ? ? ? ? ? }
?
? ? ? ? ? ? @Override
? ? ? ? ? ? public void setReadListener(ReadListener readListener) {
? ? ? ? ? ? }
? ? ? ? };
? ? }?
}

定義一個過濾器 Filter

@Slf4j
public class ReplaceStreamFilter implements Filter {
?
? ? @Override
? ? public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
? ? ? ? ServletRequest requestWrapper = new RequestWrapper((HttpServletRequest) request);
? ? ? ? chain.doFilter(requestWrapper, response);
? ? }
}

創(chuàng)建過濾器配置類 FilterConfig

@Configuration
public class FilterConfig {
?
? ? /**
? ? ?* 注冊過濾器
? ? ?*
? ? ?* @return FilterRegistrationBean
? ? ?*/
? ? @Bean
? ? public FilterRegistrationBean someFilterRegistration() {
? ? ? ? FilterRegistrationBean registration = new FilterRegistrationBean();
? ? ? ? registration.setFilter(replaceStreamFilter());
? ? ? ? registration.addUrlPatterns("/*");
? ? ? ? registration.setName("streamFilter");
? ? ? ? return registration;
? ? }
?
? ? /**
? ? ?* 實例化StreamFilter
? ? ?* @return Filter
? ? ?*/
? ? @Bean(name = "replaceStreamFilter")
? ? public Filter replaceStreamFilter() {
? ? ? ? return new ReplaceStreamFilter();
? ? }?
}

完成以上步驟即可在攔截器中讀取request中的body數(shù)據(jù) 

@Slf4j
@Component
public class APIInterceptor implements HandlerInterceptor {?
? ? /**
? ? ?* 預(yù)處理回調(diào)方法,實現(xiàn)處理器的預(yù)處理
? ? ?* 返回值:true表示繼續(xù)流程;false表示流程中斷,不會繼續(xù)調(diào)用其他的攔截器或處理器
? ? ?*/
? ? @Override
? ? public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{
? ? ? ? log.info("開始攔截請求");
?
?? ??? ?if(isJson(request)){
?? ??? ??? ?String jsonParam = new RequestWrapper(request).getBodyString();
?? ??? ??? ?JSONObject params = JSONObject.parseObject(jsonParam);
?? ??? ??? ?......
?? ??? ??? ?return true;
?? ??? ?}?? ??? ?
?? ??? ?return false;
? ? }???
?
? ? /**
? ? ?* 返回json數(shù)據(jù)給前端
? ? ?* @param response
? ? ?* @param json
? ? ?*/
? ? protected void returnJson(ServletResponse response, JSONObject json){
? ? ? ? PrintWriter writer = null;
? ? ? ? response.setCharacterEncoding("UTF-8");
? ? ? ? response.setContentType("application/json; charset=utf-8");
? ? ? ? try {
? ? ? ? ? ? writer = response.getWriter();
? ? ? ? ? ? writer.print(json.toJSONString());
?
? ? ? ? } catch (IOException e) {
? ? ? ? ? ? log.error("response error",e);
? ? ? ? } finally {
? ? ? ? ? ? if (writer != null)
? ? ? ? ? ? ? ? writer.close();
? ? ? ? }
? ? }??
?
? ? /**
? ? ?* 判斷本次請求的數(shù)據(jù)類型是否為json
? ? ?* @param request request
? ? ?* @return boolean
? ? ?*/
? ? private boolean isJson(HttpServletRequest request) {
? ? ? ? if (request.getContentType() != null) {
? ? ? ? ? ? return request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE) ||
? ? ? ? ? ? ? ? ? ? request.getContentType().equals(MediaType.APPLICATION_JSON_UTF8_VALUE);
? ? ? ? }?
? ? ? ? return false;
? ? }

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

相關(guān)文章

  • spring boot基于注解的聲明式事務(wù)配置詳解

    spring boot基于注解的聲明式事務(wù)配置詳解

    這篇文章主要介紹了spring boot基于注解的聲明式事務(wù)配置詳解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • java如何遍歷對象中的所有屬性(字段)和類型

    java如何遍歷對象中的所有屬性(字段)和類型

    這篇文章主要介紹了java如何遍歷對象中的所有屬性(字段)和類型問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • 基于Java向zip壓縮包追加文件

    基于Java向zip壓縮包追加文件

    這篇文章主要介紹了基于Java向zip壓縮包追加文件,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-12-12
  • 性能爆棚的實體轉(zhuǎn)換復(fù)制工具M(jìn)apStruct使用詳解

    性能爆棚的實體轉(zhuǎn)換復(fù)制工具M(jìn)apStruct使用詳解

    這篇文章主要為大家介紹了性能爆棚的實體轉(zhuǎn)換復(fù)制工具M(jìn)apStruct使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • Spring @Conditional注解原理解析

    Spring @Conditional注解原理解析

    這篇文章主要介紹了Spring @Conditional注解原理解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-11-11
  • java_時間戳與Date_相互轉(zhuǎn)化的實現(xiàn)代碼

    java_時間戳與Date_相互轉(zhuǎn)化的實現(xiàn)代碼

    本篇文章是對java_時間戳與Date_相互轉(zhuǎn)化的實現(xiàn)代碼進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下如下。
    2016-11-11
  • springboot 設(shè)置server.port不生效的原因及解決

    springboot 設(shè)置server.port不生效的原因及解決

    這篇文章主要介紹了springboot 設(shè)置server.port不生效的原因及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • SpringBoot項目中新增脫敏功能的實例代碼

    SpringBoot項目中新增脫敏功能的實例代碼

    項目中,由于使用端有兩個,對于兩個端的數(shù)據(jù)權(quán)限并不一樣。Web端可以查看所有數(shù)據(jù),小程序端只能查看脫敏后的數(shù)據(jù),這篇文章主要介紹了SpringBoot項目中新增脫敏功能,需要的朋友可以參考下
    2022-11-11
  • java Comparator.comparing排序使用示例

    java Comparator.comparing排序使用示例

    本文主要介紹了java Comparator.comparing排序使用示例,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • springcloud?如何解決微服務(wù)之間token傳遞問題

    springcloud?如何解決微服務(wù)之間token傳遞問題

    這篇文章主要介紹了springcloud?如何解決微服務(wù)之間token傳遞問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03

最新評論

承德市| 威远县| 巩义市| 吉林省| 商水县| 禹州市| 新巴尔虎左旗| 广安市| 太仓市| 子长县| 修武县| 秦皇岛市| 巴中市| 南投市| 宜黄县| 滨海县| 正宁县| 阿拉善右旗| 淳化县| 麟游县| 临漳县| 娱乐| 怀柔区| 和田市| 靖州| 大关县| 图木舒克市| 武强县| 丁青县| 三原县| 肥西县| 西平县| 黑河市| 乐山市| 达拉特旗| 西昌市| 玉山县| 霸州市| 合江县| 邯郸县| 涡阳县|