我反正開發(fā)三年多,最常用的還是正常參數(shù)的形式傳遞獲取。不過這個路徑傳參據(jù)說是restful風(fēng)格的常用方式(我是個土鱉,restful風(fēng)格也沒實際用過)。
所以針對多種傳參方式,這里也簡單的記錄一下:
路徑傳參
這個不僅僅是restful風(fēng)格可以用,其實本質(zhì)就是從路徑的某段中獲取參數(shù),只要使用一個注釋:
@PathVariable
下面是簡單的使用 demo:

然后我們?nèi)ソ涌谠L問這個方法:

事實證明,路徑上帶參數(shù),我們用@PathVariable注解獲取到了。
至于最后一個獲取map的用法,其實在注解中是有說到的。

獲取請求頭信息
這個其實也挺有用的,很多時候token都是放在請求頭的,當(dāng)然了還有別的東西也都o(jì)k。而獲取請求頭的方法除了我們在方法中用request獲取,也可以直接獲取。
@RequestHeader
其實這個方法和上面那個差不多??梢灾付ǐ@取,也可以用map獲取全部的。如下demo:

雖然看上去不怎么好看,但是起碼證明確實獲取到請求頭了。這個就過了。
獲取參數(shù)
這個就是正常參數(shù)了,依然一個注解:
@RequestParam
使用方法和上面一樣,指定參數(shù)名稱,或者獲取全部參數(shù)(全部參數(shù)的話必須是String,String 的)。

獲取cookie
依舊一個注解開始:
@CookieValue
需要注意的是這個cookie是沒有map的,看官網(wǎng)文檔的說法,要用cookie接收:

因為我沒前端頁面都,所以這個訪問要用postman來添加cookie再測試:

cookie的接收測試完畢。
常用的就這幾個,接下來重點說參數(shù)獲取的原理(這里用debug一步一步調(diào)試):
首先我們的測試代碼是這樣的:

其實這個是繼續(xù)上文說找到那個請求處理器以后的發(fā)展了,上文說通過DispatcherServlet類的getHandler方法,找到url所對應(yīng)的方法全名稱。這里仍然debug一步一步走:

這里有一個小竅門:一般帶注釋的方法都是值得一看的。我是習(xí)慣性百度翻譯一下看看的。然后繼續(xù)往下走到下一個方法:

ps:這里很多走到接口,然后進(jìn)入實現(xiàn)方法的。反正見到方法就進(jìn)入就行了

其實這個類應(yīng)該是個很重要的類,畢竟大量invoke方法。然后我們一步一步往下走:

因為我這個方法就是普通方法,所以走到這個方法中。其實從它的名字中午文翻譯:反射 處理器 方法。大概可以猜測是方法反射的處理器。
點進(jìn)去以后繼續(xù)一步一步走:

這個方法中代碼很多,但是首先我覺得set本身不會存在賦值行為,所以說前面所有的set我都一路往下。最終走到一個看名字就高大上是方法:

然后點進(jìn)這個方法:

往里走接下來我手欠走過了,如下截圖:

到我當(dāng)前斷點的位置,參數(shù)都已經(jīng)賦值了,因為我斷點已經(jīng)過了, 所以直接看看走過的代碼:

其實這個代碼邏輯還算是簡單,首先創(chuàng)建了一個參數(shù)長度的Object數(shù)組用來存參數(shù)。然后還是一個個 去找參數(shù)的值(中間用到了參數(shù)解析器)。找到以后continue,去找下一個參數(shù)。這里有一點要注意:找不到的話,會報錯的!就是我常見的那個錯:

哎,因為斷點跟丟了現(xiàn)在好難受,我從新走一遍吧。
繼續(xù)上面說的,給參數(shù)賦值的方法如下:

點進(jìn)去查看:

繼續(xù)點進(jìn)去:

這個就用到了我們上面說的spring boot自帶的26個參數(shù)類型解析器??梢渣c進(jìn)去瞅瞅:

進(jìn)方法中看:

這里重點的是我圈起來的:argumentResolvers這個參數(shù)就是spring boot默認(rèn)的所有解析器的集合。
如果這里返回null說明當(dāng)前參數(shù)類型不支持,所以為空,最終出去就直接報錯了。

當(dāng)有這個類型以后去賦值,繼續(xù)往下走到了賦值的方法:

