001/* 002 * Copyright 2002-2017 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 at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * 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 and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.servlet.mvc; 018 019import javax.servlet.http.HttpServletRequest; 020import javax.servlet.http.HttpServletResponse; 021 022import org.springframework.http.HttpMethod; 023import org.springframework.http.HttpStatus; 024import org.springframework.lang.Nullable; 025import org.springframework.web.servlet.ModelAndView; 026import org.springframework.web.servlet.View; 027import org.springframework.web.servlet.support.RequestContextUtils; 028 029/** 030 * Trivial controller that always returns a pre-configured view and optionally 031 * sets the response status code. The view and status can be configured using 032 * the provided configuration properties. 033 * 034 * @author Rod Johnson 035 * @author Juergen Hoeller 036 * @author Keith Donald 037 * @author Rossen Stoyanchev 038 */ 039public class ParameterizableViewController extends AbstractController { 040 041 @Nullable 042 private Object view; 043 044 @Nullable 045 private HttpStatus statusCode; 046 047 private boolean statusOnly; 048 049 050 public ParameterizableViewController() { 051 super(false); 052 setSupportedMethods(HttpMethod.GET.name(), HttpMethod.HEAD.name()); 053 } 054 055 /** 056 * Set a view name for the ModelAndView to return, to be resolved by the 057 * DispatcherServlet via a ViewResolver. Will override any pre-existing 058 * view name or View. 059 */ 060 public void setViewName(@Nullable String viewName) { 061 this.view = viewName; 062 } 063 064 /** 065 * Return the name of the view to delegate to, or {@code null} if using a 066 * View instance. 067 */ 068 @Nullable 069 public String getViewName() { 070 if (this.view instanceof String) { 071 String viewName = (String) this.view; 072 if (getStatusCode() != null && getStatusCode().is3xxRedirection()) { 073 return viewName.startsWith("redirect:") ? viewName : "redirect:" + viewName; 074 } 075 else { 076 return viewName; 077 } 078 } 079 return null; 080 } 081 082 /** 083 * Set a View object for the ModelAndView to return. 084 * Will override any pre-existing view name or View. 085 * @since 4.1 086 */ 087 public void setView(View view) { 088 this.view = view; 089 } 090 091 /** 092 * Return the View object, or {@code null} if we are using a view name 093 * to be resolved by the DispatcherServlet via a ViewResolver. 094 * @since 4.1 095 */ 096 @Nullable 097 public View getView() { 098 return (this.view instanceof View ? (View) this.view : null); 099 } 100 101 /** 102 * Configure the HTTP status code that this controller should set on the 103 * response. 104 * <p>When a "redirect:" prefixed view name is configured, there is no need 105 * to set this property since RedirectView will do that. However this property 106 * may still be used to override the 3xx status code of {@code RedirectView}. 107 * For full control over redirecting provide a {@code RedirectView} instance. 108 * <p>If the status code is 204 and no view is configured, the request is 109 * fully handled within the controller. 110 * @since 4.1 111 */ 112 public void setStatusCode(@Nullable HttpStatus statusCode) { 113 this.statusCode = statusCode; 114 } 115 116 /** 117 * Return the configured HTTP status code or {@code null}. 118 * @since 4.1 119 */ 120 @Nullable 121 public HttpStatus getStatusCode() { 122 return this.statusCode; 123 } 124 125 126 /** 127 * The property can be used to indicate the request is considered fully 128 * handled within the controller and that no view should be used for rendering. 129 * Useful in combination with {@link #setStatusCode}. 130 * <p>By default this is set to {@code false}. 131 * @since 4.1 132 */ 133 public void setStatusOnly(boolean statusOnly) { 134 this.statusOnly = statusOnly; 135 } 136 137 /** 138 * Whether the request is fully handled within the controller. 139 */ 140 public boolean isStatusOnly() { 141 return this.statusOnly; 142 } 143 144 145 /** 146 * Return a ModelAndView object with the specified view name. 147 * <p>The content of the {@link RequestContextUtils#getInputFlashMap 148 * "input" FlashMap} is also added to the model. 149 * @see #getViewName() 150 */ 151 @Override 152 protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) 153 throws Exception { 154 155 String viewName = getViewName(); 156 157 if (getStatusCode() != null) { 158 if (getStatusCode().is3xxRedirection()) { 159 request.setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, getStatusCode()); 160 } 161 else { 162 response.setStatus(getStatusCode().value()); 163 if (getStatusCode().equals(HttpStatus.NO_CONTENT) && viewName == null) { 164 return null; 165 } 166 } 167 } 168 169 if (isStatusOnly()) { 170 return null; 171 } 172 173 ModelAndView modelAndView = new ModelAndView(); 174 modelAndView.addAllObjects(RequestContextUtils.getInputFlashMap(request)); 175 if (viewName != null) { 176 modelAndView.setViewName(viewName); 177 } 178 else { 179 modelAndView.setView(getView()); 180 } 181 return modelAndView; 182 } 183 184 @Override 185 public String toString() { 186 return "ParameterizableViewController [" + formatStatusAndView() + "]"; 187 } 188 189 private String formatStatusAndView() { 190 StringBuilder sb = new StringBuilder(); 191 if (this.statusCode != null) { 192 sb.append("status=").append(this.statusCode); 193 } 194 if (this.view != null) { 195 sb.append(sb.length() != 0 ? ", " : ""); 196 String viewName = getViewName(); 197 sb.append("view=").append(viewName != null ? "\"" + viewName + "\"" : this.view); 198 } 199 return sb.toString(); 200 } 201}