Spring 注解面面通 之 @RequestHeader参数绑定源码解析

本文深入探讨了SpringMVC中@RequestHeader注解的工作原理及其两种解析器:RequestHeaderMapMethodArgumentResolver和RequestHeaderMethodArgumentResolver的实现细节。

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

  Spring MVC中使用HandlerMethodArgumentResolver策略接口来定义处理器方法参数解析器,@RequestHeader使用的是RequestHeaderMapMethodArgumentResolverRequestHeaderMethodArgumentResolver,接下来一起来深入了解一下其源码实现。

  类结构

在这里插入图片描述

在这里插入图片描述

  类解析

  HandlerMethodArgumentResolverAbstractNamedValueMethodArgumentResolver是解析策略的上层定义和抽象,关于这两个类可以参照《Spring 注解面面通 之 @CookieValue参数绑定源码解析》中的解析。

  RequestHeaderMapMethodArgumentResolverRequestHeaderMethodArgumentResolver则是用来针对不用类型的方法参数的解析。

  1) RequestHeaderMapMethodArgumentResolver实现了HandlerMethodArgumentResolversupportsParameter(...)resolveArgument(...)方法。

  RequestHeaderMapMethodArgumentResolver相对比较简单,但在某些条件成立的情况下才会使用此类进行解析:

  ① 方法参数由@RequestHeader注解注释。

  ② 方法参数类型必须是Map类型。

package org.springframework.web.method.annotation;

import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;

import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.lang.Nullable;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

/**
 * 解析用@RequestHeader注释的Map类型方法参数.
 *
 * 创建的Map包含所有请求头名称/值对.
 * 方法参数类型可以是MultiValueMap,用于接收头的所有值,而不仅仅是第一个值.
 */
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, @Nullable ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
		// 获取方法参数类型.
		Class<?> paramType = parameter.getParameterType();
		// 方法参数是MultiValueMap类型.
		if (MultiValueMap.class.isAssignableFrom(paramType)) {
			MultiValueMap<String, String> result;
			// 方法参数是HttpHeaders类型.
			if (HttpHeaders.class.isAssignableFrom(paramType)) {
				result = new HttpHeaders();
			}
			else {
				result = new LinkedMultiValueMap<>();
			}
			// 处理NativeWebRequest的所有头.
			for (Iterator<String> iterator = webRequest.getHeaderNames(); iterator.hasNext();) {
				String headerName = iterator.next();
				String[] headerValues = webRequest.getHeaderValues(headerName);
				if (headerValues != null) {
					for (String headerValue : headerValues) {
						result.add(headerName, headerValue);
					}
				}
			}
			return result;
		}
		// 方法参数是其他Map类型
		else {
			Map<String, String> result = new LinkedHashMap<>();
			for (Iterator<String> iterator = webRequest.getHeaderNames(); iterator.hasNext();) {
				String headerName = iterator.next();
				String headerValue = webRequest.getHeader(headerName);
				if (headerValue != null) {
					result.put(headerName, headerValue);
				}
			}
			return result;
		}
	}

}

  2) RequestHeaderMethodArgumentResolver继承自抽象AbstractNamedValueMethodArgumentResolver(可以参照《Spring 注解面面通 之 @CookieValue参数绑定源码解析》)。

  RequestHeaderMethodArgumentResolver相对RequestHeaderMapMethodArgumentResolver来说,,其在某些条件成立的情况下才会使用此类进行解析:

  ① 方法参数由@RequestHeader注解注释。

  ② 方法参数类型不能为Map类型。

package org.springframework.web.method.annotation;

import java.util.Map;

import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.core.MethodParameter;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.context.request.NativeWebRequest;

/**
 * 解析用@RequestHeader注释的方法参数,Map参数除外. 
 *
 * @RequestHeader 用于从请求头解析的命名值.
 * 当请求头不存在时,它有一个必需的标志和一个默认值.
 *
 * 调用WebDataBinder将类型转换应用于尚未与方法参数类型匹配的已解析请求头值.
 */
public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {

	/**
	 * @param beanFactory 用于解析默认值中${…}占位符和#{…}SpEL表达式的Bean工厂,
	 * 						或如果默认值不应包含表达式,则返回null.
	 */
	public RequestHeaderMethodArgumentResolver(@Nullable ConfigurableBeanFactory beanFactory) {
		super(beanFactory);
	}

	/**
	 * 检查方法参数.
	 * 方法参数由@RequestHeader注释.
	 * 方法参数类型不为Map类型.
	 */
	@Override
	public boolean supportsParameter(MethodParameter parameter) {
		return (parameter.hasParameterAnnotation(RequestHeader.class) &&
				!Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType()));
	}

	/**
	 * 创建NamedValueInfo.
	 */
	@Override
	protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
		RequestHeader ann = parameter.getParameterAnnotation(RequestHeader.class);
		Assert.state(ann != null, "No RequestHeader annotation");
		return new RequestHeaderNamedValueInfo(ann);
	}

	/**
	 * 解析方法参数值.
	 */
	@Override
	@Nullable
	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;
		}
	}
	
	/**
	 * 处理参数缺失异常.
	 */
	@Override
	protected void handleMissingValue(String name, MethodParameter parameter) throws ServletRequestBindingException {
		throw new ServletRequestBindingException("Missing request header '" + name +
				"' for method parameter of type " + parameter.getNestedParameterType().getSimpleName());
	}

	/**
	 * RequestHeaderNamedValueInfo.
	 */
	private static class RequestHeaderNamedValueInfo extends NamedValueInfo {

		private RequestHeaderNamedValueInfo(RequestHeader annotation) {
			super(annotation.name(), annotation.required(), annotation.defaultValue());
		}
	}

}

  总结

  @RequestHeader是用来处理Web请求头中的信息,随着网站的多样和多元化,@RequestHeader使用频率会越来越广泛。

  若文中存在错误和不足,欢迎指正!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值