springmvc揭秘參數解析

參數解析

說到參數解析,springmvc中處理參數的是HandlerMethodArgumentResolver接口

public?interface?HandlerMethodArgumentResolver?{

???//?判斷是否支持該類型參數
???boolean?supportsParameter(MethodParameter?parameter);

???//?進行參數解析
???Object?resolveArgument(MethodParameter?parameter,?ModelAndViewContainer?mavContainer,
?????????NativeWebRequest?webRequest,?WebDataBinderFactory?binderFactory)
?throws?Exception
;

}

其有一個抽象實現類AbstractNamedValueMethodArgumentResolver,有很多有用的子類

  • MapMethodProcessor

    這個用來處理 Map/ModelMap 類型的參數,解析完成后返回 model。

  • PathVariableMethodArgumentResolver

這個用來處理使用了 @PathVariable 注解并且參數類型不為 Map 的參數,參數類型為 Map 則使用 PathVariableMapMethodArgumentResolver 來處理。

  • PathVariableMapMethodArgumentResolver

見上。

  • ErrorsMethodArgumentResolver

這個用來處理 Error 參數,例如我們做參數校驗時的 BindingResult。

  • AbstractNamedValueMethodArgumentResolver

    這個用來處理 key/value 類型的參數,如請求頭參數、使用了 @PathVariable 注解的參數以及 Cookie 等。

  • RequestHeaderMethodArgumentResolver

這個用來處理使用了 @RequestHeader 注解,并且參數類型不是 Map 的參數(參數類型是 Map 的使用 RequestHeaderMapMethodArgumentResolver)。

  • RequestHeaderMapMethodArgumentResolver

見上。

  • RequestAttributeMethodArgumentResolver

這個用來處理使用了 @RequestAttribute 注解的參數。

  • RequestParamMethodArgumentResolver

這個功能就比較廣了。使用了 @RequestParam 注解的參數、文件上傳的類型 MultipartFile、或者一些沒有使用任何注解的基本類型(Long、Integer)以及 String 等,都使用該參數解析器處理。需要注意的是,如果 @RequestParam 注解的參數類型是 Map,則該注解必須有 name 值,否則解析將由 RequestParamMapMethodArgumentResolver 完成。

  • RequestParamMapMethodArgumentResolver

見上。

  • AbstractCookieValueMethodArgumentResolver

這個是一個父類,處理使用了 @CookieValue 注解的參數。

  • ServletCookieValueMethodArgumentResolver

這個處理使用了 @CookieValue 注解的參數。

  • MatrixVariableMethodArgumentResolver

這個處理使用了 @MatrixVariable 注解并且參數類型不是 Map 的參數,如果參數類型是 Map,則使用 MatrixVariableMapMethodArgumentResolver 來處理。

  • MatrixVariableMapMethodArgumentResolver

見上。

  • SessionAttributeMethodArgumentResolver

這個用來處理使用了 @SessionAttribute 注解的參數。

  • ExpressionValueMethodArgumentResolver

這個用來處理使用了 @Value 注解的參數。

  • ServletResponseMethodArgumentResolver

這個用來處理 ServletResponse、OutputStream 以及 Writer 類型的參數。

  • ModelMethodProcessor

這個用來處理 Model 類型參數,并返回 model。

  • ModelAttributeMethodProcessor

這個用來處理使用了 @ModelAttribute 注解的參數。

  • SessionStatusMethodArgumentResolver

這個用來處理 SessionStatus 類型的參數。

  • PrincipalMethodArgumentResolver

這個用來處理 Principal 類型參數

  • AbstractMessageConverterMethodArgumentResolver

這是一個父類,當使用 HttpMessageConverter 解析 requestbody 類型參數時,相關的處理類都會繼承自它。

  • RequestPartMethodArgumentResolver

這個用來處理使用了 @RequestPart 注解、MultipartFile 以及 Part 類型的參數。

  • RequestResponseBodyMethodProcessor

