從springmvc源碼看方法參數綁定的註解和返回值處理

在使用springmvc提供的註解進行方法參數的解析綁定和方法返回值處理的時候,比如說有時候會報出令人不解的400或500之類的錯誤;自以爲掌握了註解的用法但是實現起來複雜不簡潔,這情況下進行參數綁定的擴展更爲合理,等等這些情況都需要我們能深入地瞭解springmvc的內部實現。在進行錯誤調試的時候,如果能根據不同的參數類型,註解和返回值類型深入到springmvc具體的實現類源代碼進行跟蹤查看,有助於我們高效優雅地使用springmvc。

 

1.進行方法參數值的解析的接口是HandlerMethodArgumentResolver

下面是一些具體的實現類,它們針對不同的註解實現不同的解析綁定功能:

1. RequestParamMethodArgumentResolver

 支持帶有@RequestParam註解的參數或帶有MultipartFile類型的參數

2. RequestParamMapMethodArgumentResolver

  支持帶有@RequestParam註解的參數 && @RequestParam註解的屬性value存在 && 參數類型是實現Map接口的屬性

3. PathVariableMethodArgumentResolver

支持帶有@PathVariable註解的參數 且如果參數實現了Map接口,@PathVariable註解需帶有value屬性

4. MatrixVariableMethodArgumentResolver

支持帶有@MatrixVariable註解的參數 且如果參數實現了Map接口,@MatrixVariable註解需帶有value屬性 

5. RequestResponseBodyMethodProcessor

解析綁定帶有@RequestBody的方法參數和帶有@ResponseBody的方法返回值

6. ServletRequestMethodArgumentResolver

 參數類型是實現或繼承或是WebRequest、ServletRequest、MultipartRequest、HttpSession、Principal、Locale、TimeZone、InputStream、Reader、HttpMethod這些類。

7. ServletResponseMethodArgumentResolver

 參數類型是實現或繼承或是ServletResponse、OutputStream、Writer這些類

8. RedirectAttributesMethodArgumentResolver

 參數是實現了RedirectAttributes接口的類

9. HttpEntityMethodProcessor

 參數類型是HttpEntity

從名字我們也看的出來, 以Resolver結尾的是實現了HandlerMethodArgumentResolver接口的類,以Processor結尾的是實現了HandlerMethodArgumentResolver和HandlerMethodReturnValueHandler的類。

 

注意:如果controller的方法沒有任何參數的註解,但有參數對象而且參數對象的類型是簡單類型,則會默認調用RequestParamMethodArgumentResolver類進行解析,從httpServletRequest中獲取parameter,然後調用參數對象的set方法進行注入。

這是RequestParamMethodArgumentResolver類所支持的解析類型方法:

 

public boolean supportsParameter(MethodParameter parameter) {
		Class<?> paramType = parameter.getParameterType();
		if (parameter.hasParameterAnnotation(RequestParam.class)) {
			if (Map.class.isAssignableFrom(paramType)) {
				String paramName = parameter.getParameterAnnotation(RequestParam.class).value();
				return StringUtils.hasText(paramName);
			}
			else {
				return true;
			}
		}
		else {
			if (parameter.hasParameterAnnotation(RequestPart.class)) {
				return false;
			}
			else if (MultipartFile.class.equals(paramType) || "javax.servlet.http.Part".equals(paramType.getName())) {
				return true;
			}
			else if (this.useDefaultResolution) {
				return BeanUtils.isSimpleProperty(paramType);//判斷是否是簡單類型
			}
			else {
				return false;
			}
		}
	}


判斷簡單類型的方法:

 

 

public static boolean isSimpleValueType(Class<?> clazz) {
		return ClassUtils.isPrimitiveOrWrapper(clazz) || clazz.isEnum() ||//isPrimitiveOrWrapper方法是判斷參數類型是否是基本類或基本類的包裝類
				CharSequence.class.isAssignableFrom(clazz) ||
				Number.class.isAssignableFrom(clazz) ||
				Date.class.isAssignableFrom(clazz) ||
				clazz.equals(URI.class) || clazz.equals(URL.class) ||
				clazz.equals(Locale.class) || clazz.equals(Class.class);
	}

 

 

 

如果沒有註解的參數的類型不是簡單類型而是複合類型,就是用類ModelAttributeMethodProcessor來解析:

 

/**
	 * @return true if the parameter is annotated with {@link ModelAttribute}
	 * or in default resolution mode also if it is not a simple type.
	 */
	public boolean supportsParameter(MethodParameter parameter) {
		if (parameter.hasParameterAnnotation(ModelAttribute.class)) {
			return true;
		}
		else if (this.annotationNotRequired) {
			return !BeanUtils.isSimpleProperty(parameter.getParameterType());
		}
		else {
			return false;
		}
	}

 

 

 

 

 

 

 

2.方法返回值處理接口HandlerMethodReturnValueHandler

下面是一些具體的實現類,它們針對不同的註解或返回值類型實現不同的功能:

1. ModelAndViewMethodReturnValueHandler

返回值類型是ModelAndView或其子類

2. ModelMethodProcessor

返回值類型是Model或其子類

3. ViewMethodReturnValueHandler

返回值類型是View或其子類 

4. HttpHeadersReturnValueHandler

返回值類型是HttpHeaders或其子類  

5. ModelAttributeMethodProcessor

返回值有@ModelAttribute註解

6. ViewNameMethodReturnValueHandler

返回值是void或String,並且返回值沒有註解

7.RequestResponseBodyMethodProcessor

返回值有@ResponseBody註解

參考自:http://www.cnblogs.com/fangjian0423/p/springMVC-request-param-analysis.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章