001/*002 * Copyright 2002-2018 the original author or authors.003 *004 * Licensed under the Apache License, Version 2.0 (the "License");005 * you may not use this file except in compliance with the License.006 * You may obtain a copy of the License at007 *008 * https://www.apache.org/licenses/LICENSE-2.0009 *010 * Unless required by applicable law or agreed to in writing, software011 * distributed under the License is distributed on an "AS IS" BASIS,012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.013 * See the License for the specific language governing permissions and014 * limitations under the License.015 */016017package org.springframework.web.method.support;018019import java.util.HashSet;020import java.util.Map;021import java.util.Set;022023import org.springframework.http.HttpStatus;024import org.springframework.ui.Model;025import org.springframework.ui.ModelMap;026import org.springframework.validation.support.BindingAwareModelMap;027import org.springframework.web.bind.support.SessionStatus;028import org.springframework.web.bind.support.SimpleSessionStatus;029030/**031 * Records model and view related decisions made by032 * {@link HandlerMethodArgumentResolver}s and033 * {@link HandlerMethodReturnValueHandler}s during the course of invocation of034 * a controller method.035 *036 * <p>The {@link #setRequestHandled} flag can be used to indicate the request037 * has been handled directly and view resolution is not required.038 *039 * <p>A default {@link Model} is automatically created at instantiation.040 * An alternate model instance may be provided via {@link #setRedirectModel}041 * for use in a redirect scenario. When {@link #setRedirectModelScenario} is set042 * to {@code true} signalling a redirect scenario, the {@link #getModel()}043 * returns the redirect model instead of the default model.044 *045 * @author Rossen Stoyanchev046 * @author Juergen Hoeller047 * @since 3.1048 */049public class ModelAndViewContainer {050051 private boolean ignoreDefaultModelOnRedirect = false;052053 private Object view;054055 private final ModelMap defaultModel = new BindingAwareModelMap();056057 private ModelMap redirectModel;058059 private boolean redirectModelScenario = false;060061 private HttpStatus status;062063 private final Set<String> noBinding = new HashSet<String>(4);064065 private final Set<String> bindingDisabled = new HashSet<String>(4);066067 private final SessionStatus sessionStatus = new SimpleSessionStatus();068069 private boolean requestHandled = false;070071072 /**073 * By default the content of the "default" model is used both during074 * rendering and redirect scenarios. Alternatively controller methods075 * can declare an argument of type {@code RedirectAttributes} and use076 * it to provide attributes to prepare the redirect URL.077 * <p>Setting this flag to {@code true} guarantees the "default" model is078 * never used in a redirect scenario even if a RedirectAttributes argument079 * is not declared. Setting it to {@code false} means the "default" model080 * may be used in a redirect if the controller method doesn't declare a081 * RedirectAttributes argument.082 * <p>The default setting is {@code false}.083 */084 public void setIgnoreDefaultModelOnRedirect(boolean ignoreDefaultModelOnRedirect) {085 this.ignoreDefaultModelOnRedirect = ignoreDefaultModelOnRedirect;086 }087088 /**089 * Set a view name to be resolved by the DispatcherServlet via a ViewResolver.090 * Will override any pre-existing view name or View.091 */092 public void setViewName(String viewName) {093 this.view = viewName;094 }095096 /**097 * Return the view name to be resolved by the DispatcherServlet via a098 * ViewResolver, or {@code null} if a View object is set.099 */100 public String getViewName() {101 return (this.view instanceof String ? (String) this.view : null);102 }103104 /**105 * Set a View object to be used by the DispatcherServlet.106 * Will override any pre-existing view name or View.107 */108 public void setView(Object view) {109 this.view = view;110 }111112 /**113 * Return the View object, or {@code null} if we using a view name114 * to be resolved by the DispatcherServlet via a ViewResolver.115 */116 public Object getView() {117 return this.view;118 }119120 /**121 * Whether the view is a view reference specified via a name to be122 * resolved by the DispatcherServlet via a ViewResolver.123 */124 public boolean isViewReference() {125 return (this.view instanceof String);126 }127128 /**129 * Return the model to use -- either the "default" or the "redirect" model.130 * The default model is used if {@code redirectModelScenario=false} or131 * there is no redirect model (i.e. RedirectAttributes was not declared as132 * a method argument) and {@code ignoreDefaultModelOnRedirect=false}.133 */134 public ModelMap getModel() {135 if (useDefaultModel()) {136 return this.defaultModel;137 }138 else {139 if (this.redirectModel == null) {140 this.redirectModel = new ModelMap();141 }142 return this.redirectModel;143 }144 }145146 /**147 * Whether to use the default model or the redirect model.148 */149 private boolean useDefaultModel() {150 return (!this.redirectModelScenario || (this.redirectModel == null && !this.ignoreDefaultModelOnRedirect));151 }152153 /**154 * Return the "default" model created at instantiation.155 * <p>In general it is recommended to use {@link #getModel()} instead which156 * returns either the "default" model (template rendering) or the "redirect"157 * model (redirect URL preparation). Use of this method may be needed for158 * advanced cases when access to the "default" model is needed regardless,