這個用來處理添加了 @RequestBody 注解的參數。

  • HttpEntityMethodProcessor

這個用來處理 HttpEntity 和 RequestEntity 類型的參數。

  • ServletWebArgumentResolverAdapter

這個給父類提供 request。

  • UriComponentsBuilderMethodArgumentResolver

這個用來處理 UriComponentsBuilder 類型的參數。

  • ServletRequestMethodArgumentResolver

這個用來處理 WebRequest、ServletRequest、MultipartRequest、HttpSession、Principal、InputStream、Reader、HttpMethod、Locale、TimeZone、ZoneId 類型的參數。

  • HandlerMethodArgumentResolverComposite

這個看名字就知道是一個組合解析器,它是一個代理,具體代理其他干活的那些參數解析器。

  • RedirectAttributesMethodArgumentResolver

這個用來處理 RedirectAttributes 類型的參數

這些解析器是在執行

//?Actually?invoke?the?handler.
mv?=?ha.handle(processedRequest,?response,?mappedHandler.getHandler());

執行對應的Controller方法前來進行參數解析時調用的org.springframework.web.method.support.InvocableHandlerMethod#getMethodArgumentValues

if?(this.argumentResolvers.supportsParameter(parameter))?{
???try?{
??????args[i]?=?this.argumentResolvers.resolveArgument(
????????????parameter,?mavContainer,?request,?this.dataBinderFactory);
??????continue;
???}
???catch?(Exception?ex)?{
??????if?(logger.isDebugEnabled())?{
?????????logger.debug(getArgumentResolutionErrorMessage("Failed?to?resolve",?i),?ex);
??????}
??????throw?ex;
???}
}

RequestResponseBodyMethodProcessor調用消息解析器

我之前只知道解析@RequestBody需要使用消息解析器HttpMessageConverter,但是沒有深究是從哪調用的。突然看到消息解析我才知道原來是RequestResponseBodyMethodProcessor調用的。org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor#resolveArgument來進行參數解析

遍歷消息解析器找到可以進行解析該類型的消息解析器

