#12解決request中getReader()和getInputStream()只能調用一次的問題

目錄

1、背景

2、解決方案

2.1、自定義HttpServletRequestWrapper

2.2、JsonRequestHeaderParamsHelper

2.3、HttpServletRequestReplacedFilter

2.4、使用


1、背景

當前系統Content-Type為application/json,參數接收方式采用@RequestBody和@RequestParam,但Interceptor攔截器和Aspect切面中存在再次調用request獲取其中請求參數或者請求頭等操作,導致報錯getReader()和getInputStream()只能調用一次(getInputStream() has already been called for this request)。

2、解決方案

2.1、自定義HttpServletRequestWrapper

由于請求信息存儲在流中,只能調用一次,因此將其存儲到字節數組中,保證之后調用getReader()和getInputStream()均通過body數組來獲取數據。

public class BodyReaderHttpServletRequestWrapper extends
HttpServletRequestWrapper {private final byte[] body;public BodyReaderHttpServletRequestWrapper(HttpServletRequest request)throws IOException {super(request);body = JsonRequestHeaderParamsHelper.bufferReaderToString(request.getReader()).getBytes();}@Overridepublic BufferedReader getReader() throws IOException {return new BufferedReader(new InputStreamReader(getInputStream()));}@Overridepublic ServletInputStream getInputStream() throws IOException {final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body);return new ServletInputStream() {@Overridepublic boolean isFinished() {return false;}@Overridepublic boolean isReady() {return false;}@Overridepublic void setReadListener(ReadListener readListener) {}@Overridepublic int read() {return byteArrayInputStream.read();}};}
}

2.2、JsonRequestHeaderParamsHelper

@Slf4j
public class JsonRequestHeaderParamsHelper {public static JSONObject parseHeader(ServletRequest request) throws IOException {return JSON.parseObject(bufferReaderToString(request.getReader()));}public static String bufferReaderToString(BufferedReader reader) throws IOException {StringBuilder sb = new StringBuilder();try  {char[] buff = new char[1024];int len;while ((len = reader.read(buff)) != -1) {sb.append(buff, 0, len);}} catch (IOException e) {log.error("bufferReaderToString error", e);}return sb.toString();}
}

2.3、HttpServletRequestReplacedFilter

通過Order(0)使其最優先加載,保證所有請求都先將request替換為自定義的。

此處的init()和destroy()方法不要使用super.init(),務必清空idea自動生成的內容。

@Slf4j
@Order(value = 0)
@WebFilter(filterName = "httpServletRequestReplacedFilter", urlPatterns = "/*")
public class HttpServletRequestReplacedFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {log.info("進入HttpServletRequestReplacedFilter");ServletRequest requestWrapper = null;if(request instanceof HttpServletRequest) {requestWrapper = new BodyReaderHttpServletRequestWrapper((HttpServletRequest) request);}if(null == requestWrapper) {chain.doFilter(request, response);} else {chain.doFilter(requestWrapper, response);}}@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void destroy() {}
}

2.4、使用

之后就可以愉快地使用request.getParameter,@RequestBody等等了。

附上get和post手動獲取請求參數的方法:

        if("GET".equals(request.getMethod())|| "DELETE".equals(request.getMethod())) {JSONObject jsonObject = JSONObject.fromObject(request.getParameterMap());params=jsonObject.toString();log.info("get請求參數為:{}", params);}else {com.alibaba.fastjson.JSONObject jsonObject =JsonRequestHeaderParamsHelper.parseHeader(request);params=jsonObject.toJSONString();log.info("post請求參數為:{}",params);}

如果對你有幫助,點贊、收藏、關注是我更新的動力!

往期精彩:

