SpringMVC请求参数解析
2021-04-29 18:19
197 查看
请求参数解析
客户端请求在handlerMapping中找到对应handler后,将会继续执行
DispatchServlet的
doPatch()方法。
首先是找到handler对应的适配器。
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
进入到
getHandlerAdapter(mappedHandler.getHandler())方法中
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { if (this.handlerAdapters != null) { for (HandlerAdapter adapter : this.handlerAdapters) { if (adapter.supports(handler)) { return adapter; } } } throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler"); }
这里存在多个适配器,如图:
其中使用
@RequestMaping注解修饰的控制器都将适配第一个适配器;而函数式方法将会使用第二个适配器。
跟踪请求,这里将会获得第一个适配器,判断也简单,如下:
public final boolean supports(Object handler) { return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler)); }
如果是
HandlerMethod类型的处理器就采用这个适配器,而客户端请求正好对应的是
HandlerMethod处理器。
找到适配器后,将会真正执行处理器逻辑。如下:
// Actually invoke the handler. mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
进入
RequestMappingHandlerAdapter,执行适配器核心方法:
@Override protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ModelAndView mav; checkRequest(request); // Execute invokeHandlerMethod in synchronized block if required. if (this.synchronizeOnSession) { HttpSession session = request.getSession(false); if (session != null) { Object mutex = WebUtils.getSessionMutex(session); synchronized (mutex) { mav = invokeHandlerMethod(request, response, handlerMethod);} } else { // No HttpSession available -> no mutex necessary mav = invokeHandlerMethod(request, response, handlerMethod);} } else { // No synchronization on session demanded at all... mav = invokeHandlerMethod(request, response, handlerMethod);} if (!response.containsHeader(HEADER_CACHE_CONTROL)) { if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) { applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers); } else { prepareResponse(response); } } return mav; }
其核心代码为实际执行处理器方法:
mav = invokeHandlerMethod(request, response, handlerMethod);
同样,我们打开
RequestMappingHandlerAdapter中的
invokeHandlerMethod方法:
@Nullable protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod 56c handlerMethod) throws Exception { ServletWebRequest webRequest = new ServletWebRequest(request, response); try { //通过处理器获得真正的执行方法及其参数列表 ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod); //给执行方法对象添加参数解析器 if (this.argumentResolvers != null) { invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); } //给执行方法对象添加返回值处理器 if (this.returnValueHandlers != null) { invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); } //处理器对象装配完成,执行控制器方法 invocableMethod.invokeAndHandle(webRequest, mavContainer); if (asyncManager.isConcurrentHandlingStarted()) { return null; } return getModelAndView(mavContainer, modelFactory, webRequest); } finally { webRequest.requestCompleted(); } }
在这个关键方法中,首先执行请求对应的控制器逻辑,之后进行系列处理,根据返回值处理器处理返回值。
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { //执行控制器方法 Object returnValue = inv 56c okeForRequest(webRequest, mavContainer, providedArgs); setResponseStatus(webRequest); if (returnValue == null) { if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) { disableContentCachingIfNecessary(webRequest); mavContainer.setRequestHandled(true); return; } } else if (StringUtils.hasText(getResponseStatusReason())) { mavContainer.setRequestHandled(true); return; } mavContainer.setRequestHandled(false); Assert.state(this.returnValueHandlers != null, "No return value handlers"); try { //处理返回值 this.returnValueHandlers.handleReturnValue( returnValue, getReturnValueType(returnValue), mavContainer, webRequest); } catch (Exception ex) { if (logger.isTraceEnabled()) { logger.trace(formatErrorForReturnValue(returnValue), ex); } throw ex; } }
以下给出部分参数解析器及返回值处理器截图:
参数解析器。对应每一个参数(路径变量、矩阵变量、获得请求头、请求域等)的获取方式
返回值处理器。ModelAndView、ResponseBody等。每个处理器处理不同类别的返回值类型。
接下来,真正进入到最终执行method方法
invocableMethod.invokeAndHandle(webRequest, mavContainer);,这里是真是执行控制器中映射的方法。
以下为获得参数列表对应值的逻辑,参数获取完成后将会执行真正的控制器逻辑。
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); }
进入解析逻辑,解析是对比每一个参数绑定的注解,如果注解一致将会使用对应的解析器将请求传递的参数值获取到。
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { //获得控制器参数列表,每一个参数包含其参数类型,参数次序、注解修饰(用于使用对应解析器) MethodParameter[] parameters = getMethodParameters(); if (ObjectUtils.isEmpty(parameters)) { return EMPTY_ARGS; } Object[] args = new Object[parameters.length]; for (int i = 0; i < parameters.length; i++) { //轮循获得参数 MethodParameter parameter = parameters[i]; parameter.initParameterNameDiscovery(this.parameterNameDiscoverer); args[i] = findProvidedArgument(parameter, providedArgs); if (args[i] != null) { continue; } //判断解析器是否支持当前参数的解析 if (!this.resolvers.supportsParameter(parameter)) { throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver")); } try { //获得参数值的核心方法 args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory); } catch (Exception ex) { // Leave stack trace for later, exception may actually be resolved and handled... if (logger.isDebugEnabled()) { String exMsg = ex.getMessage(); if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) { logger.debug(formatArgumentError(parameter, exMsg)); } } throw ex; } } return args; }
查看解析器是否指出当前参数部分代码,可以了解到SpringMVC的缓存策略。
private 15b0 HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) { //从缓存中获取当前参数的解析器 HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter); //缓存中不存在则将这个参数对应的解析器加到缓存中,提升后续相同请求响应速度。 if (result == null) { for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) { if (resolver.supportsParameter(parameter)) { result = resolver; this.argumentResolverCache.put(parameter, result); break; } } } return result; }
参数列表
以下为获得的参数列表第一个参数部分属性
其对应的是控制器中
id参数:
@GetMapping(value = "/student01/{id}/car/{name}") public Map<String, Object> testAnnotation(@PathVariable(name = "id") String id){ Map<String, Object> map = new HashMap<>(); map.put("id", id); return map; }
以上即为获得请求Handler对应的适配器,处理参数映射、执行控制器逻辑、返回值处理的核心源码处理。
相关文章推荐
- springmvc put请求无法解析请求体参数解决办法
- SpringMVC中HandlerMethod的请求参数解析过程
- 假装看源码之springmvc (一) 如何进行请求参数的解析
- SpringMVC之分析HandlerMethodArgumentResolver请求对应处理器方法参数的解析过程(一)
- SpringMVC中HandlerMethod的请求参数解析过程
- SpringMVC中Controller类的方法如何解析ajax请求发送的请求体中的多个参数
- springMVC get请求参数封装
- JAVA获取请求地址,将参数解析成MAP
- springmvc中的http请求参数与响应
- 随笔笔记三——关于SpringMVC接收请求参数和向页面传递参数
- 解析GB18030编码格式的POST请求参数
- SpringMVC中使用Ajax POST请求以json格式传递参数服务端通过request.getParameter("name")无法获取参数值问题分析
- 解决SpringMVC请求参数中文乱码问题
- Netty实现java多线程Post请求解析(Map参数类型)—SKY
- tomcat中解析url中的参数或者post中的请求内容
- 学习SpringMVC——如何获取请求参数
- springmvc 项目完整示例06 日志–log4j 参数详细解析 log4j如何配置
- springMVC笔记系列(三)——映射请求URL中的占位符到控制器方法参数
- SpringMVC接收数组请求参数小技巧
- 为什么springmvc请求参数中的点后面的参数没了