Spring MVC : 框架缺省的控制器方法参数解析器

本文介绍SpringMVC中参数解析器HandlerMethodArgumentResolver的工作原理及其重要实现类。通过不同的解析器,SpringMVC能有效处理@RequestParam、@PathVariable等注解,并支持简单及复杂类型的参数解析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用Spring MVC进行Web应用开发时,请求参数接收是很重要的一个方面。一般情况下,我们可以通过request.getParameter(name)这种方式来获取指定名称参数的值,这种方式是由Servlet容器自身提供的。但使用这种方式会导致开发人员必须在控制器方法中书写仅用于接收参数的逻辑,在参数量多的情况下,这部分代码甚至占据了方法体的大部分,而核心业务逻辑反而淹没其中。为了使开发人员从这种窘境中解脱出来提高生产效率,关注核心业务,Spring MVC提供了各种便利工具来接收参数,同时也将该关注点从主业务逻辑中分离出来。

Spring MVC所提供的这些工具,有@PathVariable,@RequestParam,@RequestBody,@RequestParam,@CookieValue等注解,也有对一些类直接支持逻辑。本文不讲这些注解或者被支持的类如何使用以及它们的目的,而是看看针对这些便利工具,Spring MVC在背后所提供的参数解析器:HandlerMethodArgumentResolver

下表是Spring Web MVC所提供的参数解析器实现类:

控制器方法参数解析器所能解析的参数的类型特征
RequestParamMethodArgumentResolver@RequestParam并且参数类型不是Map
RequestParamMapMethodArgumentResolver@RequestParam并且参数类型是Map
PathVariableMethodArgumentResolver@PathVariable并且参数类型不是Map
PathVariableMapMethodArgumentResolver@PathVariable并且参数类型是Map
MatrixVariableMethodArgumentResolver@MatrixVariable并且参数类型不是Map
MatrixVariableMapMethodArgumentResolver@MatrixVariable并且参数类型是Map
ServletModelAttributeMethodProcessor@ModelAttribute,Servlet相关
RequestResponseBodyMethodProcessor@RequestBody,@ResponseBody
RequestPartMethodArgumentResolver@RequestPart
RequestHeaderMethodArgumentResolver@RequestHeader并且参数类型不是Map
RequestHeaderMapMethodArgumentResolver@RequestHeader并且参数类型是Map
ServletCookieValueMethodArgumentResolver@CookieValue
ExpressionValueMethodArgumentResolver@Value
SessionAttributeMethodArgumentResolver@SessionAttribute
RequestAttributeMethodArgumentResolver@RequestAttribute
ServletRequestMethodArgumentResolverWebRequest,
ServletRequest,
MultipartRequest,
HttpSession,
PushBuilder,
Principal,
InputStream,
Reader,
HttpMethod,
Locale,
TimeZone,
java.time.ZoneId
ServletResponseMethodArgumentResolverServletResponse,OutputStream,Writer
HttpEntityMethodProcessorHttpEntity,RequestEntity,ResponseEntity
RedirectAttributesMethodArgumentResolverRedirectAttributes
ModelMethodProcessorModel类型的参数和返回值
MapMethodProcessorMap类型的参数和返回值
ErrorsMethodArgumentResolverErrors
SessionStatusMethodArgumentResolverSessionStatus
UriComponentsBuilderMethodArgumentResolverUriComponentsBuilder

Spring MVC应用缺省使用类型为RequestMappingHandlerAdapterbean组件requestMappingHandlerAdapter调用每个请求对应的控制器方法。在bean组件requestMappingHandlerAdapter初始化时,它会构建一个HandlerMethodArgumentResolverComposite对象,该对象是多个HandlerMethodArgumentResolver的一个集合:

    // RequestMappingHandlerAdapter 代码片段
    // RequestMappingHandlerAdapter 的初始化方法
	@Override
	public void afterPropertiesSet() {
		// Do this first, it may add ResponseBody advice beans
		initControllerAdviceCache();

		if (this.argumentResolvers == null) {
			// 获取缺省的 HandlerMethodArgumentResolver, 多个
			List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
			// 构造 HandlerMethodArgumentResolverComposite 对象,
			// 包装缺省的多个 HandlerMethodArgumentResolver
			this.argumentResolvers = 
				new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
		}
		if (this.initBinderArgumentResolvers == null) {
			List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
			this.initBinderArgumentResolvers = 
				new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
		}
		if (this.returnValueHandlers == null) {
			List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
			this.returnValueHandlers = 
				new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
		}
	}

