Spring?MVC策略模式之MethodArgumentResolver源碼解析
正文
Spring MVC 是一個基于 MVC 設(shè)計模式的Web框架,它的核心就是 DispatcherServlet,它相當(dāng)于請求的中央處理器。在 DispatcherServlet 中,它使用了 MethodArgumentResolver 來解析方法參數(shù)。
MethodArgumentResolver 采用一種策略模式,在 Handler 的方法被調(diào)用前,Spring MVC 會自動將 HTTP 請求中的參數(shù)轉(zhuǎn)換成方法參數(shù)。MethodArgumentResolver 接口的作用就是允許開發(fā)人員自定義參數(shù)解析器,以便更好地解析 HTTP 請求中的參數(shù)。
例子
我們可以通過實現(xiàn) MethodArgumentResolver 接口來創(chuàng)建自己的參數(shù)解析器。MethodArgumentResolver 通過 supportsParameter() 這個方法用來判斷參數(shù)是否可以被當(dāng)前解析器解析。如果返回 true,則調(diào)用 resolveArgument() 方法來解析參數(shù)。
下面是一個簡單的例子,演示如何實現(xiàn)一個自定義的 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;
}
}
在上面的例子中,我們實現(xiàn)了一個 CustomArgumentResolver,用來解析 CustomObject 類型的參數(shù)。supportsParameter() 方法判斷參數(shù)類型是否為 CustomObject 類型,如果是則返回true。resolveArgument() 方法用來解析參數(shù),將請求中的 "age" 和 "name" 參數(shù)設(shè)置到 CustomObject 對象中。
源碼分析
Spring MVC 中有很多默認(rèn)的參數(shù)解析器,比如 RequestParamMethodArgumentResolver、PathVariableMethodArgumentResolver、ModelMethodProcessor 等。下面我們來看一下這些解析器的源碼實現(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 用來解析請求中的 @RequestParam 注解參數(shù)。
supportsParameter() 方法判斷參數(shù)是否有 @RequestParam 注解,如果有則返回 true。
resolveArgument()方法解析參數(shù),獲取 RequestParam 注解的 value、defaultValue 和 required 屬性,然后根據(jù)參數(shù)名從請求中獲取參數(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 用來解析請求中的 @PathVariable 注解參數(shù)。
supportsParameter() 方法判斷參數(shù)是否有 @PathVariable 注解,如果有則返回 true。
resolveArgument() 方法解析參數(shù),獲取 @PathVariable 注解的 value 屬性,然后從請求中獲取 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);
}
}
用來處理 Handler 方法的返回值,并將返回值添加到 Model中。
supportsReturnType() 方法判斷返回類型是否為 Model 類型或其子類,如果是則返回 true。
handleReturnValue() 方法將返回值轉(zhuǎn)換成 Map 類型,然后將 Map 中的鍵值對添加到 Model 中。
總結(jié)
MethodArgumentResolver 的主要作用就是將請求參數(shù)轉(zhuǎn)換為 Handler 方法的參數(shù)。在Spring MVC中,有很多默認(rèn)的MethodArgumentResolver實現(xiàn),例如RequestParamMethodArgumentResolver、PathVariableMethodArgumentResolver、ModelAttributeMethodArgumentResolver 等,這些默認(rèn)的 MethodArgumentResolver 實現(xiàn)可以滿足大多數(shù)場景的需求,如果需要自定義 MethodArgumentResolver 實現(xiàn),可以通過實現(xiàn) MethodArgumentResolver 接口來實現(xiàn),這些都遵循了策略模式的設(shè)計原則,具有較好的可擴(kuò)展性和可維護(hù)性。
以上就是Spring MVC策略模式之MethodArgumentResolver源碼解析的詳細(xì)內(nèi)容,更多關(guān)于Spring MVC MethodArgumentResolver的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java中構(gòu)造器內(nèi)部調(diào)用構(gòu)造器實例詳解
在本篇文章里小編給大家分享的是關(guān)于java中構(gòu)造器內(nèi)部調(diào)用構(gòu)造器實例內(nèi)容,需要的朋友們可以學(xué)習(xí)下。2020-05-05
maven打包成第三方j(luò)ar包且把pom依賴包打入進(jìn)來的方法
這篇文章主要介紹了maven打包成第三方j(luò)ar包且把pom依賴包打入進(jìn)來的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-11-11
Spring Boot 整合持久層之JdbcTemplate
持久層是 Java EE 中訪問數(shù)據(jù)庫的核心操作,Spring Boot 中對常見的持久層框架都提供了自動化配置,例如 JdbcTemplate 、 JPA 等,Mybatis 的自動化配置則是 Mybatis 官方提供的2022-08-08
Spring?Boot?快速使用?HikariCP?連接池配置詳解
Spring Boot 2.x 將其作為默認(rèn)的連接池組件,項目中添加 spring-boot-starter-jdbc 或 spring-boot-starter-data-jpa 模塊后,HikariCP 依賴會被自動引入,這篇文章主要介紹了Spring?Boot使用HikariCP連接池配置詳解,需要的朋友可以參考下2023-06-06
springboot整合redis修改分區(qū)的操作流程
這篇文章主要介紹了springboot整合redis修改分區(qū)的操作流程,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07

