在学习Spring框架时,我注意到在“Spring”一书中,作者没有在控制器中使用ModelandView方法返回类型。作者将控制器方法声明为String的返回类型,方法中的返回子句只是返回一个字符串(如return "/views/theview"; )。
有人能详细解释一下这是如何工作的内部差异吗?
发布于 2013-08-14 21:29:05
这是一个深入的观察。
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中已知的实现类。
例如,如果返回一个字符串,Spring将使用ViewNameMethodReturnValueHandler来处理响应。
现在,使用哪种返回类型取决于您。如果您想返回一个Model,以便您可以在jsp视图中使用请求属性,您可以让Spring将一个Model实例传递给您的方法,或者您可以自己创建Model对象并将其传递给您返回的ModelAndView。在大多数情况下,这是一个风格问题。
发布于 2013-08-14 21:30:17
就功能而言,没有区别,这两者是等价的:
@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;
}然而,首选的方法是前者,这也是为什么作者没有在书中使用后者的原因。
发布于 2013-08-15 01:32:58
在spring源代码中,您可以看到这个类org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter。在public ModelAndView getModelAndView(...)方法中,您可以了解sping如何生成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可以处理许多返回类型的处理程序方法来构建ModleAndView对象。
https://stackoverflow.com/questions/18242454
复制相似问题