#11vue3中使用el-dialog展示與關閉交由父組件控制的寫法-CSDN博客文章瀏覽閱讀1k次,點贊40次,收藏28次。vue3中使用elementplus的el-dialog展示與關閉交由父組件控制的寫法,分兩種方法,使用difineExpose或者defineEmits實現https://blog.csdn.net/weixin_42718399/article/details/136155379?spm=1001.2014.3001.5501#10外部網頁跳轉vue3+SpringMVC解碼GBK編碼的參數-CSDN博客文章瀏覽閱讀2.2k次,點贊64次,收藏18次。外部網頁跳轉vue3頁面解碼GBK編碼的參數問題(包括亂碼、解碼失敗、無法進入頁面、URI malformed等問題)https://blog.csdn.net/weixin_42718399/article/details/135995885?spm=1001.2014.3001.5501#6解析@PreAuthorize以及其中的Spel-CSDN博客文章瀏覽閱讀1.2k次,點贊41次,收藏18次。#6解析@PreAuthorize以及其中的Spel _@preauthorizehttps://blog.csdn.net/weixin_42718399/article/details/135558235?spm=1001.2014.3001.5501#2Vite+Vue3+SpringMVC前后端分離 解決跨域問題和session每次請求不一致問題_vue3前后端分離跨域問題-CSDN博客文章瀏覽閱讀1.1k次,點贊37次,收藏15次。Vite+Vue3+SpringMVC前后端分離通過vite/nginx解決跨域問題和session一致性問題_vue3前后端分離跨域問題https://blog.csdn.net/weixin_42718399/article/details/135388463?spm=1001.2014.3001.5501

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/696594.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/696594.shtml
英文地址,請注明出處:http://en.pswp.cn/news/696594.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

平時積累的FPGA知識點(10)

平時在FPGA群聊等積累的FPGA知識點,第10期: 41 ZYNQ系列芯片的PL中使用PS端送過來的時鐘,這些時鐘名字是自動生成的嗎? 解釋:是的。PS端設置的是ps_clk,用report_clocks查出來的時鐘名變成了clk_fpga_0&a…

vue系列--通過js生成前端水印的方法

此方法開箱即用,在vue項目中import即可。 例如: //在vue組件中 import Watermark from /utils/watermark.js//在methods中 Watermark.set({color:"",text:""})//設置水印Watermark.remove() //刪除水印 const watermark {}const…

Linux篇:進程

一. 前置知識 1.1馮諾依曼體系結構 我們常見的計算機,如筆記本。我們不常見的計算機,如服務器,大部分都遵守馮諾依曼體系 為什么計算機要采用馮諾依曼體系呢? 在計算機出現之前有很多人都提出過計算機體系結構,但最…

時序數據庫TimescaleDB,實戰部署全攻略

📢📢📢📣📣📣 哈嘍!大家好,我是【IT邦德】,江湖人稱jeames007,10余年DBA及大數據工作經驗 一位上進心十足的【大數據領域博主】!😜&am…

C++ Primer 筆記(總結,摘要,概括)——第5章 語句

目錄 5.1 簡單語句 5.2 語句作用域 5.3 條件語句 5.3.1 if語句 5.3.2 switch語句 5.4 迭代語句 5.4.1 while語句 5.4.2 傳統的for語句 5.4.3 范圍for語句 5.4.4 do while語句 5.5 跳轉語句 5.5.1 break語句 5.5.2 continue語句 5.5.3 goto語句 5.6 try語句塊和異常處理 5…

前端常見面試題

我們前端常見面試題涉及多個方面,這篇文章就先簡單把每個方面都舉幾個列子,分別寫一下常見的主題和可能的問題。 一:HTML/CSS 基礎 問題: 1.解釋一下什么是語義化標簽?它的好處是什么? 2.CSS 選擇器的優先級是如何工…

2024華北醫院信息網絡大會第二輪更新通知

大會背景 近年來,我國醫療行業信息化取得了飛躍式的發展,醫療信息化對醫療行業有著重要的支撐作用。2021年國家衛健委、中醫藥管理局聯合印發《公立醫院高質量發展促進行動(2021-2025年)》,提出重點建設“三位一體”智…

【青龍】快速搭建青龍面板,部署屬于你自己的應用!

青龍面板是一個支持 Python3、JavaScript、Shell、Typescript 的定時任務管理平臺。 廢話不多說,直接開始。 這里使用一臺 雨云 的云服務器作為演示。雨云注冊地址:https://www.rainyun.com/ 優惠碼:lz932 使用優惠碼注冊后綁定微信可獲得8折…

【Chrono Engine學習總結】4-vehicle-4.3-兩個vehicle碰撞測試

由于Chrono的官方教程在一些細節方面解釋的并不清楚,自己做了一些嘗試,做學習總結。 今天突發奇想,想試一下,是否可以實現兩個vehicle的碰撞? 1、兩輛vehicle的仿真 官方提供了demo_VEH_TwoCars這個demo&#xff0c…

