Spring 解析器自定义

HandlerMethodArgumentResolver接口的抽象类:AbstractMessageConverterMethodArgumentResolver仅仅引入了HttpMessageConverter,即转换的工作有这些HttpMessageConverter来完成具体的转换和判断由子类来实现。 
如下:

public abstract class AbstractMessageConverterMethodArgumentResolver implements HandlerMethodArgumentResolver {

	protected final Log logger = LogFactory.getLog(getClass());

	protected final List<HttpMessageConverter<?>> messageConverters;

	protected final List<MediaType> allSupportedMediaTypes;
     //略
}
 AbstractMessageConverterMethodArgumentResolver 的抽象子类AbstractMessageConverterMethodProcessor仅仅是加入了对响应数据进行转换的支持。  也就是AbstractMessageConverterMethodProcessor的子类不仅可以用来转换请求数据,也可以用来转换响应数据。 
AbstractMessageConverterMethodProcessor的子类HttpEntityMethodProcessor,支持请求和响应的转换,代码如下:
@Override
	public boolean supportsParameter(MethodParameter parameter) {
		return HttpEntity.class.equals(parameter.getParameterType());
	}

	@Override
	public boolean supportsReturnType(MethodParameter returnType) {
		return HttpEntity.class.isAssignableFrom(returnType.getParameterType());
	}
 AbstractMessageConverterMethodProcessor的子类RequestResponseBodyMethodProcessor:支持@RequestBody和@ResponseBody,代码如下:
@Override
	public boolean supportsParameter(MethodParameter parameter) {
               //查找参数中是否含有@RequestBody注解
		return parameter.hasParameterAnnotation(RequestBody.class);
	}

	@Override
	public boolean supportsReturnType(MethodParameter returnType) {

//查找参数中是否含有@RequestBody注解或者controller类上是否含有@RequestBody
		return ((AnnotationUtils.findAnnotation(returnType.getContainingClass(), ResponseBody.class) != null) ||
				(returnType.getMethodAnnotation(ResponseBody.class) != null));
	}
 同理RequestResponseBodyMethodProcessor也会使用相应的HttpMessageConverter来进行转换。如public Map<String,Object> testrequestBody(@RequestBody Map<String,Object> map1)则会选择MappingJackson2HttpMessageConverter或者MappingJacksonHttpMessageConverter来完成转换。 RequestParamMethodArgumentResolver支持的类型有,一种是含@RequestParam注解的参数,另一种就是简单类型,如Integer、String、Date、URI, URL,Locale等: 
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;
			}
		}
	}
 即当请求为 http://localhost:8080/test?name=abc时,处理函数若为test(String name),则对name的解析就是采用RequestParamMethodArgumentResolver来解析的。 
@Override
	public boolean supportsParameter(MethodParameter parameter) {
		return parameter.hasParameterAnnotation(RequestHeader.class)
				&& !Map.class.isAssignableFrom(parameter.getParameterType());
	}


	@Override
	protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
		String[] headerValues = request.getHeaderValues(name);
		if (headerValues != null) {
			return (headerValues.length == 1 ? headerValues[0] : headerValues);
		}
		else {
			return null;
		}
	} 
若想获取所有的header信息:则使用另一个RequestHeaderMapMethodArgumentResolver,它则用来获取所有的header信息:
public class RequestHeaderMapMethodArgumentResolver implements HandlerMethodArgumentResolver {

//这里已经写明白了,要求参数必须含有@RequestHeader注解,并且是Map类型
	@Override
	public boolean supportsParameter(MethodParameter parameter) {
		return parameter.hasParameterAnnotation(RequestHeader.class)
				&& Map.class.isAssignableFrom(parameter.getParameterType());
	}

	@Override
	public Object resolveArgument(
			MethodParameter parameter, ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
			throws Exception {

		Class<?> paramType = parameter.getParameterType();

		if (MultiValueMap.class.isAssignableFrom(paramType)) {
			MultiValueMap<String, String> result;
			if (HttpHeaders.class.isAssignableFrom(paramType)) {
				result = new HttpHeaders();
			}
			else {
				result = new LinkedMultiValueMap<String, String>();
			}
			for (Iterator<String> iterator = webRequest.getHeaderNames(); iterator.hasNext();) {
				String headerName = iterator.next();
				for (String headerValue : webRequest.getHeaderValues(headerName)) {
					result.add(headerName, headerValue);
				}
			}
			return result;
		}
		else {
			Map<String, String> result = new LinkedHashMap<String, String>();
			for (Iterator<String> iterator = webRequest.getHeaderNames(); iterator.hasNext();) {
				String headerName = iterator.next();
				String headerValue = webRequest.getHeader(headerName);
				result.put(headerName, headerValue);
			}
			return result;
		}
	}
}
  从上面的解析过程可以看出,参数类型可以是普通的Map类型,也可以是MultiValueMap或者进一步的HttpHeaders,他们与普通Map类型的区别是他们对value值后者们是以List形式存放,前者是以String形式存放。 PathVariableMethodArgumentResolver:主要针对含有@PathVariable的参数,代码如下:  
@Override
	public boolean supportsParameter(MethodParameter parameter) {
		if (!parameter.hasParameterAnnotation(PathVariable.class)) {
			return false;
		}
		if (Map.class.isAssignableFrom(parameter.getParameterType())) {
			String paramName = parameter.getParameterAnnotation(PathVariable.class).value();
			return StringUtils.hasText(paramName);
		}
		return true;
	}



@Override
	@SuppressWarnings("unchecked")
	protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
		Map<String, String> uriTemplateVars =
			(Map<String, String>) request.getAttribute(
					HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);
		return (uriTemplateVars != null) ? uriTemplateVars.get(name) : null;
	}
  对于支持的类型也说明的很详细。首先必须含有@PathVariable注解,其次如果是Map类型,必须要指定@PathVariable的值,即这个    