其實這里又查找了下,確定是有這個類型的。繼續(xù)往下走:


其實這里很有意思,大家可以注意這個解析器和注解的名稱密切相關(guān)啊。比如我demo中用的兩個注解:一個@PathVariable一個@RequestParam。都分別有map和普通單個的解析。而且大多數(shù)都挺見名知意的,有空可以詳細(xì)琢磨琢磨這26個解析器。
這里單獨說一下我們的實體類是怎么解析的。正常來講傳一個實體對象,然后debug就行了,我這里直接說結(jié)果了:
實體類的參數(shù)解析器是這個:ServletModelAttributeMethodProcessor
接下來咱們在代碼中一步一步走:

debug代碼走向:

然后我們看看哪個類型解析器解析了這個實體類參數(shù):

這個因為類型解析器有26個,比較多。所以debug 的時候千萬要看好。我就跟丟兩次。然后有些一看就不是的注解就不用進(jìn)去了。比如這個第一個@RequestParam類型的,絕對不可能直接往下走,省的耽誤時間。我直接說比對完是哪個類型了:ServletModelAttributeMethodProcessor。我們可以看下走進(jìn)去的代碼:

然后我們走進(jìn)去看看是怎么綁定屬性的:

這個方法我也是跟著走了好幾次代碼。。這里調(diào)試一定要慢,寧可每個方法都進(jìn)去走無用功也別貪快錯過去。

這里主要用反射創(chuàng)建這個類的實例

這個時候這個實例是空的,里面沒有任何值:

然后重點來了,賦值的方法是這:bindRequestParameters(binder, webRequest);我來回調(diào)試了三四次才確定了這么一個方法。執(zhí)行前attribute沒值,執(zhí)行后有了。。一眨眼就錯過:

反正是點點點進(jìn)到了這個方法,獲取實體類的屬性并賦值

從doBind方法進(jìn)入,然后再進(jìn)入父類的doBind方法:

到這里可以一步一步進(jìn)入看了,也算做到了見名知意(雖然我是進(jìn)了方法才知道干嘛用的)。簡單說下,第一步看有沒有不許出現(xiàn)的屬性。第二步需要的屬性。

這個方法是比對屬性是否可以傳。我們可以設(shè)置實體對象種某些屬性不能這么傳入。如果不能傳的屬性現(xiàn)在傳過來就會報錯:

第二步檢查需要的屬性:

第三步走進(jìn)來賦值:


就是這一步把實現(xiàn)了給attribute賦值。

接下來我們繼續(xù)往下走:

這里只要數(shù)據(jù)類型是對的,一定是可以轉(zhuǎn)化的吧。我暫時沒走過不是的分支。。
最后一直往后走,return attribute,然后我們的參數(shù)已經(jīng)是這個對象了。就完事了。
其實這里可能是因為框架完善的原因,很多設(shè)計是為了擴(kuò)展性或者維護(hù)性啥。所以debug的時候要不斷父子類方法跳,而且還有我上面說的都是大致走向,很多細(xì)節(jié)還有重要的方法都沒怎么說??偨Y(jié)一下我對這塊的理解吧:
- 獲取參數(shù)個數(shù)。
- 判斷參數(shù)是不是spring boot能解析的類型(這里涉及到spring boot默認(rèn)的解析器)。
- 獲取參數(shù)上的注釋和指定名稱(如果指定名稱的參數(shù)不存在則報錯)。
- 將參數(shù)名稱和實際值對應(yīng)起來。
- 有些復(fù)雜類型數(shù)據(jù)用web數(shù)據(jù)綁定器,將請求參數(shù)的值綁定到指定的JavaBean里面。WebDataBinder 利用它里面的 Converters 將請求數(shù)據(jù)轉(zhuǎn)成指定的數(shù)據(jù)類型。再次封裝到JavaBean中。
- 所有的參數(shù)都這么走一遍。
然后就over了。說起來簡簡單單,各種斷點跳轉(zhuǎn)方法幾十個。來回走經(jīng)常容易丟。。真的佩服寫spring 的大佬。
本篇筆記就到這里,如果稍微幫到你了記得點個喜歡點個關(guān)注,也祝大家工作順順利利!另外如果文中哪里表述不嚴(yán)瑾或者有問題歡迎指出!