概述
ModelAndView
是一个Spring MVC
小工具,一个持有器,用于持有如下信息 :
Object view
– 视图实际类型可能为
View
或者String
。
类型为View
时表示这是一个实际的View
对象。
类型为String
时表示这是一个目标View
对象的名称。HttpStatus status
– 将要写入响应的状态字可选
ModelMap model
– 数据模型用于结合
view
渲染最终结果页面的数据模型
DispatcherServlet
请求处理主逻辑执行请求处理Handler
的返回结果信息采用ModelAndView
的形式。然后这包数据ModelAndView
可能会被其他一些逻辑做进一步的调整,比如applyDefaultViewName
,或者某个HandlerInterceptor#postHandle
等。最终,DispatcherServlet
会使用这包数据ModelAndView
用于解析视图和渲染视图,参考DispatcherServlet#processDispatchResult
。
源代码
源代码版本 : spring-webmvc-5.1.5.RELEASE
package org.springframework.web.servlet;
import java.util.Map;
import org.springframework.http.HttpStatus;
import org.springframework.lang.Nullable;
import org.springframework.ui.ModelMap;
import org.springframework.util.CollectionUtils;
public class ModelAndView {
/** View instance or view name String. */
@Nullable
private Object view;
/** Model Map. */
@Nullable
private ModelMap model;
/** Optional HTTP status for the response. */
@Nullable
private HttpStatus status;
/** Indicates whether or not this instance has been cleared with a call to #clear(). */
private boolean cleared = false;
/**
* Default constructor for bean-style usage: populating bean
* properties instead of passing in constructor arguments.
* @see #setView(View)
* @see #setViewName(String)
*/
public ModelAndView() {
}
/**
* Convenient constructor when there is no model data to expose.
* Can also be used in conjunction with addObject.
* @param viewName name of the View to render, to be resolved
* by the DispatcherServlet's ViewResolver
* @see #addObject
*/
public ModelAndView(String viewName) {
this.view = viewName;
}
/**
* Convenient constructor when there is no model data to expose.
* Can also be used in conjunction with addObject.
* @param view the View object to render
* @see #addObject
*/
public ModelAndView(View view) {
this.view = view;
}
/**
* Create a new ModelAndView given a view name and a model.
* @param viewName name of the View to render, to be resolved
* by the DispatcherServlet's ViewResolver
* @param model a Map of model names (Strings) to model objects
* (Objects). Model entries may not be null, but the
* model Map may be null if there is no model data.
*/
public ModelAndView(String viewName, @Nullable Map<String, ?> model) {
this.view = viewName;
if (model != null) {
getModelMap().addAllAttributes(model);
}
}
/**
* Create a new ModelAndView given a View object and a model.
* Note: the supplied model data is copied into the internal
* storage of this class. You should not consider to modify the supplied
* Map after supplying it to this class
* @param view the View object to render
* @param model a Map of model names (Strings) to model objects
* (Objects). Model entries may not be null, but the
* model Map may be null if there is no model data.
*/
public ModelAndView(View view, @Nullable Map<String, ?> model) {
this.view = view;
if (model != null) {
getModelMap().addAllAttributes(model);
}
}
/**
* Create a new ModelAndView given a view name and HTTP status.
* @param viewName name of the View to render, to be resolved
* by the DispatcherServlet's ViewResolver
* @param status an HTTP status code to use for the response
* (to be set just prior to View rendering)
* @since 4.3.8
*/
public ModelAndView(String viewName, HttpStatus status) {
this.view = viewName;
this.status = status;
}
/**
* Create a new ModelAndView given a view name, model, and HTTP status.
* @param viewName name of the View to render, to be resolved
* by the DispatcherServlet's ViewResolver
* @param model a Map of model names (Strings) to model objects
* (Objects). Model entries may not be null, but the
* model Map may be null if there is no model data.
* @param status an HTTP status code to use for the response
* (to be set just prior to View rendering)
* @since 4.3
*/
public ModelAndView(@Nullable String viewName, @Nullable Map<String, ?> model, @Nullable HttpStatus status) {
this.view = viewName;
if (model != null) {
getModelMap().addAllAttributes(model);
}
this.status = status;
}
/**
* Convenient constructor to take a single model object.
* @param viewName name of the View to render, to be resolved
* by the DispatcherServlet's ViewResolver
* @param modelName name of the single entry in the model
* @param modelObject the single model object
*/
public ModelAndView(String viewName, String modelName, Object modelObject) {
this.view = viewName;
addObject(modelName, modelObject);
}
/**
* Convenient constructor to take a single model object.
* @param view the View object to render
* @param modelName name of the single entry in the model
* @param modelObject the single model object
*/
public ModelAndView(View view, String modelName, Object modelObject) {
this.view = view;
addObject(modelName, modelObject);
}
/**
* Set a view name for this ModelAndView, to be resolved by the
* DispatcherServlet via a ViewResolver. Will override any
* pre-existing view name or View.
*/
public void setViewName(@Nullable String viewName) {
this.view = viewName;
}
/**
* Return the view name to be resolved by the DispatcherServlet
* via a ViewResolver, or null if we are using a View object.
*/
@Nullable
public String getViewName() {
return (this.view instanceof String ? (String) this.view : null);
}
/**
* Set a View object for this ModelAndView. Will override any
* pre-existing view name or View.
*/
public void setView(@Nullable View view) {
this.view = view;
}
/**
* Return the View object, or null if we are using a view name
* to be resolved by the DispatcherServlet via a ViewResolver.
*/
@Nullable
public View getView() {
return (this.view instanceof View ? (View) this.view : null);
}
/**
* Indicate whether or not this ModelAndView has a view, either
* as a view name or as a direct View instance.
*/
public boolean hasView() {
return (this.view != null);
}
/**
* Return whether we use a view reference, i.e. true
* if the view has been specified via a name to be resolved by the
* DispatcherServlet via a ViewResolver.
*/
public boolean isReference() {
return (this.view instanceof String);
}
/**
* Return the model map. May return null.
* Called by DispatcherServlet for evaluation of the model.
*/
@Nullable
protected Map<String, Object> getModelInternal() {
return this.model;
}
/**
* Return the underlying ModelMap instance (never null).
*/
public ModelMap getModelMap() {
if (this.model == null) {
this.model = new ModelMap();
}
return this.model;
}
/**
* Return the model map. Never returns null.
* To be called by application code for modifying the model.
*/
public Map<String, Object> getModel() {
return getModelMap();
}
/**
* Set the HTTP status to use for the response.
* The response status is set just prior to View rendering.
* @since 4.3
*/
public void setStatus(@Nullable HttpStatus status) {
this.status = status;
}
/**
* Return the configured HTTP status for the response, if any.
* @since 4.3
*/
@Nullable
public HttpStatus getStatus() {
return this.status;
}
/**
* Add an attribute to the model.
* @param attributeName name of the object to add to the model (never null)
* @param attributeValue object to add to the model (can be null)
* @see ModelMap#addAttribute(String, Object)
* @see #getModelMap()
*/
public ModelAndView addObject(String attributeName, @Nullable Object attributeValue) {
getModelMap().addAttribute(attributeName, attributeValue);
return this;
}
/**
* Add an attribute to the model using parameter name generation.
* @param attributeValue the object to add to the model (never null)
* @see ModelMap#addAttribute(Object)
* @see #getModelMap()
*/
public ModelAndView addObject(Object attributeValue) {
getModelMap().addAttribute(attributeValue);
return this;
}
/**
* Add all attributes contained in the provided Map to the model.
* @param modelMap a Map of attributeName -> attributeValue pairs
* @see ModelMap#addAllAttributes(Map)
* @see #getModelMap()
*/
public ModelAndView addAllObjects(@Nullable Map<String, ?> modelMap) {
getModelMap().addAllAttributes(modelMap);
return this;
}
/**
* Clear the state of this ModelAndView object.
* The object will be empty afterwards.
* Can be used to suppress rendering of a given ModelAndView object
* in the {@code postHandle} method of a HandlerInterceptor.
* @see #isEmpty()
* @see HandlerInterceptor#postHandle
*/
public void clear() {
// 清除当前对象,使之变为空
this.view = null;
this.model = null;
this.cleared = true;
}
/**
* Return whether this ModelAndView object is empty,
* i.e. whether it does not hold any view and does not contain a model.
*/
public boolean isEmpty() {
// 如果视图未指定并且数据模型为空,则认为当前对象为空
return (this.view == null && CollectionUtils.isEmpty(this.model));
}
/**
* Return whether this ModelAndView object is empty as a result of a call to #clear
* i.e. whether it does not hold any view and does not contain a model.
* Returns false if any additional state was added to the instance
* after the call to #clear.
* @see #clear()
*/
public boolean wasCleared() {
return (this.cleared && isEmpty());
}
/**
* Return diagnostic information about this model and view.
*/
@Override
public String toString() {
return "ModelAndView [view=" + formatView() + "; model=" + this.model + "]";
}
private String formatView() {
return isReference() ? "\"" + this.view + "\"" : "[" + this.view + "]";
}
}