1. /*
  2. * Copyright 2002-2004 the original author or authors.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.springframework.web.servlet.mvc;
  17. import java.util.Map;
  18. import javax.servlet.ServletException;
  19. import javax.servlet.http.HttpServletRequest;
  20. import javax.servlet.http.HttpServletResponse;
  21. import org.springframework.validation.BindException;
  22. import org.springframework.validation.Errors;
  23. import org.springframework.web.servlet.ModelAndView;
  24. /**
  25. * <p>Concrete FormController implementation that provides configurable
  26. * form and success views, and an onSubmit chain for convenient overriding.
  27. * Automatically resubmits to the form view in case of validation errors,
  28. * and renders the success view in case of a valid submission.</p>
  29. *
  30. * <p>The workflow of this Controller does not differ much from the one described
  31. * in the {@link AbstractFormController AbstractFormController}. The difference
  32. * is that you do not need to implement {@link #showForm showForm} and
  33. * {@link #processFormSubmission processFormSubmission}: A form view and a
  34. * success view can be configured declaratively.</p>
  35. *
  36. * <p><b><a name="workflow">Workflow
  37. * (<a href="AbstractFormController.html#workflow">in addition to the superclass</a>):</b><br>
  38. * <ol>
  39. * <li>Call to {@link #processFormSubmission processFormSubmission} which inspects
  40. * the {@link org.springframework.validation.Errors Errors} object to see if
  41. * any errors have occurred during binding and validation.</li>
  42. * <li>If errors occured, the controller will return the configured formView,
  43. * showing the form again (possibly rendering according error messages).</li>
  44. * <li>If no errors occurred, the controller will call
  45. * {@link #onSubmit(HttpServletRequest, HttpServletResponse, Object, BindException) onSubmit}
  46. * using all parameters, which in case of the default implementation delegates to
  47. * {@link #onSubmit(Object, BindException) onSubmit} with just the command object.
  48. * The default implementation of the latter method will return the configured
  49. * successView. Consider implementing {@link #doSubmitAction} doSubmitAction
  50. * for simply performing a submit action and rendering the success view.</li>
  51. * </ol>
  52. * </p>
  53. *
  54. * <p>The submit behavior can be customized by overriding one of the
  55. * {@link #onSubmit onSubmit} methods. Submit actions can also perform
  56. * custom validation if necessary (typically database-driven checks), calling
  57. * {@link #showForm(HttpServletRequest, HttpServletResponse, BindException) showForm}
  58. * in case of validation errors to show the form view again.</p>
  59. *
  60. * <p><b><a name="config">Exposed configuration properties</a>
  61. * (<a href="AbstractFormController.html#config">and those defined by superclass</a>):</b><br>
  62. * <table border="1">
  63. * <tr>
  64. * <td><b>name</b></td>
  65. * <td><b>default</b></td>
  66. * <td><b>description</b></td>
  67. * </tr>
  68. * <tr>
  69. * <td>formView</td>
  70. * <td><i>null</i></td>
  71. * <td>Indicates what view to use when the user asks for a new form
  72. * or when validation errors have occurred on form submission.</td>
  73. * </tr>
  74. * <tr>
  75. * <td>successView</td>
  76. * <td><i>null</i></td>
  77. * <td>Indicates what view to use when successful form submissions have
  78. * occurred. Such a success view could e.g. display a submission summary.
  79. * More sophisticated actions can be implemented by overriding one of
  80. * the {@link #onSubmit(Object) onSubmit()} methods.</td>
  81. * </tr>
  82. * <table>
  83. * </p>
  84. *
  85. * @author Juergen Hoeller
  86. * @since 05.05.2003
  87. */
  88. public class SimpleFormController extends AbstractFormController {
  89. private String formView;
  90. private String successView;
  91. /**
  92. * Create a new SimpleFormController.
  93. * <p>Subclasses should set the following properties, either in the constructor
  94. * or via a BeanFactory: commandName, commandClass, sessionForm, formView,
  95. * successView. Note that commandClass doesn't need to be set when overriding
  96. * formBackingObject, as this determines the class anyway.
  97. * @see #setCommandClass
  98. * @see #setCommandName
  99. * @see #setSessionForm
  100. * @see #setFormView
  101. * @see #setSuccessView
  102. */
  103. public SimpleFormController() {
  104. super();
  105. }
  106. /**
  107. * Set the name of the view that should be used for form display.
  108. */
  109. public final void setFormView(String formView) {
  110. this.formView = formView;
  111. }
  112. /**
  113. * Return the name of the view that should be used for form display.
  114. */
  115. protected final String getFormView() {
  116. return this.formView;
  117. }
  118. /**
  119. * Set the name of the view that should be shown on successful submit.
  120. */
  121. public final void setSuccessView(String successView) {
  122. this.successView = successView;
  123. }
  124. /**
  125. * Return the name of the view that should be shown on successful submit.
  126. */
  127. protected final String getSuccessView() {
  128. return this.successView;
  129. }
  130. /**
  131. * Create a reference data map for the given request and command,
  132. * consisting of bean name/bean instance pairs as expected by ModelAndView.
  133. * <p>Default implementation delegates to referenceData(request).
  134. * Subclasses can override this to set reference data used in the view.
  135. * @param request current HTTP request
  136. * @param command form object with request parameters bound onto it
  137. * @param errors validation errors holder
  138. * @return a Map with reference data entries, or null if none
  139. * @throws Exception in case of invalid state or arguments
  140. * @see ModelAndView
  141. */
  142. protected Map referenceData(HttpServletRequest request, Object command, Errors errors) throws Exception {
  143. return referenceData(request);
  144. }
  145. /**
  146. * Create a reference data map for the given request.
  147. * Called by referenceData version with all parameters.
  148. * <p>Default implementation returns null.
  149. * Subclasses can override this to set reference data used in the view.
  150. * @param request current HTTP request
  151. * @return a Map with reference data entries, or null if none
  152. * @throws Exception in case of invalid state or arguments
  153. * @see #referenceData(HttpServletRequest, Object, Errors)
  154. * @see ModelAndView
  155. */
  156. protected Map referenceData(HttpServletRequest request) throws Exception {
  157. return null;
  158. }
  159. /**
  160. * This implementation shows the configured form view.
  161. * Can be called within onSubmit implementations, to redirect back to the form
  162. * in case of custom validation errors (i.e. not determined by the validator).
  163. * @see #setFormView
  164. */
  165. protected ModelAndView showForm(HttpServletRequest request, HttpServletResponse response,
  166. BindException errors) throws Exception {
  167. return showForm(request, errors, getFormView());
  168. }
  169. /**
  170. * This implementation calls showForm in case of errors,
  171. * and delegates to onSubmit's full version else.
  172. * <p>This can only be overridden to check for an action that should be executed
  173. * without respect to binding errors, like a cancel action. To just handle successful
  174. * submissions without binding errors, override one of the onSubmit methods.
  175. * @see #showForm
  176. * @see #onSubmit(HttpServletRequest, HttpServletResponse, Object, BindException)
  177. */
  178. protected ModelAndView processFormSubmission(HttpServletRequest request, HttpServletResponse response,
  179. Object command, BindException errors) throws Exception {
  180. if (errors.hasErrors()) {
  181. logger.debug("Data binding errors: " + errors.getErrorCount());
  182. return showForm(request, response, errors);
  183. }
  184. else {
  185. logger.debug("No errors -> processing submit");
  186. return onSubmit(request, response, command, errors);
  187. }
  188. }
  189. /**
  190. * Submit callback with all parameters. Called in case of submit without errors
  191. * reported by the registered validator respectively on every submit if no validator.
  192. * <p>Default implementation delegates to onSubmit(Object, BindException).
  193. * For simply performing a submit action and rendering the specified success view,
  194. * consider implementing doSubmitAction rather than an onSubmit version.
  195. * <p>Subclasses can override this to provide custom submission handling like storing
  196. * the object to the database. Implementations can also perform custom validation and
  197. * call showForm to return to the form. Do <i>not</i> implement multiple onSubmit
  198. * methods: In that case, just this method will be called by the controller.
  199. * <p>Call <code>errors.getModel()</code> to populate the ModelAndView model
  200. * with the command and the Errors instance, under the specified command name,
  201. * as expected by the "spring:bind" tag.
  202. * @param request current servlet request
  203. * @param response current servlet response
  204. * @param command form object with request parameters bound onto it
  205. * @param errors Errors instance without errors (subclass can add errors if it wants to)
  206. * @return the prepared model and view, or null
  207. * @throws Exception in case of errors
  208. * @see #onSubmit(Object, BindException)
  209. * @see #doSubmitAction
  210. * @see #showForm
  211. * @see org.springframework.validation.Errors
  212. * @see org.springframework.validation.BindException#getModel
  213. */
  214. protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response,
  215. Object command, BindException errors) throws Exception {
  216. return onSubmit(command, errors);
  217. }
  218. /**
  219. * Simpler onSubmit version. Called by the default implementation of the onSubmit
  220. * version with all parameters.
  221. * <p>Default implementation calls onSubmit(command), using the returned ModelAndView
  222. * if actually implemented in a subclass. Else, the default behavior is applied:
  223. * rendering the success view with the command and Errors instance as model.
  224. * <p>Subclasses can override this to provide custom submission handling that
  225. * does not need request and response.
  226. * <p>Call <code>errors.getModel()</code> to populate the ModelAndView model
  227. * with the command and the Errors instance, under the specified command name,
  228. * as expected by the "spring:bind" tag.
  229. * @param command form object with request parameters bound onto it
  230. * @param errors Errors instance without errors
  231. * @return the prepared model and view, or null
  232. * @throws Exception in case of errors
  233. * @see #onSubmit(HttpServletRequest, HttpServletResponse, Object, BindException)
  234. * @see #onSubmit(Object)
  235. * @see #setSuccessView
  236. * @see org.springframework.validation.Errors
  237. * @see org.springframework.validation.BindException#getModel
  238. */
  239. protected ModelAndView onSubmit(Object command, BindException errors) throws Exception {
  240. ModelAndView mv = onSubmit(command);
  241. if (mv != null) {
  242. // simplest onSubmit version implemented in custom subclass
  243. return mv;
  244. }
  245. else {
  246. // default behavior: render success view
  247. if (getSuccessView() == null) {
  248. throw new ServletException("successView isn't set");
  249. }
  250. return new ModelAndView(getSuccessView(), errors.getModel());
  251. }
  252. }
  253. /**
  254. * Simplest onSubmit version. Called by the default implementation of the onSubmit
  255. * version with command and BindException parameters.
  256. * <p>This implementation calls doSubmitAction and returns null as ModelAndView, making
  257. * the calling onSubmit method perform its default rendering of the success view.
  258. * <p>Subclasses can override this to provide custom submission handling that
  259. * just needs the command object.
  260. * @param command form object with request parameters bound onto it
  261. * @return the prepared model and view, or null
  262. * @throws Exception in case of errors
  263. * @see #onSubmit(Object, BindException)
  264. * @see #doSubmitAction
  265. */
  266. protected ModelAndView onSubmit(Object command) throws Exception {
  267. doSubmitAction(command);
  268. return null;
  269. }
  270. /**
  271. * Template method for submit actions. Called by the default implementation
  272. * of the simplest onSubmit version.
  273. * <p><b>This is the preferred submit callback to implement if you want to
  274. * perform an action (like storing changes to the database) and then render
  275. * the success view with the command and Errors instance as model.</b>
  276. * You don't need to care about the success ModelAndView here.
  277. * @param command form object with request parameters bound onto it
  278. * @throws Exception in case of errors
  279. * @see #onSubmit(Object)
  280. * @see #setSuccessView
  281. */
  282. protected void doSubmitAction(Object command) throws Exception {
  283. }
  284. }