自从spring3.1 开始就有了这个接口,可以为@RequestMapping标注的方法扩展传入的参数。 
以shiro为例,扩展一个标注,@CurrentUser,只要有这个标注,就可以在shiro的安全上下文中取出适当的对象直接从参数传入,request响应函数。 

Java代码   收藏代码
  1. import java.lang.annotation.Documented;  
  2. import java.lang.annotation.ElementType;  
  3. import java.lang.annotation.Retention;  
  4. import java.lang.annotation.RetentionPolicy;  
  5. import java.lang.annotation.Target;  
  6.   
  7. @Documented  
  8. @Target({ElementType.PARAMETER})  
  9. @Retention(RetentionPolicy.RUNTIME)  
  10. public @interface CurrentUser {  
  11. }  
Java代码   收藏代码
  1. @RequestMapping(value = "/test1")  
  2. public @ResponseBody String test1(@CurrentUser Long userId) {  
  3.     return userId.toString();  
  4. }  
  5.   
  6. @RequestMapping(value = "/test2")  
  7. public @ResponseBody String test2(@CurrentUser UserDetails userDetails) {  
  8.     return userDetails.toString();  
  9. }  
Java代码   收藏代码
  1. import java.lang.annotation.Annotation;  
  2.   
  3. import org.springframework.core.MethodParameter;  
  4. import org.springframework.web.bind.support.WebDataBinderFactory;  
  5. import org.springframework.web.context.request.NativeWebRequest;  
  6. import org.springframework.web.method.support.HandlerMethodArgumentResolver;  
  7. import org.springframework.web.method.support.ModelAndViewContainer;  
  8.   
  9. import com.github.yingzhuo.mycar2.annotation.CurrentUser;  
  10. import com.github.yingzhuo.mycar2.security.SecurityUtils;  
  11. import com.github.yingzhuo.mycar2.security.UserDetails;  
  12.   
  13. public class CurrentUserHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {  
  14.   
  15.     @Override  
  16.     public boolean supportsParameter(MethodParameter parameter) {  
  17.         Class<?> klass = parameter.getParameterType();  
  18.         if (klass.isAssignableFrom(UserDetails.class) || klass.isAssignableFrom(Long.class)) {  
  19.             Annotation[] as = parameter.getParameterAnnotations();  
  20.             for (Annotation a : as) {  
  21.                 if (a.annotationType() == CurrentUser.class) {  
  22.                     return true;  
  23.                 }  
  24.             }  
  25.         }  
  26.         return false;  
  27.     }  
  28.   
  29.     @Override  
  30.     public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest,  
  31.             WebDataBinderFactory binderFactory) throws Exception {  
  32.           
  33.         if ((SecurityUtils.isAuthenticated() || SecurityUtils.isRemembered()) == false) {  
  34.             return null;  
  35.         }  
  36.           
  37.         Class<?> klass = parameter.getParameterType();  
  38.           
  39.         UserDetails userDetails = SecurityUtils.getUserDetails();  
  40.           
  41.         if (klass.isAssignableFrom(UserDetails.class)) {  
  42.             return SecurityUtils.getUserDetails();  
  43.         }  
  44.           
  45.         if (klass.isAssignableFrom(Long.class)) {  
  46.             return userDetails != null ? userDetails.getId() : null;  
  47.         }  
  48.           
  49.         return null;  
  50.     }  
  51. }  


最后,需要配置一下 

Xml代码   收藏代码
  1. <mvc:annotation-driven>  
  2.     <mvc:argument-resolvers>  
  3.         <bean class="xxx.yyy.CurrentUserHandlerMethodArgumentResolver" />  
  4.     </mvc:argument-resolvers>  
  5. </mvc:annotation-driven>  

猜你喜欢

转载自patrick002.iteye.com/blog/2204487