隨心所欲,自定義參數解析器綁定數據。
題圖:from Zoommy
干貨
- SpringMVC解析器用於解析request請求參數並綁定數據到Controller的入參上。
- 自定義一個參數解析器需要實現
HandlerMethodArgumentResolver
接口,重寫supportsParameter
和resolveArgument
方法,配置文件中加入resolver配置。 - 如果需要多個解析器同時生效需要在一個解析器中對其他解析器做兼容
緣起
為什么要自定義一個解析器呢?
源於需要對前端請求參數進行手動URLDecode,也即除了Web容器自動decode一次,代碼內還需要再decode一次。
針對這種需求,首先想到的是filter或者interceptor實現,但是由於HttpServletRequest
對象本身是不提供setParameter()
方法的,因此想要修改request中的參數值為decode后的值是不易達到的。
SpringMVC的HandlerMethodArgumentResolver
,解析器;其功能就是解析request請求參數並綁定數據到Controller的入參上。因此自定義解析器加入URLDecode邏輯即可完全滿足需求。
下面,就一步一步的完成一個解析器由簡到繁的實現過程。
實現一個極其簡單的參數解析器
具體如何自定義一個參數解析器呢?
其實很簡單,一句話——實現HandlerMethodArgumentResolver
接口,重寫supportsParameter
和resolveArgument
方法,配置文件中加入resolver配置。
示例代碼如下:
-
自定義解析器實現
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26public class MyArgumentsResolver implements HandlerMethodArgumentResolver {
/**
* 解析器是否支持當前參數
*/
-
自定義注解
1
2
3
4
5 -
在springmvc配置文件中注冊解析器
1
2
3
4
5
6<mvc:annotation-driven>
<!--MyArgumentsResolver-->
<mvc:argument-resolvers>
<bean class="xxx.xxx.xxx.MyArgumentsResolver"/>
</mvc:argument-resolvers>
</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/