Spring?MVC策略模式之MethodArgumentResolver源碼解析
正文
Spring MVC 是一個基于 MVC 設計模式的Web框架,它的核心就是 DispatcherServlet,它相當于請求的中央處理器。在 DispatcherServlet 中,它使用了 MethodArgumentResolver 來解析方法參數。
MethodArgumentResolver 采用一種策略模式,在 Handler 的方法被調用前,Spring MVC 會自動將 HTTP 請求中的參數轉換成方法參數。MethodArgumentResolver 接口的作用就是允許開發(fā)人員自定義參數解析器,以便更好地解析 HTTP 請求中的參數。
例子
我們可以通過實現 MethodArgumentResolver 接口來創(chuàng)建自己的參數解析器。MethodArgumentResolver 通過 supportsParameter() 這個方法用來判斷參數是否可以被當前解析器解析。如果返回 true,則調用 resolveArgument() 方法來解析參數。
下面是一個簡單的例子,演示如何實現一個自定義的 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; } }
在上面的例子中,我們實現了一個 CustomArgumentResolver,用來解析 CustomObject 類型的參數。supportsParameter() 方法判斷參數類型是否為 CustomObject 類型,如果是則返回true。resolveArgument() 方法用來解析參數,將請求中的 "age" 和 "name" 參數設置到 CustomObject 對象中。
源碼分析
Spring MVC 中有很多默認的參數解析器,比如 RequestParamMethodArgumentResolver、PathVariableMethodArgumentResolver、ModelMethodProcessor 等。下面我們來看一下這些解析器的源碼實現。
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 注解參數。
supportsParameter() 方法判斷參數是否有 @RequestParam 注解,如果有則返回 true。
resolveArgument()方法解析參數,獲取 RequestParam 注解的 value、defaultValue 和 required 屬性,然后根據參數名從請求中獲取參數值,最后將參數值轉換成目標類型。
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 注解參數。
supportsParameter() 方法判斷參數是否有 @PathVariable 注解,如果有則返回 true。
resolveArgument() 方法解析參數,獲取 @PathVariable 注解的 value 屬性,然后從請求中獲取 URI 模板變量的值,最后將變量值轉換成目標類型。
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() 方法將返回值轉換成 Map 類型,然后將 Map 中的鍵值對添加到 Model 中。
總結
MethodArgumentResolver 的主要作用就是將請求參數轉換為 Handler 方法的參數。在Spring MVC中,有很多默認的MethodArgumentResolver實現,例如RequestParamMethodArgumentResolver、PathVariableMethodArgumentResolver、ModelAttributeMethodArgumentResolver 等,這些默認的 MethodArgumentResolver 實現可以滿足大多數場景的需求,如果需要自定義 MethodArgumentResolver 實現,可以通過實現 MethodArgumentResolver 接口來實現,這些都遵循了策略模式的設計原則,具有較好的可擴展性和可維護性。
以上就是Spring MVC策略模式之MethodArgumentResolver源碼解析的詳細內容,更多關于Spring MVC MethodArgumentResolver的資料請關注腳本之家其它相關文章!
相關文章
IDEA快速搭建Java開發(fā)環(huán)境的教程圖解
這篇文章主要介紹了IDEA如何快速搭建Java開發(fā)環(huán)境,本文通過圖文并茂的形式給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-11-11