爲所欲爲,自定義參數解析器綁定數據。前端
題圖:from Zoommygit
HandlerMethodArgumentResolver
接口,重寫supportsParameter
和resolveArgument
方法,配置文件中加入resolver配置。爲何要自定義一個解析器呢?github
源於須要對前端請求參數進行手動URLDecode,也即除了Web容器自動decode一次,代碼內還須要再decode一次。web
針對這種需求,首先想到的是filter或者interceptor實現,可是因爲HttpServletRequest
對象自己是不提供setParameter()
方法的,所以想要修改request中的參數值爲decode後的值是不易達到的。spring
SpringMVC的HandlerMethodArgumentResolver
,解析器;其功能就是解析request請求參數並綁定數據到Controller的入參上。所以自定義解析器加入URLDecode邏輯便可徹底知足需求。mvc
下面,就一步一步的完成一個解析器由簡到繁的實現過程。ide
具體如何自定義一個參數解析器呢?學習
其實很簡單,一句話——實現HandlerMethodArgumentResolver
接口,重寫supportsParameter
和resolveArgument
方法,配置文件中加入resolver配置。ui
示例代碼以下:this
自定義解析器實現
1 |
public class MyArgumentsResolver implements HandlerMethodArgumentResolver { |
自定義註解
1 |
|
在springmvc配置文件中註冊解析器
1 |
<mvc:annotation-driven> |
好了,如今解析器會把全部應用了@MyParam
註解的參數都賦值爲null
。
對於如何解析原始類型參數,SpringMVC已經有了一個內置的實現——RequestParamMethodArgumentResolver
,所以徹底能夠參考這個實現來自定義咱們本身的解析器。
如上所述,解析器邏輯的主要部分都在resolveArgument
方法內,這裏就說說自定義該方法的實現。
1 |
|
對於如何解析對象類型參數,SpringMVC內也有了一個內置的實現——ModelAttributeMethodProcessor
,咱們也是參考這個實現來自定義咱們本身的解析器。
一樣,resolveArgument
方法示例以下
1 |
|
到目前爲止,不論對於原始類型或者對象類型的參數,咱們均可以自定義一個參數解析器了,可是還有一個很嚴重的問題存在——沒法讓自定義解析器和現有解析器同時生效。
舉個例子,public String myController(@Valid @MyParam param, BindingResult result){}
,這個方法在執行時是會報錯的。他會提示相似以下報錯:
An Errors/BindingResult argument is expected to be declared immediately after the model attribute, the @RequestBody or the @RequestPart arguments
是SpringMVC不支持同時使用兩個解析器嗎?public String myController(@Valid @ModelAttribute param, BindingResult result){}
,也是兩個內置解析器,沒有任何問題。
再去看ModelAttributeMethodProcessor
的實現,原來是對@Valid
作了兼容處理。
所以, 若是須要多個解析器同時生效須要在一個解析器中對其餘解析器作兼容。
這裏僅以對@Valid
進行兼容處理爲例,在解析對象類型的解析器實現中進行修改
1 |
|
OK,到這裏,咱們自定義的解析器已經能夠算是一個完善的參數解析器了,若是有對其餘解析器作兼容的須要,只要參照此類方法稍做修改便可。
還記得此次自定義解析器的緣由嗎——須要對前端請求參數進行手動URLDecode,也即除了Web容器自動decode一次,代碼內還須要再decode一次。
事實證實,根本不須要進行二次decode,寫出的解析器也就無疾而終了,僅存這篇整理,算是對SpringMVC解析器的一次學習總結吧。
http://coderec.cn/2016/08/27/%E4%B8%80%E6%AD%A5%E4%B8%80%E6%AD%A5%E8%87%AA%E5%AE%9A%E4%B9%89SpringMVC%E5%8F%82%E6%95%B0%E8%A7%A3%E6%9E%90%E5%99%A8/