C++入門04 函數的參數傳遞、引用類型與重載

圖源:文心一言 聽課筆記簡單整理,供小伙伴們參考,包含以下內容“🐋3.11 引用類型、🐋3.14 內聯函數、🐋3.15 默認參數值、🐋3.16 函數重載、🐋3.17 C系統函數”~🥝&…

LabVIEW多通道壓力傳感器實時動態檢測

LabVIEW多通道壓力傳感器實時動態檢測 介紹了一種基于LabVIEW的多通道壓力傳感器實時動態檢測系統,解決壓阻式壓力傳感器溫度補償過程的復雜度,提高測量的準確性。通過自動輪詢檢測方法,結合硬件檢測模型和多通道檢測系統設計,本…

集合框架之List集合

目錄 ?編輯 一、什么是UML 二、集合框架 三、List集合 1.特點 2.遍歷方式 3.刪除 4.優化 四、迭代器原理 五、泛型 六、裝拆箱 七、ArrayList、LinkedList和Vector的區別 ArrayList和Vector的區別 LinkedList和Vector的區別 一、什么是UML UML(Unif…

基于ORB-SLAM2與YOLOv8剔除動態特征點(三種方法)

基于ORB-SLAM2與YOLOv8剔除動態特征點(三種方法) 寫上篇文章時測試過程比較亂,寫的時候有些地方有點失誤,所以重新寫了這篇 本文內容均在RGB-D環境下進行程序測試 本文涉及到的動態特征點剔除速度均是以https://cvg.cit.tum.de/data/datasets/rgbd-dat…

系統學習Python——裝飾器:類裝飾器-[單例類:編寫替代方案]

分類目錄:《系統學習Python》總目錄 有趣的是,這里如果能使用nonlocal語句(僅在Python3.X中可用)來改變外層作用域名稱,我們在這里可以編寫一個自包含程度更高的解決方案一一一下面的替代方案為每個類使用了一個外層作…

編寫程序,實現shell功能——項目訓練——day08

c c今天做了一個實戰項目訓練,編寫一個程序,實現shell功能,我們稱之為minishell。 主要是利用Linux中IO接口實現,實現的功能有: 1.ls ls -a ls -l cd cp mv pwd c…

軟件License授權原理

軟件License授權原理 你知道License是如何防止別人破解的嗎?本文將介紹License的生成原理,理解了License的授權原理你不但可以防止別人破解你的License,你甚至可以研究別人的License找到它們的漏洞。喜歡本文的朋友建議收藏關注,…

【Linux】進程狀態

進程狀態 進程狀態的簡要介紹運行狀態進程排隊 阻塞狀態掛起狀態Linux中的進程狀態 進程狀態的簡要介紹 進程狀態指的是一個操作系統中正在運行的進程當前所處的狀態。根據不同的操作系統,進程狀態可能會有一些細微的差別,但最主要的是以下三種狀態 運行…

Java——方法的使用

目錄 一.方法的概念及使用 1 什么是方法(method) 2.方法定義 3 方法調用的執行過程 4 實參和形參的關系(重要) 5.沒有返回值的方法 二.方法重載 1.為什么需要方法重載 2.方法重載概念 3.方法簽名 三.遞歸 1.遞歸的概念 2.遞歸執行過程分析 3. 遞歸練習 一.方法的…

貓頭虎分享已解決Bug || 容器編排問題:OrchestrationFailure, ContainerManagementError

博主貓頭虎的技術世界 🌟 歡迎來到貓頭虎的博客 — 探索技術的無限可能! 專欄鏈接: 🔗 精選專欄: 《面試題大全》 — 面試準備的寶典!《IDEA開發秘籍》 — 提升你的IDEA技能!《100天精通鴻蒙》 …

代碼隨想錄算法訓練營第四十二天|122. 買賣股票的最佳時機 II

674. 最長連續遞增序列 public static int findLengthOfLCIS(int[] nums) {int[] dp new int[nums.length];dp[0] 1;for (int i 1; i < nums.length; i) {dfs(nums, dp, i);}Arrays.sort(dp);return dp[dp.length - 1];}public static void dfs(int[] nums, int[] dp, i…