⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 formaction.java

📁 spring的WEB开发插件,支持多状态WEB开发
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
/*
 * Copyright 2002-2005 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.webflow.action;

import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.binding.format.InvalidFormatException;
import org.springframework.binding.format.support.LabeledEnumFormatter;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.DataBinder;
import org.springframework.validation.Errors;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.PropertyEditorRegistrar;
import org.springframework.validation.Validator;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.webflow.Event;
import org.springframework.webflow.RequestContext;
import org.springframework.webflow.ScopeType;
import org.springframework.webflow.util.DispatchMethodInvoker;

/**
 * Multi-action that implements common logic dealing with input forms.
 * <p>
 * Several action execution methods are provided:
 * <ul>
 * <li> {@link #exposeFormObject(RequestContext)} - Loads the backing form object 
 * and exposes it and an empty errors instance in the model of the executing flow
 * in the correct scope.  Any custom property editors for formatting 
 * form object values will also be installed.  This action method will return success()
 * if the form object was loaded successfully, error() otherwise.
 * <li> {@link #setupForm(RequestContext)} - Prepares the backing form object for display
 * on a form.  This method behaves exactly like exposeFormObject but goes further 
 * by adding a capability to perform optional data binding on setup.  This action
 * method will return the success() event if there are no setup errors, otherwise it
 * will return the error() event.
 * </li>
 * <li> {@link #bindAndValidate(RequestContext)} - Binds all incoming event
 * parameters to the form object and validates the form object using a
 * registered validator. This action method will return the success()
 * event if there are no binding or validation errors, otherwise it will return
 * the error() event.
 * </li>
 * <li> {@link #bind(RequestContext)} - Binds all incoming event
 * parameters to the form object.  No additional validation is performed.
 * This action method will return the success() event if there are no binding
 * errors, otherwise it will return the error() event.
 * </li>
 * <li> {@link #validate(RequestContext)} - Validates the form object using a
 * registered validator. No data binding is performed.  This action method will
 * return the success() event if there are no validation errors, otherwise it
 * will return the error() event.
 * </li>
 * <li> {@link #resetForm(RequestContext)} - Resets the form by reloading
 * the backing form object and reinstalling any custom property editors.
 * Returns success() on completion, error() if a form object load failure occurs.
 * </li>
 * </ul>
 * <p>
 * Since this is a multi-action, a subclass could add any number of additional
 * action execution methods, e.g. "setupReferenceData(RequestContext)", or 
 * "processSubmit(RequestContext)".
 * <p>
 * Using this action, it becomes very easy to implement form preparation and
 * submission logic in your flow.  One way to do this follows:
 * <ol>
 * <li> Create an view state to display the form. In an entry action of that 
 * state, invoke {@link #setupForm(RequestContext) setupForm} to prepare the
 * new form for display. </li>
 * <li> On submit, execute a state transition action that performs a bindAndValidate.
 * This will invoke {@link #bindAndValidate(RequestContext) bindAndValidate} to
 * bind incoming event parameters to the form object and validate the form object.
 * <li>If there are binding or validation errors, the transition will not be allowed
 * and the view state will automatically be re-entered.
 * <li> If binding and validation is successful, go to an action state called
 * "processSubmit" (or any other appropriate name). This will invoke an action method
 * called "processSubmit" you must provide on a subclass to process form submission,
 * e.g. interacting with the business logic. </li>
 * <li> If business processing is ok, continue to a view state to display the
 * success view. </li>
 * </ol>
 * <p>
 * Here is an example implementation of such a compact form flow:
 * <pre>
 * &lt;view-state id="displayCriteria" view="searchCriteria"&gt;
 *     &lt;entry&gt;
 *         &lt;action bean="searchFormAction" method="setupForm"/&gt;
 *     &lt;/entry&gt;
 *     &lt;transition on="search" to="executeSearch"&gt;
 *         &lt;action bean="searchFormAction" method="bindAndValidate"/&gt;
 *     &lt;/transition&gt;
 * &lt;/view-state&gt;
 *
 * &lt;action-state id="executeSearch"&gt;
 *     &lt;action bean="searchFormAction"/&gt;
 *     &lt;transition on="success" to="displayResults"/&gt;
 * &lt;/action-state&gt;
 *</pre>
 * </p>
 * <p>
 * When you need additional flexibility, consider splitting the view state above 
 * acting as a single logical <i>form state</i> into multiple states.  For example,
 * you could have one action state handle form setup, a view state trigger
 * form display, another action state handle data binding and validation, and another
 * process form submission.  This would be a bit more verbose but would also give you
 * more control over how you respond to specific results of fine-grained actions that
 * occur within the flow.
 * <p>
 * <b>Subclassing hooks:</b>
 * <ul>
 * <li>An important hook method provided by this class is 
 * {@link #initBinder(RequestContext, DataBinder) initBinder}. This is 
 * called after a new data binder is created by any of the action execution methods.
 * It allows you to install any custom property editors required to format richly-typed 
 * form object property values.
 * <li>Another important hook is {@link #loadFormObject(RequestContext) loadFormObject}.
 * You may override this to customize where the backing form object comes from
 * (e.g instantiated directly in memory or loaded from a database).
 * </ul>
 * <p>
 * Note that this action does not provide a <i>referenceData()</i> hook method
 * similar to that of Spring MVC's <code>SimpleFormController</code>. If you need to
 * expose reference data to populate form drop downs for example, you should create
 * a custom action method in your FormAction subclass that does just that, and invoke it
 * as either a chained action as part of a form setup state, or as a fine grained state 
 * definition itself.
 * <p>
 * For example, you might create this method in your subclass:
 * <pre>
 *    public Event setupReferenceData(RequestContext context) throws Exception {
 *        Scope requestScope = context.getRequestScope();
 *        requestScope.setAttribute("refData", referenceDataDao.getSupportingFormData());
 *        return success();
 *    }
 * </pre>
 * <p>
 * <b>FormAction configurable properties</b><br>
 * <table border="1">
 * <tr>
 * <td><b>name</b></td>
 * <td><b>default</b></td>
 * <td><b>description</b></td>
 * </tr>
 * <tr>
 * <td>formObjectName</td>
 * <td>"formObject"</td>
 * <td>The name of the form object. The form object will be
 * set in the configured scope using this name. </td>
 * </tr>
 * <tr>
 * <td>formObjectClass</td>
 * <td>null</td>
 * <td>The form object class for this action. An instance of this class will
 * get populated and validated. </td>
 * </tr>
 * <tr>
 * <td>formObjectScope</td>
 * <td>{@link org.springframework.webflow.ScopeType#REQUEST request}</td>
 * <td>The scope in which the form object will be put. If put in flow scope the
 * object will be cached and reused over the life of the flow, preserving previous
 * values.  Request scope will cause a new fresh form object instance to be created
 * each execution.</td>
 * </tr>
 * <tr>
 * <td>errorsScope</td>
 * <td>{@link org.springframework.webflow.ScopeType#REQUEST request}</td>
 * <td>The scope in which the form object errors instance will be put.
 * If put in flow scope the errors will be cached and reused over the life
 * of the flow.  Request scope will cause a new errors instance to be created
 * each execution.</td>
 * </tr>
 * <tr>
 * <td>propertyEditorRegistrar</td>
 * <td>null</td>
 * <td>The strategy used to register custom property editors with the data
 * binder. This is an alternative to overriding the
 * {@link #initBinder(RequestContext, DataBinder) initBinder} hook method. </td>
 * </tr>
 * <tr>
 * <td>validator</td>
 * <td>null</td>
 * <td>The validator for this action. The validator must support the
 * specified form object class. </td>
 * </tr>
 * <tr>
 * <td>bindOnSetupForm</td>
 * <td>false</td>
 * <td>Set if request parameters should be bound to the form object during the
 * {@link #setupForm(RequestContext) setupForm} action. </td>
 * </tr>
 * <tr>
 * <td>validateOnBinding</td>
 * <td>true</td>
 * <td>Indicates if the validator should get applied when binding. </td>
 * </tr>
 * <tr>
 * <td>messageCodesResolver</td>
 * <td>null</td>
 * <td>Set the strategy to use for resolving errors into message codes. </td>
 * </tr>
 * </table>
 * 
 * @author Erwin Vervaet
 * @author Keith Donald
 */
