概述 HandlerMethodArgumentResolver ,HandlerMethod 的参数解析器接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 public interface HandlerMethodArgumentResolver { /** * 是否支持解析该参数 * * Whether the given {@linkplain MethodParameter method parameter} is * supported by this resolver. * @param parameter the method parameter to check * @return {@code true} if this resolver supports the supplied parameter; * {@code false} otherwise */ boolean supportsParameter(MethodParameter parameter); /** * 解析该参数 * * Resolves a method parameter into an argument value from a given request. * A {@link ModelAndViewContainer} provides access to the model for the * request. A {@link WebDataBinderFactory} provides a way to create * a {@link WebDataBinder} instance when needed for data binding and * type conversion purposes. * @param parameter the method parameter to resolve. This parameter must * have previously been passed to {@link #supportsParameter} which must * have returned {@code true}. * @param mavContainer the ModelAndViewContainer for the current request * @param webRequest the current request * @param binderFactory a factory for creating {@link WebDataBinder} instances * @return the resolved argument value, or {@code null} if not resolvable * @throws Exception in case of errors with the preparation of argument values */ @Nullable Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception; }
两个方法,分别是是否支持解析该参数、以及解析该参数。
类图
HandlerMethodArgumentResolverComposite 复合的 HandlerMethodArgumentResolver 实现类
构造方法 1 2 3 4 5 6 7 8 9 10 /** * HandlerMethodArgumentResolver 数组 */ private final List<HandlerMethodArgumentResolver> argumentResolvers = new LinkedList<>(); /** * MethodParameter 与 HandlerMethodArgumentResolver 的映射,作为缓存。 */ private final Map<MethodParameter, HandlerMethodArgumentResolver> argumentResolverCache = new ConcurrentHashMap<>(256);
argumentResolvers 属性,HandlerMethodArgumentResolver 数组。这就是 Composite 复合
argumentResolverCache 属性,MethodParameter 与HandlerMethodArgumentResolver 的映射,作为缓存
因为,MethodParameter 是需要从 argumentResolvers 遍历到适合其的解析器,通过缓存后,无需再次重复遍历
getArgumentResolver 获得方法参数对应的 HandlerMethodArgumentResolver 对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Nullable private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) { // 优先从 argumentResolverCache 缓存中,获得 parameter 对应的 HandlerMethodArgumentResolver 对象 HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter); if (result == null) { // 获得不到,则遍历 argumentResolvers 数组,逐个判断是否支持。 for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) { // 如果支持,则添加到 argumentResolverCache 缓存中,并返回 if (methodArgumentResolver.supportsParameter(parameter)) { result = methodArgumentResolver; this.argumentResolverCache.put(parameter, result); break; } } } return result; }
supportsParameter 实现 #supportsParameter(MethodParameter parameter) 方法,如果能获得到对应的 HandlerMethodArgumentResolver 处理器,则说明支持
1 2 3 4 @Override public boolean supportsParameter(MethodParameter parameter) { return (getArgumentResolver(parameter) != null); }
resolveArgument 解析指定参数的值
1 2 3 4 5 6 7 8 9 10 11 12 13 @Override @Nullable public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { // 获得 HandlerMethodArgumentResolver 对象 HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter); // 如果获得不到,抛出 IllegalArgumentException 异常 if (resolver == null) { throw new IllegalArgumentException("Unknown parameter type [" + parameter.getParameterType().getName() + "]"); } // 执行解析 return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory); }
AbstractNamedValueMethodArgumentResolver 实现 ValueMethodArgumentResolver 接口,基于名字获取值的HandlerMethodArgumentResolver 抽象基类。
例如说,@RequestParam(value = “username”) 注解的参数,就是从请求中获得 username 对应的参数值
构造方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @Nullable private final ConfigurableBeanFactory configurableBeanFactory; @Nullable private final BeanExpressionContext expressionContext; /** * MethodParameter 和 NamedValueInfo 的映射,作为缓存。 */ private final Map<MethodParameter, NamedValueInfo> namedValueInfoCache = new ConcurrentHashMap<>(256); public AbstractNamedValueMethodArgumentResolver() { this.configurableBeanFactory = null; this.expressionContext = null; } public AbstractNamedValueMethodArgumentResolver(@Nullable ConfigurableBeanFactory beanFactory) { this.configurableBeanFactory = beanFactory; this.expressionContext = (beanFactory != null ? new BeanExpressionContext(beanFactory, new RequestScope()) : null); }
namedValueInfoCache 属性,MethodParameter 和 NamedValueInfo 的映射,作为缓存
NamedValueInfo AbstractNamedValueMethodArgumentResolver 的静态类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 protected static class NamedValueInfo { /** * 名字 */ private final String name; /** * 是否必填 */ private final boolean required; /** * 默认值 */ @Nullable private final String defaultValue; public NamedValueInfo(String name, boolean required, @Nullable String defaultValue) { this.name = name; this.required = required; this.defaultValue = defaultValue; } }
getNamedValueInfo 获得方法参数对应的 NamedValueInfo 对象
1 2 3 4 5 6 7 8 9 10 11 12 13 private NamedValueInfo getNamedValueInfo(MethodParameter parameter) { // <1> 从 namedValueInfoCache 缓存中,获得 NamedValueInfo 对象 NamedValueInfo namedValueInfo = this.namedValueInfoCache.get(parameter); if (namedValueInfo == null) { // <2> 获得不到,则创建 namedValueInfo 对象。这是一个抽象方法,子类来实现 namedValueInfo = createNamedValueInfo(parameter); // <3> 更新 namedValueInfo 对象 namedValueInfo = updateNamedValueInfo(parameter, namedValueInfo); // <4> 添加到 namedValueInfoCache 缓存中 this.namedValueInfoCache.put(parameter, namedValueInfo); } return namedValueInfo; }
从 namedValueInfoCache 缓存中,获得 NamedValueInfo 对象
获得不到,则调用 #createNamedValueInfo(MethodParameter parameter) 方法,创建 namedValueInfo 对象。这是一个抽象方法,子类来实现。
1 protected abstract NamedValueInfo createNamedValueInfo(MethodParameter parameter);
调用 #updateNamedValueInfo(MethodParameter parameter, NamedValueInfo info) 方法,更新 namedValueInfo 对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 private NamedValueInfo updateNamedValueInfo(MethodParameter parameter, NamedValueInfo info) { String name = info.name; // 如果名字为空,则抛出 IllegalArgumentException 异常 if (info.name.isEmpty()) { name = parameter.getParameterName(); // 【注意!!!】如果 name 为空,则使用参数名 if (name == null) { throw new IllegalArgumentException( "Name for argument type [" + parameter.getNestedParameterType().getName() + "] not available, and parameter name information not found in class file either."); } } // 获得默认值 String defaultValue = (ValueConstants.DEFAULT_NONE.equals(info.defaultValue) ? null : info.defaultValue); // 创建 NamedValueInfo 对象 return new NamedValueInfo(name, info.required, defaultValue); }
最终,会创建一个新的 NamedValueInfo 对象
resolveArgument 解析指定参数的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 @Override @Nullable public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { // <1> 获得方法参数对应的 NamedValueInfo 对象。 NamedValueInfo namedValueInfo = getNamedValueInfo(parameter); // <2> 如果 parameter 是内嵌类型的,则获取内嵌的参数。否则,还是使用 parameter 自身 MethodParameter nestedParameter = parameter.nestedIfOptional(); // <3> 如果 name 是占位符,则进行解析成对应的值 Object resolvedName = resolveStringValue(namedValueInfo.name); if (resolvedName == null) { // 如果解析不到,则抛出 IllegalArgumentException 异常 throw new IllegalArgumentException( "Specified name must not resolve to null: [" + namedValueInfo.name + "]"); } // <4> 解析 name 对应的值 Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest); // <5> 如果 arg 不存在,则使用默认值 if (arg == null) { if (namedValueInfo.defaultValue != null) { // <5.1> 使用默认值 arg = resolveStringValue(namedValueInfo.defaultValue); } else if (namedValueInfo.required && !nestedParameter.isOptional()) { // <5.2> 如果是必填,则处理参数缺失的情况 handleMissingValue(namedValueInfo.name, nestedParameter, webRequest); } // <5.3> 处理空值的情况 arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType()); // <6> 如果 arg 为空串,则使用默认值 } else if ("".equals(arg) && namedValueInfo.defaultValue != null) { arg = resolveStringValue(namedValueInfo.defaultValue); } // <7> 执行值的类型转换 if (binderFactory != null) { WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name); try { arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter); } catch (ConversionNotSupportedException ex) { throw new MethodArgumentConversionNotSupportedException(arg, ex.getRequiredType(), namedValueInfo.name, parameter, ex.getCause()); } catch (TypeMismatchException ex) { throw new MethodArgumentTypeMismatchException(arg, ex.getRequiredType(), namedValueInfo.name, parameter, ex.getCause()); } } // 处理解析的值 handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest); return arg; }
调用 #getNamedValueInfo(MethodParameter parameter) 方法,获得方法参数对应的 NamedValueInfo 对象
如果 parameter 是内嵌类型的,则获取内嵌的参数。否则,还是使用 parameter 自身。一般情况下,parameter 参数,我们不太会使用 Optional 类型。
调用 #resolveStringValue(String value) 方法,如果 name 是占位符,则进行解析成对应的值。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Nullable private Object resolveStringValue(String value) { // 如果 configurableBeanFactory 为空,则不进行解析 if (this.configurableBeanFactory == null) { return value; } // 如果 exprResolver 或 expressionContext 为空,则不进行解析 BeanExpressionResolver exprResolver = this.configurableBeanFactory.getBeanExpressionResolver(); if (exprResolver == null || this.expressionContext == null) { return value; } // 获得占位符对应的值 String placeholdersResolved = this.configurableBeanFactory.resolveEmbeddedValue(value); // 计算表达式 return exprResolver.evaluate(placeholdersResolved, this.expressionContext); }
DEMO 未使用过
1 2 3 4 5 6 7 8 9 // Controller.java @RequestMapping("/hello3") public String hello3(@RequestParam(value = "${server.port}") String name) { return "666"; } // application.properties server.port=8012
调用 #resolveName(String name, MethodParameter parameter, NativeWebRequest request) 抽象方法,解析 name 对应的值。
1 2 3 @Nullable protected abstract Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception;
如果 arg 为 null ,则使用默认值。
如果默认值非空,则调用 #resolveStringValue(defaultValue) 方法,解析默认值。
如果是必填,则调用 #handleMissingValue(handleMissingValue) 方法,处理参数缺失的情况调用
1 2 3 4 5 6 7 8 9 10 11 // AbstractNamedValueMethodArgumentResolver.java protected void handleMissingValue(String name, MethodParameter parameter, NativeWebRequest request) throws Exception { handleMissingValue(name, parameter); } protected void handleMissingValue(String name, MethodParameter parameter) throws ServletException { throw new ServletRequestBindingException("Missing argument '" + name + "' for method parameter of type " + parameter.getNestedParameterType().getSimpleName()); }
抛出 ServletRequestBindingException 异常。
子类 RequestParamMethodArgumentResolver 会重写该方法
调用 #handleNullValue(String name, Object value, Class<?> paramType) 方法,处理 null 值的情况。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Nullable private Object handleNullValue(String name, @Nullable Object value, Class<?> paramType) { if (value == null) { // 如果是 Boolean 类型,则返回 FALSE if (Boolean.TYPE.equals(paramType)) { return Boolean.FALSE; // 如果基本类型,因为 null 无法转化,则抛出 IllegalStateException 异常 } else if (paramType.isPrimitive()) { throw new IllegalStateException("Optional " + paramType.getSimpleName() + " parameter '" + name + "' is present but cannot be translated into a null value due to being declared as a " + "primitive type. Consider declaring it as object wrapper for the corresponding primitive type."); } } // 返回默认值 return value; }
handleResolvedValue 解析值后的后置处理
1 2 3 protected void handleResolvedValue(@Nullable Object arg, String name, MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest) { }
子类 PathVariableMethodArgumentResolver 会重写该方法
RequestParamMethodArgumentResolver 处理普通的请求参数
构造方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 // RequestParamMethodArgumentResolver.java private static final TypeDescriptor STRING_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(String.class); /** * 是否使用默认解决。 * * 这个变量有点绕,见 {@link #supportsParameter(MethodParameter)} 方法 */ private final boolean useDefaultResolution; public RequestParamMethodArgumentResolver(boolean useDefaultResolution) { this.useDefaultResolution = useDefaultResolution; } public RequestParamMethodArgumentResolver(@Nullable ConfigurableBeanFactory beanFactory, boolean useDefaultResolution) { super(beanFactory); this.useDefaultResolution = useDefaultResolution; }
supportsParameter 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 @Override public boolean supportsParameter(MethodParameter parameter) { // 有 @RequestParam 注解的情况 if (parameter.hasParameterAnnotation(RequestParam.class)) { // <3> 如果是 Map 类型,则 @RequestParam 注解必须要有 name 属性 if (Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) { RequestParam requestParam = parameter.getParameterAnnotation(RequestParam.class); return (requestParam != null && StringUtils.hasText(requestParam.name())); // 其它,默认支持 } else { return true; } } else { // 如果有 @RequestPart 注解,返回 false 。即 @RequestPart 的优先级 > @RequestParam if (parameter.hasParameterAnnotation(RequestPart.class)) { return false; } // 获得参数,如果存在内嵌的情况 parameter = parameter.nestedIfOptional(); // <1> 如果 Multipart 参数。则返回 true ,表示支持 if (MultipartResolutionDelegate.isMultipartArgument(parameter)) { return true; // <2> 如果开启 useDefaultResolution 功能,则判断是否为普通类型 } else if (this.useDefaultResolution) { return BeanUtils.isSimpleProperty(parameter.getNestedParameterType()); // 其它,不支持 } else { return false; } } }
调用 MultipartResolutionDelegate#isMultipartArgument(parameter) 方法,如果 Multipart 参数。则返回 true ,表示支持。
1 2 3 4 5 6 7 public static boolean isMultipartArgument(MethodParameter parameter) { Class<?> paramType = parameter.getNestedParameterType(); // MultipartFile 的多种情况 return (MultipartFile.class == paramType || isMultipartFileCollection(parameter) || isMultipartFileArray(parameter) || // Part 的多种情况 (Part.class == paramType || isPartCollection(parameter) || isPartArray(parameter))); }
如果开启 useDefaultResolution 功能,则调用 BeanUtils#isSimpleProperty(Class<?> clazz) 方法,判断是否为普通类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // BeanUtils.java public static boolean isSimpleProperty(Class<?> clazz) { Assert.notNull(clazz, "Class must not be null"); return isSimpleValueType(clazz) || (clazz.isArray() && isSimpleValueType(clazz.getComponentType())); } // 实际上就是判断,该class是否可以转换为某些类 public static boolean isSimpleValueType(Class<?> clazz) { return (ClassUtils.isPrimitiveOrWrapper(clazz) || Enum.class.isAssignableFrom(clazz) || CharSequence.class.isAssignableFrom(clazz) || Number.class.isAssignableFrom(clazz) || Date.class.isAssignableFrom(clazz) || URI.class == clazz || URL.class == clazz || Locale.class == clazz || Class.class == clazz); }
那么 useDefaultResolution 到底是怎么样的赋值呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // RequestMappingHandlerAdapter.java private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() { List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(); // Annotation-based argument resolution resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false)); // .. 省略一大片 // Catch-all resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true)); // .. 省略几个 return resolvers; }
有两个 RequestParamMethodArgumentResolver 对象,前者 useDefaultResolution 为 false ,后者为 useDefaultResolution 为 true 。什么意思呢?
优先将待有 @RequestParam 注解的请求参数给第一个 RequestParamMethodArgumentResolver 对象;
其次,给中间省��的一大片参数解析器试试能不能解析;
最后,使用第二个 RequestParamMethodArgumentResolver 兜底,处理剩余的情况。
createNamedValueInfo 创建 NamedValueInfo 对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Override protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) { RequestParam ann = parameter.getParameterAnnotation(RequestParam.class); return (ann != null ? new RequestParamNamedValueInfo(ann) : new RequestParamNamedValueInfo()); } private static class RequestParamNamedValueInfo extends NamedValueInfo { public RequestParamNamedValueInfo() { super("", false, ValueConstants.DEFAULT_NONE); } public RequestParamNamedValueInfo(RequestParam annotation) { super(annotation.name(), annotation.required(), annotation.defaultValue()); } }
resolveName 获得参数的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 @Override @Nullable protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception { // 情况一,HttpServletRequest 情况下的 MultipartFile 和 Part 的情况 HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class); if (servletRequest != null) { Object mpArg = MultipartResolutionDelegate.resolveMultipartArgument(name, parameter, servletRequest); if (mpArg != MultipartResolutionDelegate.UNRESOLVABLE) { return mpArg; } } // 情况二,MultipartHttpServletRequest 情况下的 MultipartFile 的情况 Object arg = null; MultipartHttpServletRequest multipartRequest = request.getNativeRequest(MultipartHttpServletRequest.class); if (multipartRequest != null) { List<MultipartFile> files = multipartRequest.getFiles(name); if (!files.isEmpty()) { arg = (files.size() == 1 ? files.get(0) : files); } } // 情况三,普通参数的获取 if (arg == null) { String[] paramValues = request.getParameterValues(name); if (paramValues != null) { arg = (paramValues.length == 1 ? paramValues[0] : paramValues); } } return arg; }
情况一、二,是处理参数类型为文件 org.springframework.web.multipart.MultipartFile 和 javax.servlet.http.Part 的参数的获取
情况三,是处理普通参数的获取。就是我们常见的 String、Integer 之类的请求参数。
handleMissingValue 重写 handleMissingValue方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Override protected void handleMissingValue(String name, MethodParameter parameter, NativeWebRequest request) throws Exception { HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class); if (MultipartResolutionDelegate.isMultipartArgument(parameter)) { if (servletRequest == null || !MultipartResolutionDelegate.isMultipartRequest(servletRequest)) { throw new MultipartException("Current request is not a multipart request"); } else { throw new MissingServletRequestPartException(name); } } else { throw new MissingServletRequestParameterException(name, parameter.getNestedParameterType().getSimpleName()); } }
根据参数的类型,做更详细的异常抛出
RequestParamMapMethodArgumentResolver 实现 HandlerMethodArgumentResolver 接口,处理带有 @RequestParam 注解,但是注解上无 name 属性的 Map 类型的参数的 RequestParamMethodArgumentResolver 实现类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 public class RequestParamMapMethodArgumentResolver implements HandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter parameter) { RequestParam requestParam = parameter.getParameterAnnotation(RequestParam.class); return (requestParam != null && Map.class.isAssignableFrom(parameter.getParameterType()) && !StringUtils.hasText(requestParam.name())); } @Override public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { Class<?> paramType = parameter.getParameterType(); // 获得请求的参数集合 Map<String, String[]> parameterMap = webRequest.getParameterMap(); // MultiValueMap 类型的处理 if (MultiValueMap.class.isAssignableFrom(paramType)) { MultiValueMap<String, String> result = new LinkedMultiValueMap<>(parameterMap.size()); parameterMap.forEach((key, values) -> { for (String value : values) { result.add(key, value); } }); return result; // 普通 Map 类型的处理 } else { Map<String, String> result = new LinkedHashMap<>(parameterMap.size()); parameterMap.forEach((key, values) -> { if (values.length > 0) { result.put(key, values[0]); } }); return result; } } }
对于 RequestParamMapMethodArgumentResolver 类,它的效果是,将所有参数添加到 Map 集合中
1 2 3 4 @RequestMapping("/hello4") public String hello4(@RequestParam Map<String, Object> map) { return "666"; }
对于 RequestParamMethodArgumentResolver 类,它的效果是,将指定名字的参数添加到 Map 集合中
1 2 3 4 @RequestMapping("/hello5") public String hello5(@RequestParam(name = "map") Map<String, Object> map) { return "666"; }
PathVariableMethodArgumentResolver 实现 UriComponentsContributor 接口,继承 AbstractNamedValueMethodArgumentResolver 抽象类,处理路径参数
supportsParameter 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Override public boolean supportsParameter(MethodParameter parameter) { // 如果无 @PathVariable 注解 if (!parameter.hasParameterAnnotation(PathVariable.class)) { return false; } // <x> Map 类型,有 @PathVariable 注解,但是有 name 属性 if (Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) { PathVariable pathVariable = parameter.getParameterAnnotation(PathVariable.class); return (pathVariable != null && StringUtils.hasText(pathVariable.value())); } // 有 @PathVariable 注解 return true; }
createNamedValueInfo 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 // PathVariableMethodArgumentResolver.java @Override protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) { // 获得 @PathVariable 注解 PathVariable ann = parameter.getParameterAnnotation(PathVariable.class); Assert.state(ann != null, "No PathVariable annotation"); // 创建 PathVariableNamedValueInfo 对象 return new PathVariableNamedValueInfo(ann); } private static class PathVariableNamedValueInfo extends NamedValueInfo { public PathVariableNamedValueInfo(PathVariable annotation) { super(annotation.name(), annotation.required(), ValueConstants.DEFAULT_NONE); } }
resolveName 1 2 3 4 5 6 7 8 9 @Override @Nullable 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); }
handleMissingValue 1 2 3 4 5 @Override protected void handleMissingValue(String name, MethodParameter parameter) throws ServletRequestBindingException { // 抛出 MissingPathVariableException 异常 throw new MissingPathVariableException(name, parameter); }
handleResolvedValue 重写 #handleResolvedValue(Object arg, String name, MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest request) 方法,添加获得的属性值到请求的 View.PATH_VARIABLES 属性中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Override protected void handleResolvedValue(@Nullable Object arg, String name, MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest request) { // 获得 pathVars String key = View.PATH_VARIABLES; int scope = RequestAttributes.SCOPE_REQUEST; Map<String, Object> pathVars = (Map<String, Object>) request.getAttribute(key, scope); // 如果不存在 pathVars ,则进行创建 if (pathVars == null) { pathVars = new HashMap<>(); request.setAttribute(key, pathVars, scope); } // 添加 name + arg 到 pathVars 中 pathVars.put(name, arg); }