KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > web > servlet > mvc > SimpleFormController


1 /*
2  * Copyright 2002-2006 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
17 package org.springframework.web.servlet.mvc;
18
19 import java.util.Map JavaDoc;
20
21 import javax.servlet.ServletException JavaDoc;
22 import javax.servlet.http.HttpServletRequest JavaDoc;
23 import javax.servlet.http.HttpServletResponse JavaDoc;
24
25 import org.springframework.validation.BindException;
26 import org.springframework.validation.Errors;
27 import org.springframework.web.servlet.ModelAndView;
28
29 /**
30  * <p>Concrete FormController implementation that provides configurable
31  * form and success views, and an onSubmit chain for convenient overriding.
32  * Automatically resubmits to the form view in case of validation errors,
33  * and renders the success view in case of a valid submission.</p>
34  *
35  * <p>The workflow of this Controller does not differ much from the one described
36  * in the {@link AbstractFormController AbstractFormController}. The difference
37  * is that you do not need to implement {@link #showForm showForm} and
38  * {@link #processFormSubmission processFormSubmission}: A form view and a
39  * success view can be configured declaratively.</p>
40  *
41  * <p><b><a name="workflow">Workflow
42  * (<a HREF="AbstractFormController.html#workflow">in addition to the superclass</a>):</b><br>
43  * <ol>
44  * <li>Call to {@link #processFormSubmission processFormSubmission} which inspects
45  * the {@link org.springframework.validation.Errors Errors} object to see if
46  * any errors have occurred during binding and validation.</li>
47  * <li>If errors occured, the controller will return the configured formView,
48  * showing the form again (possibly rendering according error messages).</li>
49  * <li>If {@link #isFormChangeRequest isFormChangeRequest} is overridden and returns
50  * true for the given request, the controller will return the formView too.
51  * In that case, the controller will also suppress validation. Before returning the formView,
52  * the controller will invoke {@link #onFormChange}, giving sub-classes a chance
53  * to make modification to the command object.
54  * This is intended for requests that change the structure of the form,
55  * which should not cause validation and show the form in any case.</li>
56  * <li>If no errors occurred, the controller will call
57  * {@link #onSubmit(HttpServletRequest, HttpServletResponse, Object, BindException) onSubmit}
58  * using all parameters, which in case of the default implementation delegates to
59  * {@link #onSubmit(Object, BindException) onSubmit} with just the command object.
60  * The default implementation of the latter method will return the configured
61  * <code>successView</code>. Consider implementing {@link #doSubmitAction} doSubmitAction
62  * for simply performing a submit action and rendering the success view.</li>
63  * </ol>
64  * </p>
65  *
66  * <p>The submit behavior can be customized by overriding one of the
67  * {@link #onSubmit onSubmit} methods. Submit actions can also perform
68  * custom validation if necessary (typically database-driven checks), calling
69  * {@link #showForm(HttpServletRequest, HttpServletResponse, BindException) showForm}
70  * in case of validation errors to show the form view again.</p>
71  *
72  * <p><b><a name="config">Exposed configuration properties</a>
73  * (<a HREF="AbstractFormController.html#config">and those defined by superclass</a>):</b><br>
74  * <table border="1">
75  * <tr>
76  * <td><b>name</b></td>
77  * <td><b>default</b></td>
78  * <td><b>description</b></td>
79  * </tr>
80  * <tr>
81  * <td>formView</td>
82  * <td><i>null</i></td>
83  * <td>Indicates what view to use when the user asks for a new form
84  * or when validation errors have occurred on form submission.</td>
85  * </tr>
86  * <tr>
87  * <td>successView</td>
88  * <td><i>null</i></td>
89  * <td>Indicates what view to use when successful form submissions have
90  * occurred. Such a success view could e.g. display a submission summary.
91  * More sophisticated actions can be implemented by overriding one of
92  * the {@link #onSubmit(Object) onSubmit()} methods.</td>
93  * </tr>
94  * <table>
95  * </p>
96  *
97  * @author Juergen Hoeller
98  * @author Rob Harrop
99  * @since 05.05.2003
100  */

