如何實現多次讀取request裡面的引數值
首先需要明確如下幾個概念:
1:web開發的時候,過濾器屬於java原生元件,而攔截器屬於spring框架的元件,從它們的引數就可以看出來,過濾器引數為ServletRequest, 而攔截器為HttpServeletRequest,因為spring本來就是web開發針對的就是http協議,而java則是針對所有網路通訊不單單是http協議。
2:需要了解一下ServletRequest HttpServletRequest 之間的聯絡和區別
3:tomcat處理http請求的。Tomcat將請求轉換成了RequestFacade傳給過濾器,而RequestFacade實現了HttpServlestRequest介面。至於如何轉換可以看(
4:大部分IO輸入流是無法重複讀取的,只能讀取一次。再讀取時,會丟擲IO異常。無論是get請求還是post請求,在後端讀取一次之後,便無法再次讀取為了解決這個問題,我們需要包裝HttpServletRequest物件,快取body裡面的資料,再次讀取的時候從快取裡面讀取。
5: 我們可以定義自己的HttpServletRequest實現類來達到快取的目的。
public class MAPIHttpServletRequestWrapper extends HttpServletRequestWrapper { private static final Logger logger = LoggerFactory.getLogger(MAPIHttpServletRequestWrapper.class); private Map<String, String[]> parameterMap; // get方法 private byte[] requestBody = null; // post 方法body資料 public MAPIHttpServletRequestWrapper(HttpServletRequest request) { super(request); //快取請求body try { parameterMap = request.getParameterMap(); requestBody = StreamUtils.copyToByteArray(request.getInputStream()); } catch (IOException e) { e.printStackTrace(); } } /** * 獲取所有引數名, get相關方法重寫 * * @return 返回所有引數名 */ @Override public Enumeration<String> getParameterNames() { Vector<String> vector = new Vector<>(parameterMap.keySet()); return vector.elements(); } /** * 獲取指定引數名的值,如果有重複的引數名,則返回第一個的值 接收一般變數 ,如text型別 * * @param name * 指定引數名 * @return 指定引數名的值 */ @Override public String getParameter(String name) { String[] results = parameterMap.get(name); if (results == null || results.length <= 0) return null; else { System.out.println("modify before:" + results[0]); return modify(results[0]); } } /** * 獲取指定引數名的所有值的陣列,如:checkbox的所有資料 * 接收陣列變數 ,如checkobx型別 */ @Override public String[] getParameterValues(String name) { String[] results = parameterMap.get(name); if (results == null || results.length <= 0) return null; else { int length = results.length; for (int i = 0; i < length; i++) { results[i] = modify(results[i]); logger.info("modify before,{}:{}",name, results[i]); } return results; } } /** * 自定義的一個簡單修改原引數的方法,即:給原來的引數值前面添加了一個修改標誌的字串 * * @param string * 原引數值 * @return 修改之後的值 ,這裡並不進行改變 */ private String modify(String string) { return string; } /** * 重寫 getReader() */ @Override public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(getInputStream())); } /** * 重寫 getInputStream() */ @Override public ServletInputStream getInputStream() throws IOException { logger.info("modify before post"); if(requestBody == null){ requestBody= new byte[0]; } final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody); MyServletInputStream myServletInputStream = new MyServletInputStream(bais); return myServletInputStream; } // 定義自己的ServletInputStream class MyServletInputStream extends ServletInputStream{ private InputStream inputStream; public MyServletInputStream(InputStream inputStream){ super(); this.inputStream = inputStream; } @Override public boolean isFinished() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener readListener) { return; } @Override public int read() throws IOException { return inputStream.read(); } } }
6:修改過濾器 dofilter方法
if(request instanceof HttpServletRequest && response instanceof HttpServletResponse){
request = new MAPIHttpServletRequestWrapper((HttpServletRequest) request);
response = new MAPIHttpServletResponseWrapper((HttpServletResponse)response);
}
將tomcat傳過來的httprequest實現類RequestFacade轉換成我們自己寫的類即可,這樣就可以實現多次讀取request裡面的引數值。
總結:其實除了自己可以實現之外也可以使用spring官方提供的元件ContentCachingRequestWrapper,其原理和上面講的是一樣的,只是具體實現細節上有少許不同。
參考資料:
相關推薦
如何實現多次讀取request裡面的引數值
首先需要明確如下幾個概念:1:web開發的時候,過濾器屬於java原生元件,而攔截器屬於spring框架的元件,從它們的引數就可以看出來,過濾器引數為ServletRequest, 而攔截器為HttpServeletRequest,因為spring本來就是web開發針對的就是
實現多次不完全恢復(RAC環境需要將另一節點關閉)
chang hang startup 節點 lec star med immediate 關閉 #查看以resetlogs打開的歷史SQL> SELECT a.INCARNATION#,a.RESETLOGS_CHANGE#,to_char(a.RESETLOGS_T
用面向物件重寫thread 實現多次呼叫一個執行緒
思路: 利用thread類中,run方法在子執行緒中呼叫,其他方法在主執行緒呼叫,所以將生產者寫入主執行緒,將消費者寫入run函式中在子執行緒中執行,完成生產者消費者模型 注意: 1. 要在 init 函式中例項化一個Queue佇列作為生產者消費者中介 2. 要在 init 函式中把d
用面向對象重寫thread 實現多次調用一個線程
reading img 面向對象 run方法 消費者 任務 調用 生產者 true 思路: 利用thread類中,run方法在子線程中調用,其他方法在主線程調用,所以將生產者寫入主線程,將消費者寫入run函數中在子線程中執行,完成生產者消費者模型 註意: 1. 要
Android開發之實現多次點選事件
使用Google提供的api中採用的演算法 能夠實現n次點選事件,我們需要定義一個n長度的陣列,每點選一次將數組裡的內容按序號整體向左移動一格,然後給n-1出即陣列的最後添加當前的時間,如果0個位置的時間大於當前時間減去1000毫秒的話,那麼證明在1000毫秒內點選了n次。實現如
java在OJ上實現多次輸入
import java.util.Scanner; public class Main { public static void main(String args[]) { int a,b; Scanner reader=new Scann
《程式設計珠璣》程式碼之路13:陣列如何線上性時間內實現多次區間修改
給一個數組,每次對某個區間增加某個值,如何線上性時間內完成。 比如一個數組,剛開始都是0吧,如下表,第一行是下標: 0 1 2 3 4 5 6 7 0 0
關於在Spring過濾器中修改request的引數值遇到的問題(三)
繼上一遍為背景 問題描述: 成功解密了reqeust中的引數後,在控制層Controller中獲取到的引數,是沒有解密的引數。例如:在過濾器中修改 引數名為username 的引數值432895328195783915781(一串加密的密文) 為 xiaomin(解密後的
關於在Spring過濾器中修改request的引數值遇到的問題(二)
背景 見上一篇Blog關於在Spring過濾器中修改request的引數值遇到的問題(一) 問題描述 Spring框架,使用過濾器解密request中的引數(修改Request中的值),並傳遞到下一個過濾器 錯誤詳情 第一次的修改方式是這樣的(RSAUtil是封
關於在Spring過濾器中修改request的引數值遇到的問題(一)
關於在Spring過濾器中修改request的引數值遇到的問題 背景 專案上要對前臺傳輸到後臺的資料進行加密(二級等保什麼的),於是想到前臺使用JS進行RSA加密,後臺解密。於是在Spring中新增過濾器,來解密request中傳過來的引數值。 問題描述 前臺登入表
實現多次點選只觸發一次點選事件
$('.sumbit1').click(function () { $('.sumbit1').unbind();//在點選事件裡移除觸發事件 var pad = $('input:radio[name=info]:checked').val(); i
spring應用中多次讀取http post方法中的流(附原始碼)
一、問題簡述 先說下為啥有這個需求,在基於spring的web應用中,一般會在controller層獲取http方法body中的資料。 方式1: 比如http請求的content-type為application/json的情況下,直接用@RequestBody接收。 方式2: 也有像目前我們在做的
python 多次讀取同樣的csv 會發生記憶體報錯 --解決方案
1.多次讀取同樣的csv時,記憶體儲存,可以通過刪除變數且釋放記憶體的形式恢復原有記憶體 (天池O2O) #1754884 record,1053282 with coupon_id,9738 coupon. date_received:20160101~20160615,date:2016
struts2的action從request獲取引數值的兩種方式
無論是提交form表單還是從URL中直接獲取,struts2的action類中獲取請求引數值,總的來說有2種方式: 第一種在action中定義同名變數,提供get/set方法。 第二種方式是手動獲取H
springboot中的攔截器interceptor和過濾器filter,多次獲取request引數
大家好,我是烤鴨: 這是一篇關於springboot的攔截器(interceptor)和過濾器(Filter)。 先說一下過濾器和攔截器。區別:1.servlet請求,順序:Filter ——> interceptor。2.Filter的作用是對所有進行過濾
input file實現多次上傳檔案(不會覆蓋上次上傳的檔案)
html原生的file多選控制元件:<input class="className" type="file" name="name" accept="image/*" multiple /> 存在問題:第一次選擇了n個檔案,第二次選中m個檔案,第二次選擇結束
新手學習FFmpeg - 呼叫API編寫實現多次淡入淡出效果的濾鏡
前面幾篇文章聊了聊FFmpeg的基礎知識,我也是接觸FFmpeg不久,除了時間處理之外,很多高深(濾鏡)操作都沒接觸到。在學習時間處理的時候,都是通過在ffmpeg目前提供的avfilter基礎上面修修補補(補充各種debug log)來驗證想法。 而這次我將嘗試新建立一個avfilter,來實現一個新濾鏡。
recyclerview裡面實現多佈局巢狀recyclerview第一次進入的時候出現自動滾動到第二天reccyclerview問題
今天用recyclerview寫的時候出現一個問題,第一層用的一個imageview,第二層用的是recyclerview,第三層也是recyclerview,,第一層進去的時候出現一個問題,顯示不是從第一層imageview而是自動滾到了第二層recyclerview,查
js實現每次程序發送一個數據 ,多次發送不一樣,5秒後繼續執行多次程序,判斷如果五秒後發送過來的數據和上次不一樣,少的刪除多的增加
增加 開始 後繼 tin key cli 監控 沒有 sop /*存儲設備ID*/var IDSNew = new Array();//判斷是否已經啟用服務var isopen = true;//需要放到接收設備數據處IDSNew[client.deviceId]=new
python文件操作:pickle模塊多次dump後出現的讀取問題
讀寫 class 取出 span 由於 無法 pen 寫文件 color pickle模塊在python中是用於數據持久化的,基本用法涉及到的也就是dump和load,亦或者dumps和loads。 pickle在使用過程中有一個特點,就是由於其特殊的內容標記,使得文件du