While learning the Spring framework, I notice in the book Spring in Action, the author doesn\'t use ModelandView method return type in controllers. The aut
Here's an in depth look.
Spring offers a DispatcherServlet class that, typically, handles all your requests. It does this in its doDispatch(HttpServletRequest request, HttpServletResponse response) method
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
where mv is the final ModelAndView object, ha is a wrapper to your controller method annotated with @RequestMapping.
This will usually go through a stack of method calls ending up at 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
Looking at the source
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 is the object returned by your @RequestMapping method. It goes through
this.returnValueHandlers.handleReturnValue
where Spring determines a HandlerMethodReturnValueHandler to handle that object.
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); returns the appropriate handler. The HandlerMethodReturnValueHandler is an interface with a supportsReturnType method that returns true if the handler supports that type (String, View, ResponseEntity, etc. (look for supported return types)). So the method returns the first handler it finds that supports that type and runs it.
Spring, at initialization, registers a whole slew of implementations of HandlerMethodReturnValueHandler. Basically all the known implementing classes in its javadoc.
For example, if you return a String, Spring will use a ViewNameMethodReturnValueHandler to handle the response.
Now, which return type to use is up to you. If you wanted to return a Model so you can use request attributes in your jsp view, you can either have Spring pass a Model instance to your method or you can create the Model object yourself and pass it to a ModelAndView which your return. It's a matter of style in most cases.