Spring?MVC策略模式之MethodArgumentResolver源碼解析
正文
Spring MVC 是一個(gè)基于 MVC 設(shè)計(jì)模式的Web框架,它的核心就是 DispatcherServlet,它相當(dāng)于請(qǐng)求的中央處理器。在 DispatcherServlet 中,它使用了 MethodArgumentResolver 來(lái)解析方法參數(shù)。
MethodArgumentResolver 采用一種策略模式,在 Handler 的方法被調(diào)用前,Spring MVC 會(huì)自動(dòng)將 HTTP 請(qǐng)求中的參數(shù)轉(zhuǎn)換成方法參數(shù)。MethodArgumentResolver 接口的作用就是允許開(kāi)發(fā)人員自定義參數(shù)解析器,以便更好地解析 HTTP 請(qǐng)求中的參數(shù)。
例子
我們可以通過(guò)實(shí)現(xiàn) MethodArgumentResolver 接口來(lái)創(chuàng)建自己的參數(shù)解析器。MethodArgumentResolver 通過(guò) supportsParameter() 這個(gè)方法用來(lái)判斷參數(shù)是否可以被當(dāng)前解析器解析。如果返回 true,則調(diào)用 resolveArgument() 方法來(lái)解析參數(shù)。
下面是一個(gè)簡(jiǎn)單的例子,演示如何實(shí)現(xiàn)一個(gè)自定義的 MethodArgumentResolver:
public class CustomArgumentResolver implements MethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.getParameterType().equals(CustomObject.class); } @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { CustomObject customObject = new CustomObject(); customObject.setName(webRequest.getParameter("name")); customObject.setAge(Integer.parseInt(webRequest.getParameter("age"))); return customObject; } }
在上面的例子中,我們實(shí)現(xiàn)了一個(gè) CustomArgumentResolver,用來(lái)解析 CustomObject 類型的參數(shù)。supportsParameter() 方法判斷參數(shù)類型是否為 CustomObject 類型,如果是則返回true。resolveArgument() 方法用來(lái)解析參數(shù),將請(qǐng)求中的 "age" 和 "name" 參數(shù)設(shè)置到 CustomObject 對(duì)象中。
源碼分析
Spring MVC 中有很多默認(rèn)的參數(shù)解析器,比如 RequestParamMethodArgumentResolver、PathVariableMethodArgumentResolver、ModelMethodProcessor 等。下面我們來(lái)看一下這些解析器的源碼實(shí)現(xiàn)。
RequestParamMethodArgumentResolver:
public class RequestParamMethodArgumentResolver implements HandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(RequestParam.class); } @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { // 獲取注解 RequestParam annotation = parameter.getParameterAnnotation(RequestParam.class); String paramName = annotation.value(); String defaultValue = annotation.defaultValue(); boolean required = annotation.required(); String[] paramValues = webRequest.getParameterValues(paramName); if (paramValues == null || paramValues.length == 0) { if (required) { throw new MissingServletRequestParameterException(paramName, parameter.getParameterType().getSimpleName()); } return defaultValue; } if (paramValues.length == 1) { return convertIfNecessary(paramValues[0], parameter.getParameterType()); } return Arrays.stream(paramValues).map(value -> convertIfNecessary(value, parameter.getParameterType())).collect(Collectors.toList()); } }
RequestParamMethodArgumentResolver 用來(lái)解析請(qǐng)求中的 @RequestParam 注解參數(shù)。
supportsParameter() 方法判斷參數(shù)是否有 @RequestParam 注解,如果有則返回 true。
resolveArgument()方法解析參數(shù),獲取 RequestParam 注解的 value、defaultValue 和 required 屬性,然后根據(jù)參數(shù)名從請(qǐng)求中獲取參數(shù)值,最后將參數(shù)值轉(zhuǎn)換成目標(biāo)類型。
PathVariableMethodArgumentResolver:
public class PathVariableMethodArgumentResolver implements HandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(PathVariable.class); } @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { PathVariable annotation = parameter.getParameterAnnotation(PathVariable.class); String attributeName = annotation.value(); Map<String, String> uriTemplateVariables = (Map<String, String>) webRequest.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST); String attributeValue = uriTemplateVariables.get(attributeName); return convertIfNecessary(attributeValue, parameter.getParameterType()); } }
PathVariableMethodArgumentResolver 用來(lái)解析請(qǐng)求中的 @PathVariable 注解參數(shù)。
supportsParameter() 方法判斷參數(shù)是否有 @PathVariable 注解,如果有則返回 true。
resolveArgument() 方法解析參數(shù),獲取 @PathVariable 注解的 value 屬性,然后從請(qǐng)求中獲取 URI 模板變量的值,最后將變量值轉(zhuǎn)換成目標(biāo)類型。
ModelMethodProcessor:
public class ModelMethodProcessor implements HandlerMethodReturnValueHandler { @Override public boolean supportsReturnType(MethodParameter returnType) { return Model.class.isAssignableFrom(returnType.getParameterType()); } @Override public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { Model model = mavContainer.getModel(); model.addAllAttributes((Map<String, ?>) returnValue); } }
用來(lái)處理 Handler 方法的返回值,并將返回值添加到 Model中。
supportsReturnType() 方法判斷返回類型是否為 Model 類型或其子類,如果是則返回 true。
handleReturnValue() 方法將返回值轉(zhuǎn)換成 Map 類型,然后將 Map 中的鍵值對(duì)添加到 Model 中。
總結(jié)
MethodArgumentResolver 的主要作用就是將請(qǐng)求參數(shù)轉(zhuǎn)換為 Handler 方法的參數(shù)。在Spring MVC中,有很多默認(rèn)的MethodArgumentResolver實(shí)現(xiàn),例如RequestParamMethodArgumentResolver、PathVariableMethodArgumentResolver、ModelAttributeMethodArgumentResolver 等,這些默認(rèn)的 MethodArgumentResolver 實(shí)現(xiàn)可以滿足大多數(shù)場(chǎng)景的需求,如果需要自定義 MethodArgumentResolver 實(shí)現(xiàn),可以通過(guò)實(shí)現(xiàn) MethodArgumentResolver 接口來(lái)實(shí)現(xiàn),這些都遵循了策略模式的設(shè)計(jì)原則,具有較好的可擴(kuò)展性和可維護(hù)性。
以上就是Spring MVC策略模式之MethodArgumentResolver源碼解析的詳細(xì)內(nèi)容,更多關(guān)于Spring MVC MethodArgumentResolver的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
IDEA快速搭建Java開(kāi)發(fā)環(huán)境的教程圖解
這篇文章主要介紹了IDEA如何快速搭建Java開(kāi)發(fā)環(huán)境,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-11-11JAVA使用動(dòng)態(tài)代理對(duì)象進(jìn)行敏感字過(guò)濾代碼實(shí)例
這篇文章主要介紹了JAVA使用動(dòng)態(tài)代理對(duì)象進(jìn)行敏感字過(guò)濾代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09Java動(dòng)態(tài)代理和反射機(jī)制詳解
這篇文章主要介紹了Java動(dòng)態(tài)代理和反射機(jī)制,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03Java執(zhí)行cmd命令的舉例與注意事項(xiàng)
Java應(yīng)用程序主要是通過(guò)Runtime和Process兩個(gè)類來(lái)執(zhí)行cmd命令,下面這篇文章主要給大家介紹了關(guān)于Java執(zhí)行cmd命令的方法與注意事項(xiàng),文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-02-02如何使用JCTools實(shí)現(xiàn)Java并發(fā)程序
這篇文章主要介紹了如何使用JCTools實(shí)現(xiàn)Java并發(fā)程序,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下2021-03-03Spring+Http請(qǐng)求+HttpClient實(shí)現(xiàn)傳參
這篇文章主要介紹了Spring+Http請(qǐng)求+HttpClient實(shí)現(xiàn)傳參,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03