for?(HttpMessageConverter<?>?converter?:?this.messageConverters)?{

對于簡單的參數會以簡單的轉換器進行轉換,而這些簡單的轉換器是Spring MVC自身已經提供了的,但是如果是轉換HTTP請求體,會調用HttpMessageConverter接口的方法對請求體的信息進行轉換

public?interface?HttpMessageConverter<T>?{

???
??//?是否可讀,clazz為java類型,mediaType為HTTP請求類型
???boolean?canRead(Class<?>?clazz,?MediaType?mediaType);

???
??//?判斷clazz類型是否能夠轉換為mediaType媒體類型,其中clazz為java類型,mediaType為HTTP響應類型
???boolean?canWrite(Class<?>?clazz,?MediaType?mediaType);

???
??//?可支持的媒體類型列表
???List<MediaType>?getSupportedMediaTypes();

???
??//?當canRead驗證通過后,讀入HTTP請求信息
???T?read(Class<??extends?T>?clazz,?HttpInputMessage?inputMessage)
?????????throws?IOException,?HttpMessageNotReadableException
;

???
??//?單canWrite方法驗證通過后,寫入響應
???void?write(T?t,?MediaType?contentType,?HttpOutputMessage?outputMessage)
?????????throws?IOException,?HttpMessageNotWritableException
;

}

HttpMessageConverter接口是將HTTP請求體轉換為對應的java對象,對于HTTP參數和其他內容需要使用參數轉換規則

參數轉換

Spring MVC中,是通過WebDataBinder機制來獲取參數的,它的主要作用是解析HTTP請求的上下文,然后在控制器的調用之前轉換參數并且提供驗證的功能,為調用控制器方法做準備。處理器會從HTTP請求中讀取數據,然后通過三種接口進行各類參數轉換(Converter、Formatter、GenericConverter)。

Converter接口

Converter接口是一個普通的轉換器

public?interface?Converter<S,?T>?{

?
?T?convert(S?source);

}

可以將某個類型轉換為另一個類型

Formatter接口

Formatter接口是一個格式化轉換器,如將日期字符串格式化

public?interface?Formatter<T>?extends?Printer<T>,?Parser<T>?{

}
GenericConverter接口

GenericConverter接口是將HTTP參數轉換為數組

public?interface?GenericConverter?{

???
???Set<ConvertiblePair>?getConvertibleTypes();

???
???Object?convert(Object?source,?TypeDescriptor?sourceType,?TypeDescriptor?targetType);


???/**
????*?Holder?for?a?source-to-target?class?pair.
????*/

???final?class?ConvertiblePair?{

??????private?final?Class<?>?sourceType;

??????private?final?Class<?>?targetType;

??????/**
???????*?Create?a?new?source-to-target?pair.
???????*?@param?sourceType?the?source?type
???????*?@param?targetType?the?target?type
???????*/

??????public?ConvertiblePair(Class<?>?sourceType,?Class<?>?targetType)?{
?????????Assert.notNull(sourceType,?"Source?type?must?not?be?null");
?????????Assert.notNull(targetType,?"Target?type?must?not?be?null");
?????????this.sourceType?=?sourceType;
?????????this.targetType?=?targetType;
??????}

??????public?Class<?>?getSourceType()?{
?????????return?this.sourceType;
??????}

??????public?Class<?>?getTargetType()?{
?????????return?this.targetType;
??????}

??????@Override
??????public?boolean?equals(Object?other)?{
?????????if?(this?==?other)?{
????????????return?true;
?????????}
?????????if?(other?==?null?||?other.getClass()?!=?ConvertiblePair.class)?{
????????????return?false;
?????????}
?????????ConvertiblePair?otherPair?=?(ConvertiblePair)?other;
?????????return?(this.sourceType?==?otherPair.sourceType?&&?this.targetType?==?otherPair.targetType);
??????}

??????@Override
??????public?int?hashCode()?{
?????????return?(this.sourceType.hashCode()?*?31?+?this.targetType.hashCode());
??????}

??????@Override
??????public?String?toString()?{
?????????return?(this.sourceType.getName()?+?"?->?"?+?this.targetType.getName());
??????}
???}

}
ConversionService接口
public?interface?ConversionService?{

???boolean?canConvert(Class<?>?sourceType,?Class<?>?targetType);

???boolean?canConvert(TypeDescriptor?sourceType,?TypeDescriptor?targetType);

???<T>?T?convert(Object?source,?Class<T>?targetType);

???Object?convert(Object?source,?TypeDescriptor?sourceType,?TypeDescriptor?targetType);

}

數據驗證

Validator接口用于數據驗證

public?interface?Validator?{

??//?判斷當前驗證器是否支持該Class類型的驗證
???boolean?supports(Class<?>?clazz);

???
??//?如果supports返回true,則執行該方法驗證邏輯
???void?validate(Object?target,?Errors?errors);

}

WebDataBinder還可以進行驗證,使用@InitBinder注解可以允許在進入控制器方法之前修改WebDataBinder機制,可以來設置驗證器

通過WebDataBinder#setValidator來添加驗證器

https://zhhll.icu/2023/框架/springmvc/底層剖析/6.參數解析/

本文由 mdnice 多平臺發布

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

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

相關文章

[羊城杯 2021]BabySmc

運行就是輸入flag 不知道怎么跳過去的 這個應該就是smc加密的函數了 運行完這個函數才能繼續往下 int __cdecl main(int argc, const char **argv, const char **envp) {__int64 v3; // rbx__int64 v4; // r12__int64 v5; // r13unsigned __int64 v6; // raxchar v7; // spcha…

學習Vue中圖片上傳前進行壓縮的實現方法

學習Vue中圖片上傳前進行壓縮的實現方法 一、前言1. 為什么要在客戶端進行圖片壓縮&#xff1f;2. Vue組件中實現圖片上傳前壓縮的方法3. 注意事項與優化4. 總結 一、前言 在Web開發中&#xff0c;圖片上傳是一個常見的功能需求&#xff0c;而客戶端對圖片進行壓縮可以有效減小…

企業如何進行快遞運費對賬?

在電子面單寄件取代手寫紙質面單之后&#xff0c;加上月結寄件模式的推行&#xff0c;企業快遞運費對賬&#xff0c;成了行政的一個難題...... 早期的手寫紙質面單寄件&#xff0c;企業行政或者財務相關人員&#xff0c;遵循寄前審批&#xff0c;寄后報銷的原則進行對賬。隨著電…

FinalShell無法連接Linux

Linux使用Vmware會創建一個網絡&#xff0c;讓兩個子網處于一個網關&#xff0c;這樣就能在windows中連接Linux&#xff0c;只有在這種情況下才能FinalShell才能連接Linux

面試題合集(2)

1. Self Attention的時候 Q K T QK^T QKT之后要除以 d ? \sqrt{d}? d ?? 參考蘇劍林大神&#xff1a; 淺談Transformer的初始化、參數化與標準化 模型初始化&#xff1a;介紹了常用的采樣分布&#xff0c;包括正態分布、均勻分布和截尾正態分布。并從代數角度理解初始化方…

module_param的用法

在Linux內核模塊編程中,`module_param`宏允許你聲明一個模塊參數。模塊參數是指可以在加載模塊時從命令行設置的參數,也可以通過/sys文件系統(如果內核配置了CONFIG_SYSFS)在模塊加載后進行修改。這些參數對于調整模塊的行為而不需要重新編譯模塊代碼非常有用。 使用方法 …

KT6368A雙模藍牙芯片上電到正常發送AT指令或指令復位需要多久

一、簡介 KT6368A芯片上電到正常發送AT指令&#xff0c;或者開啟藍牙廣播被搜索到&#xff0c;或者指令復位需要多久等等系列問題總結 詳細描述 其實這些問題歸結到一起&#xff0c;就還是一個問題&#xff0c;芯片上電需要多久的時間 在另外一份文檔里面&#xff0c;是有描…

跟我學C++中級篇——if constexpr的應用

一、場景應用 在一個開發場景下&#xff0c;需要動態處理不同類型的數據寫入。本來這個非常簡單&#xff0c;只要定義一個模板即可搞定&#xff0c;但這里偏偏有一個細節&#xff0c;是調用別人的庫來實現寫入。而這個庫對不同的數據類型的寫入&#xff0c;提供了N種不同的函數…

Python實戰開發及案例分析(28)—— 預編碼算法

預編碼算法&#xff08;Precoding Algorithm&#xff09;通常用于無線通信系統中&#xff0c;尤其是多輸入多輸出&#xff08;MIMO&#xff09;系統中&#xff0c;以提高數據傳輸的可靠性和效率。預編碼是為了在發送端對信號進行處理&#xff0c;以優化傳輸性能。 在MIMO系統中…

Java設計模式 _行為型模式_訪問者模式

一、訪問者模式 1、訪問者模式 訪問者模式&#xff08;Visitor Pattern&#xff09;是一種行為型模式。它允許在不修改已有類結構的情況下&#xff0c;向類中添加新的操作。訪問者模式通過將操作封裝在一個訪問者對象中&#xff0c;使得可以在不改變各個元素類的前提下&#x…

RedisTemplate實戰應用--隊列等

一、RedisTemplate隊列插入 1、從集合左邊插入值 https://blog.csdn.net/weixin_43658899/article/details/121040307 leftPush(K key, V value) redisTemplate.opsForList().leftPush("leftdatakey","bbbb");2、從集合左邊開始在v1值后邊插入新值v2 le…

使用 Django 連接 MySQL 數據庫

文章目錄 步驟一&#xff1a;安裝必要的庫和驅動步驟二&#xff1a;配置數據庫連接步驟三&#xff1a;執行數據庫遷移步驟四&#xff1a;開始使用 MySQL 數據庫創建一個模型遷移模型到數據庫使用模型進行數據操作創建新記錄&#xff1a;查詢記錄&#xff1a;更新記錄&#xff1…

Mac安裝第三方軟件的命令安裝方式

場景&#xff1a; 打開終端命令行&#xff0c;sudo xattr -rd com.apple.quarantine&#xff0c;注意最后quarantine 后面加一個空格&#xff01;然后打開Finder&#xff08;訪達&#xff09;&#xff0c;點擊左側的 應用程序&#xff0c;找到相關應用&#xff0c;拖進終端qua…

(超實用)京東訂單數據分析案例-維度下鉆

1&#xff0c;數據介紹&#xff0c;字段了解 盡可能熟悉業務&#xff0c;多知道字段的含義&#xff0c;字段字段間的邏輯關系&#xff0c;后期數據分析思路才能更清晰&#xff0c;結果才能更準確 2&#xff0c;訂單數據分析基本思路 維度下鉆 3&#xff0c;代碼實現全流程思路…

華為telnet的兩種認證方式

華為telnet的兩種認證方式 實驗拓撲&#xff1a; 實驗要求&#xff1a; 1.采用普通密碼認證實現telnet 遠程登錄機房設備R3 2.采用AAA認證服務方式實現telnet 遠程登錄機房設備R3 實驗步驟&#xff1a; 1.完成基本配置&#xff08;設備接口配置IP&#xff0c;此步驟略過&#…

Facebook的隱私保護挑戰:用戶數據安全的新時代

在全球范圍內&#xff0c;Facebook已經成為了不可忽視的社交媒體巨頭&#xff0c;它連接著超過20億的活躍用戶。然而&#xff0c;隨著其影響力的不斷擴大&#xff0c;關于用戶隱私和數據安全的問題也愈加引人關注。本文將深入探討Facebook面臨的隱私保護挑戰&#xff0c;以及它…

一個程序員的牢獄生涯(47)學法

星期一 學法 二鋪不知道什么時候走到了我的身邊,向我說道,這是二鋪在我進來號子后主動過來和我說話。 我聽到二鋪這聲突兀的說話后,抬起頭。這時我才看到,除了二鋪,還有六子、棍子都圍在我的身邊,看著我。雖然六子和棍子依舊一副‘吊兒郎當’的樣子,但我從他們幾個的眼神…

解析前端開發中同源策略與配置代理

提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 文章目錄 前言一、pandas是什么&#xff1f;二、使用步驟 1.引入庫2.讀入數據總結 前言 在前端開發中&#xff0c;跨域請求是一個常見的問題。同源策略限制了瀏覽器中一個頁面…

C++高手進階:Windows 模塊加載的藝術與策略

前文我們講到了怎么不依賴第三庫&#xff0c;搭建自己的測試框架 沒有看的讀者可以通過這個鏈接自行閱讀&#xff1a; &#x1f449;&#x1f449;&#x1f449; 自力更生&#xff1a;0依賴三方庫&#xff0c;手把手教你打造專屬C測試框架 作為項目開發來說&#xff0c;我們通常…

Leetcode:最長回文子串

題目鏈接&#xff1a;5. 最長回文子串 - 力扣&#xff08;LeetCode&#xff09; 普通版本&#xff08;暴力枚舉&#xff09; 解題關鍵&#xff1a; 1、記錄最長回文字串的長度和起始字符的下標 2、判斷回文字串的邏輯與整體邏輯分離 3、先確定尋找回文字串的邊界范圍后從兩邊向…