SpringMVC-解析@PathVariable
DispatcherServlet.doService去处理请求时,调用getHandler去获取匹配请求的handle。会调用RequestMappingInfoHandlerMapping.handleMatch,这个方法会调用extractMatchDetails解析uri模板变量,MATRIX变量,并将解析后的值设置到request的属性中。
RequestMappingInfoHandlerMapping.extractMatchDetails(
PatternsRequestCondition condition, String lookupPath, HttpServletRequest request)
private void extractMatchDetails(
PatternsRequestCondition condition, String lookupPath, HttpServletRequest request) {
String bestPattern;
Map<String, String> uriVariables;
if (condition.isEmptyPathMapping()) {
bestPattern = lookupPath;
uriVariables = Collections.emptyMap();
}
else {
bestPattern = condition.getPatterns().iterator().next();
uriVariables = getPathMatcher().extractUriTemplateVariables(bestPattern, lookupPath);
if (!getUrlPathHelper().shouldRemoveSemicolonContent()) {
request.setAttribute(MATRIX_VARIABLES_ATTRIBUTE, extractMatrixVariables(request, uriVariables));
}
uriVariables = getUrlPathHelper().decodePathVariables(request, uriVariables);
}
request.setAttribute(BEST_MATCHING_PATTERN_ATTRIBUTE, bestPattern);
request.setAttribute(URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriVariables);
}
extractUriTemplateVariables将匹配到的handle的处理请求路径和传过来的请求路径对比,将路径中的{}里面的参数和客户的请求路径对比后放到Map中返回。例如匹配路径是/testPath/{value},请求路径是/testPath/123,则Map中的值是value->123.decodePathVariables对uri模板变量值进行解码。调用request.setAttribute(URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriVariables);将uri模板变量值设置到request的属性中。
DispatcherServlet的doService方法调用handle处理request。会调用InvocableHandlerMethod.invokeForRequest处理request。
InvocableHandlerMethod.invokeForRequest
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
return doInvoke(args);
}
1、getMethodArgumentValues解析参数。
2、doInvoke执行处理方法。
InvocableHandlerMethod.getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,Object... providedArgs) 的执行流程和@@RequestParam的解析一致。
AbstractNamedValueMethodArgumentResolver.getNamedValueInfo(MethodParameter parameter)
private NamedValueInfo getNamedValueInfo(MethodParameter parameter) {
NamedValueInfo namedValueInfo = this.namedValueInfoCache.get(parameter);
if (namedValueInfo == null) {
namedValueInfo = createNamedValueInfo(parameter);
namedValueInfo = updateNamedValueInfo(parameter, namedValueInfo);
this.namedValueInfoCache.put(parameter, namedValueInfo);
}
return namedValueInfo;
}
1、createNamedValueInfo解析参数注解的name属性
2、updateNamedValueInfo判断解析后的name是否存在,不存在则获取参数名作为name,并将name,required,defaultValue封装成NamedValueInfo。
PathVariableMethodArgumentResolver.createNamedValueInfo(MethodParameter parameter)
protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
PathVariable ann = parameter.getParameterAnnotation(PathVariable.class);
Assert.state(ann != null, "No PathVariable annotation");
return new PathVariableNamedValueInfo(ann);
}
PathVariableNamedValueInfo(PathVariable annotation)
public PathVariableNamedValueInfo(PathVariable annotation) {
super(annotation.name(), annotation.required(), ValueConstants.DEFAULT_NONE);
}
createNamedValueInfo解析@PathVariable的name,required属性。并设置默认值为DEFAULT_NONE。并封装成NamedValueInfo。
PathVariableMethodArgumentResolver.resolveName重写了父类AbstractNamedValueMethodArgumentResolver.resolveName方法。
PathVariableMethodArgumentResolver.resolveName(String name, MethodParameter parameter, NativeWebRequest request)
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);
}
从request中获取uri模板变量属性,并从属性中获取值。