Source Code Cross Referenced for AbstractFormController.java in  » J2EE » spring-framework-2.0.6 » org » springframework » web » servlet » mvc » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » J2EE » spring framework 2.0.6 » org.springframework.web.servlet.mvc 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Copyright 2002-2006 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:         *      http://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:
017:        package org.springframework.web.servlet.mvc;
018:
019:        import java.util.Map;
020:
021:        import javax.servlet.ServletException;
022:        import javax.servlet.http.HttpServletRequest;
023:        import javax.servlet.http.HttpServletResponse;
024:        import javax.servlet.http.HttpSession;
025:
026:        import org.springframework.validation.BindException;
027:        import org.springframework.validation.Errors;
028:        import org.springframework.web.HttpSessionRequiredException;
029:        import org.springframework.web.bind.ServletRequestDataBinder;
030:        import org.springframework.web.servlet.ModelAndView;
031:
032:        /**
033:         * <p>Form controller that auto-populates a form bean from the request.
034:         * This, either using a new bean instance per request, or using the same bean
035:         * when the <code>sessionForm</code> property has been set to <code>true</code>.</p>
036:         *
037:         * <p>This class is the base class for both framework subclasses like
038:         * {@link SimpleFormController SimpleFormController} and
039:         * {@link AbstractWizardFormController AbstractWizardFormController}, and
040:         * custom form controllers you can provide yourself.</p>
041:         *
042:         * <p>Both form-input views and after-submission views have to be provided
043:         * programmatically. To provide those views using configuration properties,
044:         * use the {@link SimpleFormController SimpleFormController}.</p>
045:         *
046:         * <p>Subclasses need to override <code>showForm</code> to prepare the form view,
047:         * and <code>processFormSubmission</code> to handle submit requests. For the latter,
048:         * binding errors like type mismatches will be reported via the given "errors" holder.
049:         * For additional custom form validation, a validator (property inherited from
050:         * BaseCommandController) can be used, reporting via the same "errors" instance.</p>
051:         *
052:         * <p>Comparing this Controller to the Struts notion of the <code>Action</code>
053:         * shows us that with Spring, you can use any ordinary JavaBeans or database-
054:         * backed JavaBeans without having to implement a framework-specific class
055:         * (like Struts' <code>ActionForm</code>). More complex properties of JavaBeans
056:         * (Dates, Locales, but also your own application-specific or compound types)
057:         * can be represented and submitted to the controller, by using the notion of
058:         * a <code>java.beans.PropertyEditor</code>. For more information on that
059:         * subject, see the workflow of this controller and the explanation of the
060:         * {@link BaseCommandController BaseCommandController}.</p>
061:         *
062:         * <p><b><a name="workflow">Workflow
063:         * (<a href="BaseCommandController.html#workflow">and that defined by superclass</a>):</b><br>
064:         * <ol>
065:         *  <li><b>The controller receives a request for a new form (typically a GET).</b></li>
066:         *  <li>Call to {@link #formBackingObject formBackingObject()} which by default,
067:         *      returns an instance of the commandClass that has been configured
068:         *      (see the properties the superclass exposes), but can also be overridden
069:         *      to e.g. retrieve an object from the database (that needs to be modified
070:         * using the form).</li>
071:         *  <li>Call to {@link #initBinder initBinder()} which allows you to register
072:         *      custom editors for certain fields (often properties of non-primitive
073:         *      or non-String types) of the command class. This will render appropriate
074:         *      Strings for those property values, e.g. locale-specific date strings.</li>
075:         *  <li><em>Only if <code>bindOnNewForm</code> is set to <code>true</code></em>, then
076:         *      {@link org.springframework.web.bind.ServletRequestDataBinder ServletRequestDataBinder}
077:         *      gets applied to populate the new form object with initial request parameters and the
078:         *      {@link #onBindOnNewForm(HttpServletRequest, Object, BindException)} callback method is
079:         *      called. <em>Note:</em> any defined Validators are not applied at this point, to allow
080:         *      partial binding. However be aware that any Binder customizations applied via 
081:         *      initBinder() (such as
082:         *      {@link org.springframework.validation.DataBinder#setRequiredFields(String[])} will
083:         *      still apply. As such, if using bindOnNewForm=true and initBinder() customizations are
084:         *      used to validate fields instead of using Validators, in the case that only some fields
085:         *      will be populated for the new form, there will potentially be some bind errors for
086:         *      missing fields in the errors object. Any view (JSP, etc.) that displays binder errors
087:         *      needs to be intelligent and for this case take into account whether it is displaying the
088:         *      initial form view or subsequent post results, skipping error display for the former.</li>
089:         *  <li>Call to {@link #showForm(HttpServletRequest, HttpServletResponse, BindException) showForm()}
090:         *      to return a View that should be rendered (typically the view that renders
091:         *      the form). This method has to be implemented in subclasses.</li>
092:         *  <li>The showForm() implementation will call {@link #referenceData referenceData()},
093:         *      which you can implement to provide any relevant reference data you might need
094:         *      when editing a form (e.g. a List of Locale objects you're going to let the
095:         *      user select one from).</li>
096:         *  <li>Model gets exposed and view gets rendered, to let the user fill in the form.</li>
097:         *  <li><b>The controller receives a form submission (typically a POST).</b>
098:         *      To use a different way of detecting a form submission, override the
099:         *      {@link #isFormSubmission isFormSubmission} method.
100:         *      </li>
101:         *  <li>If <code>sessionForm</code> is not set, {@link #formBackingObject formBackingObject()}
102:         *      is called to retrieve a form object. Otherwise, the controller tries to
103:         *      find the command object which is already bound in the session. If it cannot
104:         *      find the object, it does a call to {@link #handleInvalidSubmit handleInvalidSubmit}
105:         *      which - by default - tries to create a new form object and resubmit the form.</li>
106:         *  <li>The {@link org.springframework.web.bind.ServletRequestDataBinder ServletRequestDataBinder}
107:         *      gets applied to populate the form object with current request parameters.
108:         *  <li>Call to {@link #onBind onBind(HttpServletRequest, Object, Errors)} which allows
109:         *      you to do custom processing after binding but before validation (e.g. to manually
110:         *      bind request parameters to bean properties, to be seen by the Validator).</li>
111:         *  <li>If <code>validateOnBinding</code> is set, a registered Validator will be invoked.
112:         *      The Validator will check the form object properties, and register corresponding
113:         *      errors via the given {@link org.springframework.validation.Errors Errors}</li> object.
114:         *  <li>Call to {@link #onBindAndValidate onBindAndValidate()} which allows you
115:         *      to do custom processing after binding and validation (e.g. to manually
116:         *      bind request parameters, and to validate them outside a Validator).</li>
117:         *  <li>Call {@link #processFormSubmission(HttpServletRequest, HttpServletResponse,
118:         *      Object, BindException) processFormSubmission()} to process the submission, with
119:         *      or without binding errors. This method has to be implemented in subclasses.</li>
120:         * </ol>
121:         * </p>
122:         *
123:         * <p>In session form mode, a submission without an existing form object in the
124:         * session is considered invalid, like in case of a resubmit/reload by the browser.
125:         * The {@link #handleInvalidSubmit handleInvalidSubmit} method is invoked then,
126:         * by default trying to resubmit. It can be overridden in subclasses to show
127:         * corresponding messages or to redirect to a new form, in order to avoid duplicate
128:         * submissions. The form object in the session can be considered a transaction
129:         * token in that case.</p>
130:         *
131:         * <p>Note that views should never retrieve form beans from the session but always
132:         * from the request, as prepared by the form controller. Remember that some view
133:         * technologies like Velocity cannot even access a HTTP session.</p>
134:         *
135:         * <p><b><a name="config">Exposed configuration properties</a>
136:         * (<a href="BaseCommandController.html#config">and those defined by superclass</a>):</b><br>
137:         * <table border="1">
138:         *  <tr>
139:         *      <td><b>name</b></td>
140:         *      <td><b>default</b></td>
141:         *      <td><b>description</b></td>
142:         *  </tr>
143:         *  <tr>
144:         *      <td>bindOnNewForm</td>
145:         *      <td>false</td>
146:         *      <td>Indicates whether to bind servlet request parameters when
147:         *          creating a new form. Otherwise, the parameters will only be
148:         *          bound on form submission attempts.</td>
149:         *  </tr>
150:         *  <tr>
151:         *      <td>sessionForm</td>
152:         *      <td>false</td>
153:         *      <td>Indicates whether the form object should be kept in the session
154:         *          when a user asks for a new form. This allows you e.g. to retrieve
155:         *          an object from the database, let the user edit it, and then persist
156:         *          it again. Otherwise, a new command object will be created for each
157:         *          request (even when showing the form again after validation errors).</td>
158:         *  </tr>
159:         * </table>
160:         * </p>
161:         *
162:         * @author Rod Johnson
163:         * @author Juergen Hoeller
164:         * @author Alef Arendsen
165:         * @author Rob Harrop
166:         * @author Colin Sampaleanu
167:         * @see #showForm(HttpServletRequest, HttpServletResponse, BindException)
168:         * @see #processFormSubmission
169:         * @see SimpleFormController
170:         * @see AbstractWizardFormController
171:         */
172:        public abstract class AbstractFormController extends
173:                BaseCommandController {
174:
175:            private boolean bindOnNewForm = false;
176:
177:            private boolean sessionForm = false;
178:
179:            /**
180:             * Create a new AbstractFormController.
181:             * <p>Subclasses should set the following properties, either in the constructor
182:             * or via a BeanFactory: commandName, commandClass, bindOnNewForm, sessionForm.
183:             * Note that "commandClass" doesn't need to be set when overriding
184:             * {@link #formBackingObject}, since the latter determines the class anyway.
185:             * <p>"cacheSeconds" is by default set to 0 (-> no caching for all form controllers).
186:             * @see #setCommandName
187:             * @see #setCommandClass
188:             * @see #setBindOnNewForm
189:             * @see #setSessionForm
190:             * @see #formBackingObject
191:             */
192:            public AbstractFormController() {
193:                setCacheSeconds(0);
194:            }
195:
196:            /**
197:             * Set if request parameters should be bound to the form object
198:             * in case of a non-submitting request, i.e. a new form.
199:             */
200:            public final void setBindOnNewForm(boolean bindOnNewForm) {
201:                this .bindOnNewForm = bindOnNewForm;
202:            }
203:
204:            /**
205:             * Return if request parameters should be bound in case of a new form.
206:             */
207:            public final boolean isBindOnNewForm() {
208:                return bindOnNewForm;
209:            }
210:
211:            /**
212:             * Activate resp. deactivate session form mode. In session form mode,
213:             * the form is stored in the session to keep the form object instance
214:             * between requests, instead of creating a new one on each request.
215:             * <p>This is necessary for either wizard-style controllers that populate a
216:             * single form object from multiple pages, or forms that populate a persistent
217:             * object that needs to be identical to allow for tracking changes.
218:             */
219:            public final void setSessionForm(boolean sessionForm) {
220:                this .sessionForm = sessionForm;
221:            }
222:
223:            /**
224:             * Return if session form mode is activated.
225:             */
226:            public final boolean isSessionForm() {
227:                return sessionForm;
228:            }
229:
230:            /**
231:             * Handles two cases: form submissions and showing a new form.
232:             * Delegates the decision between the two to {@link #isFormSubmission},
233:             * always treating requests without existing form session attribute
234:             * as new form when using session form mode.
235:             * @see #isFormSubmission
236:             * @see #showNewForm
237:             * @see #processFormSubmission
238:             */
239:            protected ModelAndView handleRequestInternal(
240:                    HttpServletRequest request, HttpServletResponse response)
241:                    throws Exception {
242:
243:                // Form submission or new form to show?
244:                if (isFormSubmission(request)) {
245:                    // Fetch form object from HTTP session, bind, validate, process submission.
246:                    try {
247:                        Object command = getCommand(request);
248:                        ServletRequestDataBinder binder = bindAndValidate(
249:                                request, command);
250:                        BindException errors = new BindException(binder
251:                                .getBindingResult());
252:                        return processFormSubmission(request, response,
253:                                command, errors);
254:                    } catch (HttpSessionRequiredException ex) {
255:                        // Cannot submit a session form if no form object is in the session.
256:                        if (logger.isDebugEnabled()) {
257:                            logger.debug("Invalid submit detected: "
258:                                    + ex.getMessage());
259:                        }
260:                        return handleInvalidSubmit(request, response);
261:                    }
262:                }
263:
264:                else {
265:                    // New form to show: render form view.
266:                    return showNewForm(request, response);
267:                }
268:            }
269:
270:            /**
271:             * Determine if the given request represents a form submission.
272:             * <p>The default implementation treats a POST request as form submission.
273:             * Note: If the form session attribute doesn't exist when using session form
274:             * mode, the request is always treated as new form by handleRequestInternal.
275:             * <p>Subclasses can override this to use a custom strategy, e.g. a specific
276:             * request parameter (assumably a hidden field or submit button name).
277:             * @param request current HTTP request
278:             * @return if the request represents a form submission
279:             */
280:            protected boolean isFormSubmission(HttpServletRequest request) {
281:                return "POST".equals(request.getMethod());
282:            }
283:
284:            /**
285:             * Return the name of the HttpSession attribute that holds the form object
286:             * for this form controller.
287:             * <p>The default implementation delegates to the {@link #getFormSessionAttributeName()}
288:             * variant without arguments.
289:             * @param request current HTTP request
290:             * @return the name of the form session attribute, or <code>null</code> if not in session form mode
291:             * @see #getFormSessionAttributeName
292:             * @see javax.servlet.http.HttpSession#getAttribute
293:             */
294:            protected String getFormSessionAttributeName(
295:                    HttpServletRequest request) {
296:                return getFormSessionAttributeName();
297:            }
298:
299:            /**
300:             * Return the name of the HttpSession attribute that holds the form object
301:             * for this form controller.
302:             * <p>Default is an internal name, of no relevance to applications, as the form
303:             * session attribute is not usually accessed directly. Can be overridden to use
304:             * an application-specific attribute name, which allows other code to access
305:             * the session attribute directly.
306:             * @return the name of the form session attribute
307:             * @see javax.servlet.http.HttpSession#getAttribute
308:             */
309:            protected String getFormSessionAttributeName() {
310:                return getClass().getName() + ".FORM." + getCommandName();
311:            }
312:
313:            /**
314:             * Show a new form. Prepares a backing object for the current form
315:             * and the given request, including checking its validity.
316:             * @param request current HTTP request
317:             * @param response current HTTP response
318:             * @return the prepared form view
319:             * @throws Exception in case of an invalid new form object
320:             * @see #getErrorsForNewForm
321:             */
322:            protected final ModelAndView showNewForm(
323:                    HttpServletRequest request, HttpServletResponse response)
324:                    throws Exception {
325:
326:                logger.debug("Displaying new form");
327:                return showForm(request, response, getErrorsForNewForm(request));
328:            }
329:
330:            /**
331:             * Create a BindException instance for a new form.
332:             * Called by {@link #showNewForm}.
333:             * <p>Can be used directly when intending to show a new form but with
334:             * special errors registered on it (for example, on invalid submit).
335:             * Usually, the resulting BindException will be passed to
336:             * {@link #showForm(HttpServletRequest, HttpServletResponse, BindException)},
337:             * after registering the errors on it.
338:             * @param request current HTTP request
339:             * @return the BindException instance
340:             * @throws Exception in case of an invalid new form object
341:             * @see #showNewForm
342:             * @see #showForm(HttpServletRequest, HttpServletResponse, BindException)
343:             * @see #handleInvalidSubmit
344:             */
345:            protected final BindException getErrorsForNewForm(
346:                    HttpServletRequest request) throws Exception {
347:                // Create form-backing object for new form.
348:                Object command = formBackingObject(request);
349:                if (command == null) {
350:                    throw new ServletException(
351:                            "Form object returned by formBackingObject() must not be null");
352:                }
353:                if (!checkCommand(command)) {
354:                    throw new ServletException(
355:                            "Form object returned by formBackingObject() must match commandClass");
356:                }
357:
358:                // Bind without validation, to allow for prepopulating a form, and for
359:                // convenient error evaluation in views (on both first attempt and resubmit).
360:                ServletRequestDataBinder binder = createBinder(request, command);
361:                BindException errors = new BindException(binder
362:                        .getBindingResult());
363:                if (isBindOnNewForm()) {
364:                    logger.debug("Binding to new form");
365:                    binder.bind(request);
366:                    onBindOnNewForm(request, command, errors);
367:                }
368:
369:                // Return BindException object that resulted from binding.
370:                return errors;
371:            }
372:
373:            /**
374:             * Callback for custom post-processing in terms of binding for a new form.
375:             * Called when preparing a new form if <code>bindOnNewForm</code> is <code>true</code>.
376:             * <p>The default implementation delegates to <code>onBindOnNewForm(request, command)</code>.
377:             * @param request current HTTP request
378:             * @param command the command object to perform further binding on
379:             * @param errors validation errors holder, allowing for additional
380:             * custom registration of binding errors
381:             * @throws Exception in case of invalid state or arguments
382:             * @see #onBindOnNewForm(javax.servlet.http.HttpServletRequest, Object)
383:             * @see #setBindOnNewForm
384:             */
385:            protected void onBindOnNewForm(HttpServletRequest request,
386:                    Object command, BindException errors) throws Exception {
387:
388:                onBindOnNewForm(request, command);
389:            }
390:
391:            /**
392:             * Callback for custom post-processing in terms of binding for a new form.
393:             * <p>Called by the default implementation of the
394:             * {@link #onBindOnNewForm(HttpServletRequest, Object, BindException)} variant
395:             * with all parameters, after standard binding when displaying the form view.
396:             * Only called if <code>bindOnNewForm</code> is set to <code>true</code>.
397:             * <p>The default implementation is empty.
398:             * @param request current HTTP request
399:             * @param command the command object to perform further binding on
400:             * @throws Exception in case of invalid state or arguments
401:             * @see #onBindOnNewForm(HttpServletRequest, Object, BindException)
402:             * @see #setBindOnNewForm(boolean)
403:             */
404:            protected void onBindOnNewForm(HttpServletRequest request,
405:                    Object command) throws Exception {
406:            }
407:
408:            /**
409:             * Return the form object for the given request.
410:             * <p>Calls {@link #formBackingObject} if not in session form mode.
411:             * Else, retrieves the form object from the session. Note that the form object
412:             * gets removed from the session, but it will be re-added when showing the
413:             * form for resubmission.
414:             * @param request current HTTP request
415:             * @return object form to bind onto
416:             * @throws org.springframework.web.HttpSessionRequiredException
417:             * if a session was expected but no active session (or session form object) found
418:             * @throws Exception in case of invalid state or arguments
419:             * @see #formBackingObject
420:             */
421:            protected final Object getCommand(HttpServletRequest request)
422:                    throws Exception {
423:                // If not in session-form mode, create a new form-backing object.
424:                if (!isSessionForm()) {
425:                    return formBackingObject(request);
426:                }
427:
428:                // Session-form mode: retrieve form object from HTTP session attribute.
429:                HttpSession session = request.getSession(false);
430:                if (session == null) {
431:                    throw new HttpSessionRequiredException(
432:                            "Must have session when trying to bind (in session-form mode)");
433:                }
434:                String formAttrName = getFormSessionAttributeName(request);
435:                Object sessionFormObject = session.getAttribute(formAttrName);
436:                if (sessionFormObject == null) {
437:                    throw new HttpSessionRequiredException(
438:                            "Form object not found in session (in session-form mode)");
439:                }
440:
441:                // Remove form object from HTTP session: we might finish the form workflow
442:                // in this request. If it turns out that we need to show the form view again,
443:                // we'll re-bind the form object to the HTTP session.
444:                if (logger.isDebugEnabled()) {
445:                    logger.debug("Removing form session attribute ["
446:                            + formAttrName + "]");
447:                }
448:                session.removeAttribute(formAttrName);
449:
450:                return currentFormObject(request, sessionFormObject);
451:            }
452:
453:            /**
454:             * Retrieve a backing object for the current form from the given request.
455:             * <p>The properties of the form object will correspond to the form field values
456:             * in your form view. This object will be exposed in the model under the specified
457:             * command name, to be accessed under that name in the view: for example, with
458:             * a "spring:bind" tag. The default command name is "command".
459:             * <p>Note that you need to activate session form mode to reuse the form-backing
460:             * object across the entire form workflow. Else, a new instance of the command
461:             * class will be created for each submission attempt, just using this backing
462:             * object as template for the initial form.
463:             * <p>The default implementation calls {@link #createCommand()},
464:             * creating a new empty instance of the specified command class.
465:             * Subclasses can override this to provide a preinitialized backing object.
466:             * @param request current HTTP request
467:             * @return the backing object
468:             * @throws Exception in case of invalid state or arguments
469:             * @see #setCommandName
470:             * @see #setCommandClass
471:             * @see #createCommand
472:             */
473:            protected Object formBackingObject(HttpServletRequest request)
474:                    throws Exception {
475:                return createCommand();
476:            }
477:
478:            /**
479:             * Return the current form object to use for binding and further processing,
480:             * based on the passed-in form object as found in the HttpSession.
481:             * <p>The default implementation simply returns the session form object as-is.
482:             * Subclasses can override this to post-process the session form object,
483:             * for example reattaching it to a persistence manager.
484:             * @param sessionFormObject the form object retrieved from the HttpSession
485:             * @return the form object to use for binding and further processing
486:             * @throws Exception in case of invalid state or arguments
487:             */
488:            protected Object currentFormObject(HttpServletRequest request,
489:                    Object sessionFormObject) throws Exception {
490:                return sessionFormObject;
491:            }
492:
493:            /**
494:             * Prepare the form model and view, including reference and error data.
495:             * Can show a configured form page, or generate a form view programmatically.
496:             * <p>A typical implementation will call
497:             * <code>showForm(request, errors, "myView")</code>
498:             * to prepare the form view for a specific view name, returning the
499:             * ModelAndView provided there.
500:             * <p>For building a custom ModelAndView, call <code>errors.getModel()</code>
501:             * to populate the ModelAndView model with the command and the Errors instance,
502:             * under the specified command name, as expected by the "spring:bind" tag.
503:             * You also need to include the model returned by {@link #referenceData}.
504:             * <p>Note: If you decide to have a "formView" property specifying the
505:             * view name, consider using SimpleFormController.
506:             * @param request current HTTP request
507:             * @param response current HTTP response
508:             * @param errors validation errors holder
509:             * @return the prepared form view, or <code>null</code> if handled directly
510:             * @throws Exception in case of invalid state or arguments
511:             * @see #showForm(HttpServletRequest, BindException, String)
512:             * @see org.springframework.validation.Errors
513:             * @see org.springframework.validation.BindException#getModel
514:             * @see #referenceData(HttpServletRequest, Object, Errors)
515:             * @see SimpleFormController#setFormView
516:             */
517:            protected abstract ModelAndView showForm(
518:                    HttpServletRequest request, HttpServletResponse response,
519:                    BindException errors) throws Exception;
520:
521:            /**
522:             * Prepare model and view for the given form, including reference and errors.
523:             * <p>In session form mode: Re-puts the form object in the session when
524:             * returning to the form, as it has been removed by getCommand.
525:             * <p>Can be used in subclasses to redirect back to a specific form page.
526:             * @param request current HTTP request
527:             * @param errors validation errors holder
528:             * @param viewName name of the form view
529:             * @return the prepared form view
530:             * @throws Exception in case of invalid state or arguments
531:             */
532:            protected final ModelAndView showForm(HttpServletRequest request,
533:                    BindException errors, String viewName) throws Exception {
534:
535:                return showForm(request, errors, viewName, null);
536:            }
537:
538:            /**
539:             * Prepare model and view for the given form, including reference and errors,
540:             * adding a controller-specific control model.
541:             * <p>In session form mode: Re-puts the form object in the session when returning
542:             * to the form, as it has been removed by getCommand.
543:             * <p>Can be used in subclasses to redirect back to a specific form page.
544:             * @param request current HTTP request
545:             * @param errors validation errors holder
546:             * @param viewName name of the form view
547:             * @param controlModel model map containing controller-specific control data
548:             * (e.g. current page in wizard-style controllers or special error message)
549:             * @return the prepared form view
550:             * @throws Exception in case of invalid state or arguments
551:             */
552:            protected final ModelAndView showForm(HttpServletRequest request,
553:                    BindException errors, String viewName, Map controlModel)
554:                    throws Exception {
555:
556:                // In session form mode, re-expose form object as HTTP session attribute.
557:                // Re-binding is necessary for proper state handling in a cluster,
558:                // to notify other nodes of changes in the form object.
559:                if (isSessionForm()) {
560:                    String formAttrName = getFormSessionAttributeName(request);
561:                    if (logger.isDebugEnabled()) {
562:                        logger.debug("Setting form session attribute ["
563:                                + formAttrName + "] to: " + errors.getTarget());
564:                    }
565:                    request.getSession().setAttribute(formAttrName,
566:                            errors.getTarget());
567:                }
568:
569:                // Fetch errors model as starting point, containing form object under
570:                // "commandName", and corresponding Errors instance under internal key.
571:                Map model = errors.getModel();
572:
573:                // Merge reference data into model, if any.
574:                Map referenceData = referenceData(request, errors.getTarget(),
575:                        errors);
576:                if (referenceData != null) {
577:                    model.putAll(referenceData);
578:                }
579:
580:                // Merge control attributes into model, if any.
581:                if (controlModel != null) {
582:                    model.putAll(controlModel);
583:                }
584:
585:                // Trigger rendering of the specified view, using the final model.
586:                return new ModelAndView(viewName, model);
587:            }
588:
589:            /**
590:             * Create a reference data map for the given request, consisting of
591:             * bean name/bean instance pairs as expected by ModelAndView.
592:             * <p>The default implementation returns <code>null</code>.
593:             * Subclasses can override this to set reference data used in the view.
594:             * @param request current HTTP request
595:             * @param command form object with request parameters bound onto it
596:             * @param errors validation errors holder
597:             * @return a Map with reference data entries, or <code>null</code> if none
598:             * @throws Exception in case of invalid state or arguments
599:             * @see ModelAndView
600:             */
601:            protected Map referenceData(HttpServletRequest request,
602:                    Object command, Errors errors) throws Exception {
603:                return null;
604:            }
605:
606:            /**
607:             * Process form submission request. Called by {@link #handleRequestInternal}
608:             * in case of a form submission, with or without binding errors. Implementations
609:             * need to proceed properly, typically showing a form view in case of binding
610:             * errors or performing a submit action else.
611:             * <p>Subclasses can implement this to provide custom submission handling like
612:             * triggering a custom action. They can also provide custom validation and call
613:             * {@link #showForm(HttpServletRequest, HttpServletResponse, BindException)}
614:             * or proceed with the submission accordingly.
615:             * <p>For a success view, call <code>errors.getModel()</code> to populate the
616:             * ModelAndView model with the command and the Errors instance, under the
617:             * specified command name, as expected by the "spring:bind" tag. For a form view,
618:             * simply return the ModelAndView object provided by
619:             * {@link #showForm(HttpServletRequest, HttpServletResponse, BindException)}.
620:             * @param request current servlet request
621:             * @param response current servlet response
622:             * @param command form object with request parameters bound onto it
623:             * @param errors holder without errors (subclass can add errors if it wants to)
624:             * @return the prepared model and view, or <code>null</code>
625:             * @throws Exception in case of errors
626:             * @see #handleRequestInternal
627:             * @see #isFormSubmission
628:             * @see #showForm(HttpServletRequest, HttpServletResponse, BindException)
629:             * @see org.springframework.validation.Errors
630:             * @see org.springframework.validation.BindException#getModel
631:             */
632:            protected abstract ModelAndView processFormSubmission(
633:                    HttpServletRequest request, HttpServletResponse response,
634:                    Object command, BindException errors) throws Exception;
635:
636:            /**
637:             * Handle an invalid submit request, e.g. when in session form mode but no form object
638:             * was found in the session (like in case of an invalid resubmit by the browser).
639:             * <p>The default implementation simply tries to resubmit the form with a new
640:             * form object. This should also work if the user hit the back button, changed
641:             * some form data, and resubmitted the form.
642:             * <p>Note: To avoid duplicate submissions, you need to override this method.
643:             * Either show some "invalid submit" message, or call {@link #showNewForm} for
644:             * resetting the form (prepopulating it with the current values if "bindOnNewForm"
645:             * is true). In this case, the form object in the session serves as transaction token.
646:             * <pre>
647:             * protected ModelAndView handleInvalidSubmit(HttpServletRequest request, HttpServletResponse response) throws Exception {
648:             *   return showNewForm(request, response);
649:             * }</pre>
650:             * You can also show a new form but with special errors registered on it:
651:             * <pre>
652:             * protected ModelAndView handleInvalidSubmit(HttpServletRequest request, HttpServletResponse response) throws Exception {
653:             *   BindException errors = getErrorsForNewForm(request);
654:             *   errors.reject("duplicateFormSubmission", "Duplicate form submission");
655:             *   return showForm(request, response, errors);
656:             * }</pre>
657:             * @param request current HTTP request
658:             * @param response current HTTP response
659:             * @return a prepared view, or <code>null</code> if handled directly
660:             * @throws Exception in case of errors
661:             * @see #showNewForm
662:             * @see #getErrorsForNewForm
663:             * @see #showForm(HttpServletRequest, HttpServletResponse, BindException)
664:             * @see #setBindOnNewForm
665:             */
666:            protected ModelAndView handleInvalidSubmit(
667:                    HttpServletRequest request, HttpServletResponse response)
668:                    throws Exception {
669:
670:                Object command = formBackingObject(request);
671:                ServletRequestDataBinder binder = bindAndValidate(request,
672:                        command);
673:                BindException errors = new BindException(binder
674:                        .getBindingResult());
675:                return processFormSubmission(request, response, command, errors);
676:            }
677:
678:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.