从上面的代码可见,缺省使用的控制器方法参数解析器由getDefaultInitBinderArgumentResolvers()提供。该方法实现如下:

	// RequestMappingHandlerAdapter 代码片段
	private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
		List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();

		// Annotation-based argument resolution
		resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
		resolvers.add(new RequestParamMapMethodArgumentResolver());
		resolvers.add(new PathVariableMethodArgumentResolver());
		resolvers.add(new PathVariableMapMethodArgumentResolver());
		resolvers.add(new MatrixVariableMethodArgumentResolver());
		resolvers.add(new MatrixVariableMapMethodArgumentResolver());
		resolvers.add(new ServletModelAttributeMethodProcessor(false));
		resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), 
			this.requestResponseBodyAdvice));
		resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), 
			this.requestResponseBodyAdvice));
		resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
		resolvers.add(new RequestHeaderMapMethodArgumentResolver());
		resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
		resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
		resolvers.add(new SessionAttributeMethodArgumentResolver());
		resolvers.add(new RequestAttributeMethodArgumentResolver());

		// Type-based argument resolution
		resolvers.add(new ServletRequestMethodArgumentResolver());
		resolvers.add(new ServletResponseMethodArgumentResolver());
		resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), 
			this.requestResponseBodyAdvice));
		resolvers.add(new RedirectAttributesMethodArgumentResolver());
		resolvers.add(new ModelMethodProcessor());
		resolvers.add(new MapMethodProcessor());
		resolvers.add(new ErrorsMethodArgumentResolver());
		resolvers.add(new SessionStatusMethodArgumentResolver());
		resolvers.add(new UriComponentsBuilderMethodArgumentResolver());

		// Custom arguments , 添加定制的参数解析器
		if (getCustomArgumentResolvers() != null) {
			resolvers.addAll(getCustomArgumentResolvers());
		}

		// Catch-all , 如果上面的参数解析器都处理不了,尝试使用下面的解析器尝试兜底
		// true 表示 : 即使不使用注解 @RequestParam ,简单类型的方法参数也会被认为是请求参数被解析,
		// 此时请求参数名称会根据方法参数名称派生而来。
		resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
		// true 表示 : 即使不使用注解 @ModelAttribute,非简单类型的方法参数和返回值也会被认为
		// 是 model attribute 
		resolvers.add(new ServletModelAttributeMethodProcessor(true));

		return resolvers;
	}

上面方法中参数解析器添加的顺序很重要,因为为每个参数寻找参数解析器时,会按照以上添加顺序去寻找第一个能够解析该参数的参数解析器。

另外,以上这些的HandlerMethodArgumentResolver继承/实现关系如下所示 :

  • HandlerMethodArgumentResolver
    • AbstractNamedValueMethodArgumentResolver
      • AbstractCookieValueMethodArgumentResolver
        • ServletCookieValueMethodArgumentResolver
      • ExpressionValueMethodArgumentResolver
      • RequestHeaderMethodArgumentResolver
      • RequestParamMethodArgumentResolver
      • MatrixVariableMethodArgumentResolver
      • PathVariableMethodArgumentResolver
      • RequestAttributeMethodArgumentResolver
      • SessionAttributeMethodArgumentResolver
    • AbstractWebArgumentResolverAdapter
      • ServletWebArgumentResolverAdapter
    • ErrorsMethodArgumentResolver
    • MapMethodProcessor
    • ModelAttributeMethodProcessor
      • ServletModelAttributeMethodProcessor
    • ModelMethodProcessor
    • RequestHeaderMapMethodArgumentResolver
    • RequestParamMapMethodArgumentResolver
    • SessionStatusMethodArgumentResolver
    • AbstractMessageConverterMethodArgumentResolver
      • AbstractMessageConverterMethodProcessor
        • HttpEntityMethodProcessor
        • RequestResponseBodyMethodProcessor
      • RequestPartMethodArgumentResolver
    • MatrixVariableMapMethodArgumentResolver
    • PathVariableMapMethodArgumentResolver
    • RedirectAttributesMethodArgumentResolver
    • ServletRequestMethodArgumentResolver
    • ServletResponseMethodArgumentResolver
    • UriComponentsBuilderMethodArgumentResolver
    • HandlerMethodArgumentResolverComposite

参考文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值