Controller handler方法支持返回类型
在学习Spring框架的同时,我在Spring in Action一书中注意到,作者没有在控制器中使用ModelandView
方法返回类型。 作者声明控制器方法是String
返回类型,方法中的return子句只返回一个字符串,如return "/views/theview";
有人可以详细说明其工作原理的内部差异吗?
这是一个深入的了解。
Spring提供了一个DispatcherServlet
类,通常可以处理所有请求。 它在其doDispatch(HttpServletRequest request, HttpServletResponse response)
方法中执行此操作
// Actually invoke the handler. mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
其中mv
是最终的ModelAndView
对象, ha
是使用@RequestMapping
注释的控制器方法的包装器。
这通常会经过一堆方法调用,最后是ServletInvocableHandlerMethod.invokeAndHandle
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle at org.springframework.web.servlet.DispatcherServlet.doDispatch
看着源头
public final void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); setResponseStatus(webRequest); if (returnValue == null) { if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) { mavContainer.setRequestHandled(true); return; } } else if (StringUtils.hasText(this.responseReason)) { mavContainer.setRequestHandled(true); return; } mavContainer.setRequestHandled(false); try { this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest); } catch (Exception ex) { if (logger.isTraceEnabled()) { logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex); } throw ex; } }
returnValue
是@RequestMapping
方法返回的对象。 它经历了
this.returnValueHandlers.handleReturnValue
其中Spring确定HandlerMethodReturnValueHandler
来处理该对象。
public void handleReturnValue( Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { HandlerMethodReturnValueHandler handler = getReturnValueHandler(returnType); // returns the appropriate handler Assert.notNull(handler, "Unknown return value type [" + returnType.getParameterType().getName() + "]"); handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest); }
getReturnValueHandler(returnType);
返回适当的处理程序。 HandlerMethodReturnValueHandler
是一个带有supportsReturnType
方法的接口,如果处理程序支持该类型( String
, View
, ResponseEntity
等(查找支持的返回类型) ),则返回true
。 因此,该方法返回它找到的第一个支持该类型并运行它的处理程序。
Spring在初始化时注册了HandlerMethodReturnValueHandler
大量实现。 基本上所有已知的实现类都在其javadoc中 。
例如,如果返回String,Spring将使用ViewNameMethodReturnValueHandler
来处理响应。
现在,使用哪种返回类型取决于您。 如果您想返回一个Model
以便在jsp视图中使用请求属性,您可以让Spring将Model
实例传递给您的方法,也可以自己创建Model
对象并将其传递给返回的ModelAndView
。 在大多数情况下,这是一个风格问题。
function明智没有区别,这些都是等价的:
@RequestMapping(..) public String requestMapping1(Model model){ model.addAttribute("attr1", attr1); return "viewName"; } @RequestMapping(..) public ModelAndView requestMapping2(){ ModelAndView modelAndView = new ModelAndView("viewName"); modelAndView.addObject("attr1", attr1); return modelAndView; }
然而,首选的方法是前者,这就是为什么作者在书籍样本中没有使用后者的原因。
在Spring源代码中,您可以看到此类org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
。 在方法public ModelAndView getModelAndView(...)
,您可以获得ModelAandView
-mvc如何生成ModelAandView
对象。
if (returnValue instanceof HttpEntity) { // returnValue is returned Value of Handler method handleHttpEntityResponse((HttpEntity>) returnValue, webRequest); return null; } else if (AnnotationUtils.findAnnotation(handlerMethod, ResponseBody.class) != null) { handleResponseBody(returnValue, webRequest); return null; } else if (returnValue instanceof ModelAndView) { ModelAndView mav = (ModelAndView) returnValue; mav.getModelMap().mergeAttributes(implicitModel); return mav; } else if (returnValue instanceof Model) { return new ModelAndView().addAllObjects(implicitModel).addAllObjects(((Model) returnValue).asMap()); } else if (returnValue instanceof View) { return new ModelAndView((View) returnValue).addAllObjects(implicitModel); } else if (AnnotationUtils.findAnnotation(handlerMethod, ModelAttribute.class) != null) { addReturnValueAsModelAttribute(handlerMethod, handlerType, returnValue, implicitModel); return new ModelAndView().addAllObjects(implicitModel); } else if (returnValue instanceof Map) { return new ModelAndView().addAllObjects(implicitModel).addAllObjects((Map) returnValue); } else if (returnValue instanceof String) { // String is here, return new ModelAndView return new ModelAndView((String) returnValue).addAllObjects(implicitModel); }
所以在这个方法中你可以知道spring-mvc可以处理许多返回类型的handler方法来构建ModleAndView对象。