101 public class SimpleFormController extends AbstractFormController {
102
103     private String JavaDoc formView;
104
105     private String JavaDoc successView;
106
107
108     /**
109      * Create a new SimpleFormController.
110      * <p>Subclasses should set the following properties, either in the constructor
111      * or via a BeanFactory: commandName, commandClass, sessionForm, formView,
112      * successView. Note that commandClass doesn't need to be set when overriding
113      * <code>formBackingObject</code>, as this determines the class anyway.
114      * @see #setCommandClass
115      * @see #setCommandName
116      * @see #setSessionForm
117      * @see #setFormView
118      * @see #setSuccessView
119      * @see #formBackingObject
120      */

121     public SimpleFormController() {
122         // AbstractFormController sets default cache seconds to 0.
123
super();
124     }
125
126     /**
127      * Set the name of the view that should be used for form display.
128      */

129     public final void setFormView(String JavaDoc formView) {
130         this.formView = formView;
131     }
132
133     /**
134      * Return the name of the view that should be used for form display.
135      */

136     public final String JavaDoc getFormView() {
137         return this.formView;
138     }
139
140     /**
141      * Set the name of the view that should be shown on successful submit.
142      */

143     public final void setSuccessView(String JavaDoc successView) {
144         this.successView = successView;
145     }
146
147     /**
148      * Return the name of the view that should be shown on successful submit.
149      */

150     public final String JavaDoc getSuccessView() {
151         return this.successView;
152     }
153
154
155     /**
156      * This implementation shows the configured form view, delegating to the analogous
157      * {@link #showForm(HttpServletRequest, HttpServletResponse, BindException, Map)}
158      * variant with a "controlModel" argument.
159      * <p>Can be called within
160      * {@link #onSubmit(HttpServletRequest, HttpServletResponse, Object, BindException)}
161      * implementations, to redirect back to the form in case of custom validation errors
162      * (errors not determined by the validator).
163      * <p>Can be overridden in subclasses to show a custom view, writing directly
164      * to the response or preparing the response before rendering a view.
165      * <p>If calling showForm with a custom control model in subclasses, it's preferable
166      * to override the analogous showForm version with a controlModel argument
167      * (which will handle both standard form showing and custom form showing then).
168      * @see #setFormView
169      * @see #showForm(HttpServletRequest, HttpServletResponse, BindException, Map)
170      */

171     protected ModelAndView showForm(
172             HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response, BindException errors)
173             throws Exception JavaDoc {
174
175         return showForm(request, response, errors, null);
176     }
177
178     /**
179      * This implementation shows the configured form view.
180      * <p>Can be called within
181      * {@link #onSubmit(HttpServletRequest, HttpServletResponse, Object, BindException)}
182      * implementations, to redirect back to the form in case of custom validation errors
183      * (errors not determined by the validator).
184      * <p>Can be overridden in subclasses to show a custom view, writing directly
185      * to the response or preparing the response before rendering a view.
186      * @param request current HTTP request
187      * @param errors validation errors holder
188      * @param controlModel model map containing controller-specific control data
189      * (e.g. current page in wizard-style controllers or special error message)
190      * @return the prepared form view
191      * @throws Exception in case of invalid state or arguments
192      * @see #setFormView
193      */

194     protected ModelAndView showForm(
195             HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response, BindException errors, Map JavaDoc controlModel)
196             throws Exception JavaDoc {
197
198         return showForm(request, errors, getFormView(), controlModel);
199     }
200
201     /**
202      * Create a reference data map for the given request and command,
203      * consisting of bean name/bean instance pairs as expected by ModelAndView.
204      * <p>The default implementation delegates to {@link #referenceData(HttpServletRequest)}.
205      * Subclasses can override this to set reference data used in the view.
206      * @param request current HTTP request
207      * @param command form object with request parameters bound onto it
208      * @param errors validation errors holder
209      * @return a Map with reference data entries, or <code>null</code> if none
210      * @throws Exception in case of invalid state or arguments
211      * @see ModelAndView
212      */

213     protected Map JavaDoc referenceData(HttpServletRequest JavaDoc request, Object JavaDoc command, Errors errors) throws Exception JavaDoc {
214         return referenceData(request);
215     }
216
217     /**
218      * Create a reference data map for the given request.
219      * Called by the {@link #referenceData(HttpServletRequest, Object, Errors)}
220      * variant with all parameters.
221      * <p>The default implementation returns <code>null</code>.
222      * Subclasses can override this to set reference data used in the view.
223      * @param request current HTTP request
224      * @return a Map with reference data entries, or <code>null</code> if none
225      * @throws Exception in case of invalid state or arguments
226      * @see #referenceData(HttpServletRequest, Object, Errors)
227      * @see ModelAndView
228      */

229     protected Map JavaDoc referenceData(HttpServletRequest JavaDoc request) throws Exception JavaDoc {
230         return null;
231     }
232
233
234     /**
235      * This implementation calls
236      * {@link #showForm(HttpServletRequest, HttpServletResponse, BindException)}
237      * in case of errors, and delegates to the full
238      * {@link #onSubmit(HttpServletRequest, HttpServletResponse, Object, BindException)}'s
239      * variant else.
240      * <p>This can only be overridden to check for an action that should be executed
241      * without respect to binding errors, like a cancel action. To just handle successful
242      * submissions without binding errors, override one of the <code>onSubmit</code>
243      * methods or {@link #doSubmitAction}.
244      * @see #showForm(HttpServletRequest, HttpServletResponse, BindException)
245      * @see #onSubmit(HttpServletRequest, HttpServletResponse, Object, BindException)
246      * @see #onSubmit(Object, BindException)
247      * @see #onSubmit(Object)
248      * @see #doSubmitAction(Object)
249      */

250     protected ModelAndView processFormSubmission(
251             HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response, Object JavaDoc command, BindException errors)
252             throws Exception JavaDoc {
253
254         if (errors.hasErrors()) {
255             if (logger.isDebugEnabled()) {
256                 logger.debug("Data binding errors: " + errors.getErrorCount());
257             }
258             return showForm(request, response, errors);
259         }
260         else if (isFormChangeRequest(request, command)) {
261             logger.debug("Detected form change request -> routing request to onFormChange");
262             onFormChange(request, response, command, errors);
263             return showForm(request, response, errors);
264         }
265         else {
266             logger.debug("No errors -> processing submit");
267             return onSubmit(request, response, command, errors);
268         }
269     }
270
271     /**
272      * This implementation delegates to {@link #isFormChangeRequest(HttpServletRequest, Object)}:
273      * A form change request changes the appearance of the form and should not get
274      * validated but just show the new form.
275      * @see #isFormChangeRequest
276      */

277     protected boolean suppressValidation(HttpServletRequest JavaDoc request, Object JavaDoc command) {
278         return isFormChangeRequest(request, command);
279     }
280
281     /**
282      * Determine whether the given request is a form change request.
283      * A form change request changes the appearance of the form
284      * and should always show the new form, without validation.
285      * <p>Gets called by {@link #suppressValidation} and {@link #processFormSubmission}.
286      * Consequently, this single method determines to suppress validation
287      * <i>and</i> to show the form view in any case.
288      * <p>The default implementation delegates to {@link #onSubmit(Object, BindException)}.
289      * @param request current HTTP request
290      * @param command form object with request parameters bound onto it
291      * @return whether the given request is a form change request
292      * @see #suppressValidation
293      * @see #processFormSubmission
294      */

295     protected boolean isFormChangeRequest(HttpServletRequest JavaDoc request, Object JavaDoc command) {
296         return isFormChangeRequest(request);
297     }
298
299     /**
300      * Simpler <code>isFormChangeRequest</code> variant, called by the full
301      * variant {@link #isFormChangeRequest(HttpServletRequest, Object)}.
302      * <p>The default implementation is empty.
303      * @param request current HTTP request
304      * @return whether the given request is a form change request
305      * @see #suppressValidation
306      * @see #processFormSubmission
307      */

308     protected boolean isFormChangeRequest(HttpServletRequest JavaDoc request) {
309         return false;
310     }
311
312     /**
313      * Called during form submission if
314      * {@link #isFormChangeRequest(javax.servlet.http.HttpServletRequest)}
315      * returns <code>true</code>. Allows subclasses to implement custom logic
316      * to modify the command object to directly modify data in the form.
317      * <p>The default implementation delegates to
318      * {@link #onFormChange(HttpServletRequest, HttpServletResponse, Object, BindException)}.
319      * @param request current servlet request
320      * @param response current servlet response
321      * @param command form object with request parameters bound onto it
322      * @param errors validation errors holder, allowing for additional
323      * custom validation
324      * @throws Exception in case of errors
325      * @see #isFormChangeRequest(HttpServletRequest)
326      * @see #onFormChange(HttpServletRequest, HttpServletResponse, Object)
327      */

328     protected void onFormChange(
329             HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response, Object JavaDoc command, BindException errors)
330             throws Exception JavaDoc {
331
332         onFormChange(request, response, command);
333     }
334
335     /**
336      * Simpler <code>onFormChange</code> variant, called by the full variant
337      * {@link #onFormChange(HttpServletRequest, HttpServletResponse, Object, BindException)}.
338      * <p>The default implementation is empty.
339      * @param request current servlet request
340      * @param response current servlet response
341      * @param command form object with request parameters bound onto it
342      * @throws Exception in case of errors
343      * @see #onFormChange(HttpServletRequest, HttpServletResponse, Object, BindException)
344      */

345     protected void onFormChange(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response, Object JavaDoc command)
346             throws Exception JavaDoc {
347     }
348
349
350     /**
351      * Submit callback with all parameters. Called in case of submit without errors
352      * reported by the registered validator, or on every submit if no validator.
353      * <p>The default implementation delegates to {@link #onSubmit(Object, BindException)}.
354      * For simply performing a submit action and rendering the specified success
355      * view, consider implementing {@link #doSubmitAction} rather than an
356      * <code>onSubmit</code> variant.
357      * <p>Subclasses can override this to provide custom submission handling like storing
358      * the object to the database. Implementations can also perform custom validation and
359      * call showForm to return to the form. Do <i>not</i> implement multiple onSubmit
360      * methods: In that case, just this method will be called by the controller.
361      * <p>Call <code>errors.getModel()</code> to populate the ModelAndView model
362      * with the command and the Errors instance, under the specified command name,
363      * as expected by the "spring:bind" tag.
364      * @param request current servlet request
365      * @param response current servlet response
366      * @param command form object with request parameters bound onto it
367      * @param errors Errors instance without errors (subclass can add errors if it wants to)
368      * @return the prepared model and view, or <code>null</code>
369      * @throws Exception in case of errors
370      * @see #onSubmit(Object, BindException)
371      * @see #doSubmitAction
372      * @see #showForm
373      * @see org.springframework.validation.Errors
374      * @see org.springframework.validation.BindException#getModel
375      */

376     protected ModelAndView onSubmit(
377             HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response, Object JavaDoc command, BindException errors)
378             throws Exception JavaDoc {
379
380         return onSubmit(command, errors);
381     }
382
383     /**
384      * Simpler <code>onSubmit</code> variant.
385      * Called by the default implementation of the
386      * {@link #onSubmit(HttpServletRequest, HttpServletResponse, Object, BindException)}
387      * variant with all parameters.
388      * <p>The default implementation calls {@link #onSubmit(Object)}, using the
389      * returned ModelAndView if actually implemented in a subclass. Else, the
390      * default behavior will apply: rendering the success view with the command
391      * and Errors instance as model.
392      * <p>Subclasses can override this to provide custom submission handling that
393      * does not need request and response.
394      * <p>Call <code>errors.getModel()</code> to populate the ModelAndView model
395      * with the command and the Errors instance, under the specified command name,
396      * as expected by the "spring:bind" tag.
397      * @param command form object with request parameters bound onto it
398      * @param errors Errors instance without errors
399      * @return the prepared model and view
400      * @throws Exception in case of errors
401      * @see #onSubmit(HttpServletRequest, HttpServletResponse, Object, BindException)
402      * @see #onSubmit(Object)
403      * @see #setSuccessView
404      * @see org.springframework.validation.Errors
405      * @see org.springframework.validation.BindException#getModel
406      */

407     protected ModelAndView onSubmit(Object JavaDoc command, BindException errors) throws Exception JavaDoc {
408         ModelAndView mv = onSubmit(command);
409         if (mv != null) {
410             // simplest onSubmit variant implemented in custom subclass
411
return mv;
412         }
413         else {
414             // default behavior: render success view
415
if (getSuccessView() == null) {
416                 throw new ServletException JavaDoc("successView isn't set");
417             }
418             return new ModelAndView(getSuccessView(), errors.getModel());
419         }
420     }
421
422     /**
423      * Simplest <code>onSubmit</code> variant. Called by the default implementation
424      * of the {@link #onSubmit(Object, BindException)} variant.
425      * <p>This implementation calls {@link #doSubmitAction(Object)} and returns
426      * <code>null</code> as ModelAndView, making the calling <code>onSubmit</code>
427      * method perform its default rendering of the success view.
428      * <p>Subclasses can override this to provide custom submission handling
429      * that just depends on the command object. It's preferable to use either
430      * {@link #onSubmit(Object, BindException)} or {@link #doSubmitAction(Object)},
431      * though: Use the former when you want to build your own ModelAndView; use the
432      * latter when you want to perform an action and forward to the successView.
433      * @param command form object with request parameters bound onto it
434      * @return the prepared model and view, or <code>null</code> for default
435      * (that is, rendering the configured "successView")
436      * @throws Exception in case of errors
437      * @see #onSubmit(Object, BindException)
438      * @see #doSubmitAction
439      * @see #setSuccessView
440      */

441     protected ModelAndView onSubmit(Object JavaDoc command) throws Exception JavaDoc {
442         doSubmitAction(command);
443         return null;
444     }
445
446     /**
447      * Template method for submit actions. Called by the default implementation
448      * of the simplest {@link #onSubmit(Object)} variant.
449      * <p><b>This is the preferred submit callback to implement if you want to
450      * perform an action (like storing changes to the database) and then render
451      * the success view with the command and Errors instance as model.</b>
452      * You don't need to care about the success ModelAndView here.
453      * @param command form object with request parameters bound onto it
454      * @throws Exception in case of errors
455      * @see #onSubmit(Object)
456      * @see #setSuccessView
457      */

458     protected void doSubmitAction(Object JavaDoc command) throws Exception JavaDoc {
459     }
460
461 }
462
Popular Tags