public class FormAction extends MultiAction implements InitializingBean {

	/**
	 * Optional property that identifies the method that should be invoked on the 
	 * configured validator instance, to support piecemeal wizard page validation.
	 */
	public static final String VALIDATOR_METHOD_PROPERTY = "validatorMethod";
	
	/**
	 * The name the form object should be exposed under.
	 */
	private String formObjectName = "formObject";

	/**
	 * The type of form object -- typically a instantiable class. 
	 */
	private Class formObjectClass;

	/**
	 * The scope in which the form object should be exposed. 
	 */
	private ScopeType formObjectScope = ScopeType.REQUEST;

	/**
	 * The scope in which the form object errors holder should be exposed.
	 */
	private ScopeType formErrorsScope = ScopeType.REQUEST;

	/**
	 * A centralized service for property editor registration, for type conversion during
	 * form object data binding. 
	 */
	private PropertyEditorRegistrar propertyEditorRegistrar;

	/**
	 * A validator for the form's form object.
	 */
	private Validator validator;

	/**
	 * Should binding from event parameters happen on form setup?
	 */
	private boolean bindOnSetupForm = false;

	/**
	 * Should validation happen after data binding?
	 */
	private boolean validateOnBinding = true;

	/**
	 * Strategy for resolving error message codes.
	 */
	private MessageCodesResolver messageCodesResolver;

	/**
	 * A cache for dispatched action execute methods.
	 */
	private DispatchMethodInvoker validateMethodDispatcher = new DispatchMethodInvoker();

	/**
	 * Return the name of the form object in the configured scope.
	 */
	public String getFormObjectName() {
		return this.formObjectName;
	}

	/**
	 * Set the name of the form object in the configured scope. The form object
	 * will be included in the configured scope under this name.
	 */
	public void setFormObjectName(String formObjectName) {
		this.formObjectName = formObjectName;
	}

	/**
	 * Return the form object class for this action.
	 */
	public Class getFormObjectClass() {
		return this.formObjectClass;
	}

	/**
	 * Set the form object class for this action. An instance of this class will
	 * get populated and validated.
	 */
	public void setFormObjectClass(Class formObjectClass) {
		this.formObjectClass = formObjectClass;
		getValidateMethodDispatcher().setParameterTypes(new Class[] { this.formObjectClass, Errors.class });
	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -