| <?xml version="1.0"?> |
| <document url="./building_controller.xml"> |
| |
| <properties> |
| <author>Craig R. McClanahan</author> |
| <author>Mike Schachter</author> |
| <author>Ted Husted</author> |
| <author>Martin Cooper</author> |
| <author>Ed Burns</author> |
| <title>The Struts User's Guide - Building Controller Components</title> |
| </properties> |
| |
| <body> |
| <chapter name="4. Building Controller Components" href="building_controller"> |
| |
| <section name="4.1 Overview" href="overview"> |
| |
| <p> |
| Now that we understand how to construct the Model and View components |
| of your application, it is time to focus on the <code>Controller</code> |
| components. Struts includes a servlet that implements the primary function |
| of mapping a request URI to an <code>Action</code> class. Therefore, your |
| primary responsibilities related to the Controller are: |
| </p> |
| |
| <ul> |
| <li>Write an <code>Action</code> class for each logical request that may |
| be received (extend <code>org.apache.action.Action</code>).</li> |
| <li>Configure a ActionMapping (in XML) for each logical request that may |
| be submitted. The XML configuration file is usually named |
| <code>struts-config.xml</code>.</li> |
| <li>Update the web application deployment descriptor file (in XML) |
| for your application to include the necessary Struts components.</li> |
| <li>Add the appropriate Struts components to your application.</li> |
| </ul> |
| </section> |
| |
| <section name="4.2 Action Classes" href="action_classes"> |
| |
| <p>The <code>Action</code> class defines two methods that could be |
| executed depending on your servlet environment: |
| </p> |
| |
| <pre> |
| public ActionForward perform(ActionMapping mapping, |
| ActionForm form, |
| ServletRequest request, |
| ServletResponse response) |
| throws IOException, ServletException; |
| |
| public ActionForward perform(ActionMapping mapping, |
| ActionForm form, |
| HttpServletRequest request, |
| HttpServletResponse response) |
| throws IOException, ServletException; |
| </pre> |
| |
| <p> |
| Most projects would only use the "HttpServletRequest" version. |
| </p> |
| <p> |
| The goal of an <code>Action</code> class is to process a request, via |
| its <code>perform()</code> method, and return an <code>ActionForward</code> object |
| that identifies where control should be forwarded (e.g. a JSP) to provide |
| the appropriate response. In the <i>MVC/Model 2</i> design pattern, |
| a typical <code>Action</code> class will often implement logic like the following |
| in its <code>perform()</code> method: |
| </p> |
| <ul> |
| <li>Validate the current state of the user's session (for example, checking |
| that the user has successfully logged on). If the <code>Action</code> |
| class finds that no logon exists, the request can be forwarded to |
| the JSP page that displays the username and password prompts for |
| logging on. This could occur because a user tried to enter an |
| application "in the middle" (say, from a bookmark), or because the |
| session has timed out, and the servlet container created a new one.</li> |
| <li>If validation is not complete, |
| validate the form bean properties as needed. If a problem is found, |
| store the appropriate error message keys as a request attribute, and |
| forward control back to the input form so that the errors can be |
| corrected.</li> |
| <li>Perform the processing required to deal with this request (such as |
| saving a row into a database). This can be done by logic code embedded within |
| the <code>Action</code> class itself, but should generally be performed |
| by calling an appropriate method of a business logic bean.</li> |
| <li>Update the server-side objects that will be used to create the next |
| page of the user interface (typically request scope or session scope |
| beans, depending on how long you need to keep these items available).</li> |
| <li>Return an appropriate <code>ActionForward</code> object that identifies |
| the JSP page to be used to generate this response, based on the newly |
| updated beans. Typically, you will acquire a reference to such an |
| object by calling <code>findForward()</code> on either the |
| <code>ActionMapping</code> object you received (if you are using a |
| logical name local to this mapping), or on the controller servlet |
| itself (if you are using a logical name global to the application).</li> |
| </ul> |
| |
| <p> |
| Design issues to remember when coding <code>Action</code> classes |
| include the following: |
| </p> |
| |
| <ul> |
| <li>The controller servlet creates only one instance of your |
| <code>Action</code> class, and uses it for all requests. Thus, |
| you need to code your <code>Action</code> class so that it operates |
| correctly in a multi-threaded environment, just as you must code a |
| servlet's <code>service()</code> method safely.</li> |
| <li>The most important principle that aids in thread-safe coding is to |
| use only local variables, not instance variables, in your |
| <code>Action</code> class. Local variables are created on a |
| stack that is assigned (by your JVM) to each request thread, so |
| there is no need to worry about sharing them.</li> |
| <li>The beans that represent the Model of your system may throw exceptions |
| due to problems accessing databases or other resources. |
| You should trap all such exceptions |
| in the logic of your <code>perform()</code> method, and log them to the |
| application logfile (along with the corresponding stack trace) by |
| calling:<br /> |
| <code>servlet.log("Error message text", exception);</code></li> |
| <li>As a general rule, allocating scarce resources and keeping them across |
| requests from the same user (in the user's session) can cause |
| scalability problems. You should strive to release such resources |
| (such as database connections) prior to forwarding control to the |
| appropriate View component -- even if a bean method you have called |
| throws an exception.</li> |
| </ul> |
| |
| <p> |
| In addition, you will want to guard against <code>Action</code> classes |
| that are too large. The easiest way for this to happen is to embed your |
| functional logic in the <code>Action</code> class itself, rather than |
| coding it in separate business logic beans. Besides making the |
| <code>Action</code> class itself hard to understand and maintain, this |
| approach also makes it harder to re-use the business logic code, because |
| it is embedded inside a component (the <code>Action</code> class) that |
| is tied to being executed in a web application environment. |
| </p> |
| |
| <p> |
| An <code>Action</code> can be factored into several local methods, so long as all |
| properties needed are passed in the method signatures. The JVM |
| handles such properties using the stack, and so they are thread-safe. |
| </p> |
| |
| <p> |
| The example application included with Struts stretches this design |
| principle somewhat, because the business logic itself is embedded in the |
| <code>Action</code> classes. This should be considered something of a |
| bug in the design of the sample application, rather than an intrinsic |
| feature of the Struts architecture, or an approach to be emulated. |
| </p> |
| </section> |
| |
| <section name="4.3 The ActionMapping Implementation" href="actionmapping"> |
| |
| <p> |
| In order to operate successfully, the Struts controller servlet needs |
| to know several things about how each request URI should be mapped to an |
| appropriate <code>Action</code> class. The required knowledge has been |
| encapsulated in a Java interface named <code>ActionMapping</code>, the most |
| important properties are as follows: |
| </p> |
| |
| <ul> |
| <li><b>type</b> - Fully qualified Java class name of the |
| <code>Action</code> implementation class used by this mapping.</li> |
| <li><b>name</b> - The name of the form bean defined in the config file |
| that this action will use</li> |
| <li><b>path</b> - The request URI path that is matched to select this |
| mapping. See below for examples of how matching works.</li> |
| <li><b>unknown</b> - Set to <code>true</code> if this action |
| should be configured as the default for this application, to handle |
| all requests not handled by another action. Only one action can be |
| defined as a default within a single application.</li> |
| <li><b>validate</b> - Set to <code>true</code> if the |
| <code>validate()</code> method of the action associated |
| with this mapping should be called.</li> |
| <li><b>forward</b> - The request URI path to which control is passed |
| when his mapping is invoked. This is an alternative to declaring |
| a <b>type</b> property. </li> |
| |
| </ul> |
| |
| </section> |
| |
| <section name="4.4 The Action Mappings Configuration File" href="config"> |
| |
| <p> |
| How does the controller servlet learn about the mappings you want? It |
| would be possible (but tedious) to write a small Java class that simply |
| instantiated new <code>ActionMapping</code> instances, and called all of |
| the appropriate setter methods. To make this process easier, Struts includes |
| a Digester module that is capable of reading an XML-based description of |
| the desired mappings, creating the appropriate objects along the way. |
| See the <a href="../api/index.html">API documentation</a> for more information |
| about Digester. |
| </p> |
| |
| <p> |
| The developer's responsibility is to create an XML file named |
| <code>struts-config.xml</code>, and place it in the WEB-INF directory of your |
| application. This format of this document is constrained by it's definition in |
| "struts-config_1_0.dtd". The outermost XML element must be <code><struts-config></code>. |
| </p> |
| |
| <p> |
| Inside of the <struts-config> element, there are two important |
| elements that are used to describe your actions: |
| |
| <blockquote> |
| <b><form-beans></b><br /> |
| This section contains your form bean definitions. You use a <form-bean> element |
| for each form bean, which has the following important attributes: |
| <ul> |
| <li> |
| <b>name</b>: A unique identifier for this bean, which will be used |
| to reference it in corresponding action mappings. Usually, this |
| is also the name of the request or session attribute under which |
| this form bean will be stored. |
| </li> |
| <li> |
| <b>type</b>: The fully-qualified Java classname of your form bean. |
| </li> |
| </ul> |
| </blockquote> |
| <blockquote> |
| <b><action-mappings></b><br /> |
| This section contains your action definitions. You use an <action> element |
| for each of your actions you would like to define. Each action element requires |
| the following attributes to be defined: |
| |
| <ul> |
| <li> |
| <b>path</b>: The application context-relative path to the action |
| </li> |
| <li> |
| <b>type</b>: The fully qualified java classname of your Action class |
| </li> |
| <li> |
| <b>name</b>: The name of your <form-bean> element to use with this action |
| </li> |
| </ul> |
| </blockquote> |
| |
| </p> |
| |
| |
| <p> |
| The <code>struts-config.xml</code> file from the example application includes |
| the following mapping entry for the "log on" function, which we will use |
| to illustrate the requirements. Note that the entries for all the other actions |
| are left out: |
| </p> |
| |
| <pre> |
| <struts-config> |
| <form-beans> |
| <form-bean |
| name="logonForm" |
| type="org.apache.struts.example.LogonForm" /> |
| </form-beans> |
| <global-forwards |
| type="org.apache.struts.action.ActionForward" /> |
| <forward name="logon" path="/logon.jsp" |
| redirect="false" /> |
| </global-forwards> |
| <action-mappings> |
| <action |
| path="/logon" |
| type="org.apache.struts.example.LogonAction" |
| name="logonForm" |
| scope="request" |
| input="/logon.jsp" |
| unknown="false" |
| validate="true" /> |
| </action-mappings> |
| </struts-config> |
| </pre> |
| |
| <p> |
| First the form bean is defined. A basic bean of class "<code>org.apache.struts.example.LogonForm</code>" |
| is mapped to the logical name "<code>logonForm</code>". This name is used as a session or request attribute |
| name for the form bean. |
| </p> |
| <p> |
| The "<code>global-forwards</code>" section is used to create logical name mappings for commonly used |
| jsp pages. Each of these forwards is available through a call to your action mapping instance, |
| i.e. <code>actionMappingInstace.findForward("logicalName")</code>. |
| </p> |
| <p> |
| As you can see, this mapping matches the path <code>/logon</code> (actually, |
| because the example application uses extension mapping, the request URI you |
| specify in a JSP page would end in <code>/logon.do</code>). When a request |
| that matches this path is received, an instance of the <code>LogonAction</code> |
| class will be created (the first time only) and used. The controller servlet |
| will look for a session scoped bean under key <code>logonForm</code>, creating |
| and saving a bean of the specified class if needed. |
| </p> |
| <p> |
| Optional but very useful are the local "<code>forward</code>" elements. In the example |
| application, many actions include a local "success" and/or "failure" forward as |
| part of an Action mapping. |
| </p> |
| <pre> |
| <!-- Edit mail subscription --> |
| <action path="/editSubscription" |
| type="org.apache.struts.example.EditSubscriptionAction" |
| name="subscriptionForm" |
| scope="request" |
| validate="false"> |
| <forward name="failure" path="/mainMenu.jsp"/> |
| <forward name="success" path="/subscription.jsp"/> |
| </action> |
| </pre> |
| |
| <p>Using just these two extra properties, the <code>Action</code> classes in the example |
| application are almost totally independent of the actual names of the JSP pages |
| that are used by the page designers. The pages can be renamed (for example) during |
| a redesign, with negligible impact on the <code>Action</code> classes themselves. |
| If the names of the "next" JSP pages were hard coded into the <code>Action</code> |
| classes, all of these classes would also need to be modified. Of course, you can define |
| whatever local forward properties makes sense for your own application. |
| </p> |
| |
| <p> |
| One more section of good use is the <code><data-sources></code> section, which |
| specifies data sources that your application can use.This is how you would specify a basic data source for your application inside |
| of struts-config.xml: |
| </p> |
| |
| <pre> |
| <struts-config> |
| <data-sources> |
| <data-source |
| autoCommit="false" |
| description="Example Data Source Description" |
| driverClass="org.postgresql.Driver" |
| maxCount="4" |
| minCount="2" |
| password="mypassword" |
| url="jdbc:postgresql://localhost/mydatabase" |
| user="myusername"/> |
| </data-sources> |
| </struts-config> |
| </pre> |
| |
| <p> |
| For information on how to retrieve the data source, see the |
| <a href="building_model.html#databases">Accessing Relational Databases</a> section. |
| </p> |
| </section> |
| |
| <section name="4.5 The Web Application Deployment Descriptor" href="dd_config"> |
| |
| <p> |
| The final step in setting up the application is to configure the application |
| deployment descriptor (stored in file <code>WEB-INF/web.xml</code>) to include |
| all the Struts components that are required. Using the deployment descriptor |
| for the example application as a guide, we see that the following entries need |
| to be created or modified. |
| </p> |
| |
| <section name="4.5.1 Configure the Action Servlet Instance" href="dd_config_servlet"> |
| |
| <p> |
| Add an entry defining the action servlet itself, along with the appropriate |
| initialization parameters. Such an entry might look like this: |
| </p> |
| |
| <pre> |
| <servlet> |
| <servlet-name>action</servlet-name> |
| <servlet-class> |
| org.apache.struts.action.ActionServlet |
| </servlet-class> |
| <init-param> |
| <param-name>application</param-name> |
| <param-value> |
| org.apache.struts.example.ApplicationResources |
| </param-value> |
| </init-param> |
| <init-param> |
| <param-name>config</param-name> |
| <param-value> |
| /WEB-INF/struts-config.xml |
| </param-value> |
| </init-param> |
| <init-param> |
| <param-name>debug</param-name> |
| <param-value>2</param-value> |
| </init-param> |
| <init-param> |
| <param-name>mapping</param-name> |
| <param-value> |
| org.apache.struts.example.ApplicationMapping |
| </param-value> |
| </init-param> |
| <load-on-startup>2</load-on-startup> |
| </servlet> |
| </pre> |
| |
| <p> |
| The initialization parameters supported by the controller servlet are |
| described below. (You can also find these details in the <a |
| href="../api/index.html">Javadocs</a> for the ActionServlet class.) Square brackets |
| describe the default values that are assumed if you do not provide a value for |
| that initialization parameter. |
| </p> |
| <ul> |
| |
| <li><strong>application</strong> - Java class name of the application |
| resources bundle base class. [NONE]</li> |
| <li><strong>bufferSize</strong> - The size of the input buffer used when |
| processing file uploads. [4096]</li> |
| <li><strong>config</strong> - Context-relative path to the XML resource |
| containing our configuration information. |
| [/WEB-INF/struts-config.xml]</li> |
| <li><strong>content</strong> - Default content type and character encoding |
| to be set on each response; may be overridden by a forwarded-to |
| servlet or JSP page. [text/html]</li> |
| <li><strong>debug</strong> - The debugging detail level for this |
| servlet, which controls how much information is logged. [0]</li> |
| <li><strong>detail</strong> - The debugging detail level for the Digester |
| we utilize in <code>initMapping()</code>, which logs to System.out |
| instead of the servlet log. [0]</li> |
| <li><strong>factory</strong> - The Java class name of the |
| <code>MessageResourcesFactory</code> used to create the application |
| <code>MessageResources</code> object. |
| [org.apache.struts.util.PropertyMessageResourcesFactory]</li> |
| <li><strong>formBean</strong> - The Java class name of the ActionFormBean |
| implementation to use [org.apache.struts.action.ActionFormBean].</li> |
| <li><strong>forward</strong> - The Java class name of the ActionForward |
| implementation to use [org.apache.struts.action.ActionForward]. |
| Two convenient classes you may wish to use are: |
| <ul> |
| <li><em>org.apache.struts.action.ForwardingActionForward</em> - |
| Subclass of <code>org.apache.struts.action.ActionForward</code> |
| that defaults the <code>redirect</code> property to |
| <code>false</code> (same as the ActionForward default value).</li> |
| <li><em>org.apache.struts.action.RedirectingActionForward</em> - |
| Subclass of <code>org.apache.struts.action.ActionForward</code> |
| that defaults the <code>redirect</code> property to |
| <code>true</code>.</li> |
| </ul></li> |
| <li><strong>locale</strong> - If set to <code>true</code>, and there is a |
| user session, identify and store an appropriate |
| <code>java.util.Locale</code> object (under the standard key |
| identified by <code>Action.LOCALE_KEY</code>) in the user's session |
| if there is not a Locale object there already. [true]</li> |
| <li><strong>mapping</strong> - The Java class name of the ActionMapping |
| implementation to use [org.apache.struts.action.ActionMapping]. |
| Two convenient classes you may wish to use are: |
| <ul> |
| <li><em>org.apache.struts.action.RequestActionMapping</em> - Subclass |
| of <code>org.apache.struts.action.ActionMapping</code> that |
| defaults the <code>scope</code> property to "request".</li> |
| <li><em>org.apache.struts.action.SessionActionMapping</em> - Subclass |
| of <code>org.apache.struts.action.ActionMapping</code> that |
| defaults the <code>scope</code> property to "session". (Same |
| as the ActionMapping default value).</li> |
| </ul></li> |
| <li><strong>maxFileSize</strong> - The maximum size (in bytes) of a file |
| to be accepted as a file upload. Can be expressed as a number followed |
| by a "K" "M", or "G", which are interpreted to mean kilobytes, |
| megabytes, or gigabytes, respectively. [250M]</li> |
| <li><strong>multipartClass</strong> - The fully qualified name of the |
| MultipartRequestHandler implementation class to be used for processing |
| file uploads. [org.apache.struts.upload.DiskMultipartRequestHandler] |
| </li> |
| <li><strong>nocache</strong> - If set to <code>true</code>, add HTTP headers |
| to every response intended to defeat browser caching of any response we |
| generate or forward to. [false]</li> |
| <li><strong>null</strong> - If set to <code>true</code>, set our application |
| resources to return <code>null</code> if an unknown message key is used. |
| Otherwise, an error message including the offending message key will |
| be returned. [true]</li> |
| <li><strong>tempDir</strong> - The temporary working directory to use when |
| processing file uploads. [The working directory provided to this web |
| application as a servlet context attribute]</li> |
| <li><strong>validate</strong> - Are we using the new configuration file |
| format? [true]</li> |
| <li><strong>validating</strong> - Should we use a validating XML parse to |
| process the configuration file (strongly recommended)? [true]</li> |
| </ul> |
| </section> |
| |
| <section name="4.5.2 Configure the Action Servlet Mapping" href="dd_config_mapping"> |
| |
| <p> |
| <strong>Note:</strong> The material in this section is not specific to |
| Struts. The configuration of servlet mappings is defined in the Java |
| Servlet Specification. This section describes the most common means |
| of configuring a Struts application. |
| </p> |
| <p> |
| There are two common approaches to defining the URLs that will |
| be processed by the controller servlet -- prefix matching and extension |
| matching. An appropriate mapping entry for each approach will be |
| described below. |
| </p> |
| |
| <p> |
| Prefix matching means that you want all URLs that start (after the context |
| path part) with a particular value to be passed to this servlet. Such an |
| entry might look like this: |
| </p> |
| |
| <pre> |
| <servlet-mapping> |
| <servlet-name>action</servlet-name> |
| <url-pattern>/execute/*</url-pattern> |
| </servlet-mapping> |
| </pre> |
| |
| <p> |
| which means that a request URI to match the <code>/logon</code> path |
| described earlier might look like this:</p> |
| |
| <pre> |
| http://www.mycompany.com/myapplication/execute/logon |
| </pre> |
| |
| <p> |
| where <code>/myapplication</code> is the context path under which your |
| application is deployed. |
| </p> |
| |
| <p> |
| Extension mapping, on the other hand, matches request URIs to the action |
| servlet based on the fact that the URI ends with a period followed by a |
| defined set of characters. For example, the JSP processing servlet is mapped |
| to the <code>*.jsp</code> pattern so that it is called to process every |
| JSP page that is requested. To use the <code>*.do</code> extension (which |
| implies "do something"), the mapping entry would look like this: |
| </p> |
| |
| <pre> |
| <servlet-mapping> |
| <servlet-name>action</servlet-name> |
| <url-pattern>*.do</url-pattern> |
| </servlet-mapping> |
| </pre> |
| |
| <p> |
| and a request URI to match the <code>/logon</code> path described |
| earlier might look like this: |
| </p> |
| |
| <pre> |
| http://www.mycompany.com/myapplication/logon.do |
| </pre> |
| </section> |
| |
| <section name="4.5.3 Configure the Struts Tag Library" href="dd_config_taglib"> |
| |
| <p> |
| Next, you must add an entry defining the Struts tag library. There are currently four |
| taglibs that Struts is packaged with. |
| </p> |
| <p> |
| The struts-bean taglib contains tags useful in accessing |
| beans and their properties, as well as defining new beans (based on these accesses) that are |
| accessible to the remainder of the page via scripting variables and page scope attributes. |
| Convenient mechanisms to create new beans based on the value of request cookies, headers, |
| and parameters are also provided. |
| </p> |
| <p> |
| The struts-html taglib contains tags used to create struts input forms, as well as other |
| tags generally useful in the creation of HTML-based user interfaces. |
| </p> |
| <p> |
| The struts-logic taglib contains tags that are useful in managing conditional generation |
| of output text, looping over object collections for repetitive generation of output text, |
| and application flow management. |
| </p> |
| <p> |
| The struts-template taglib contains tags that define a template mechanism. |
| </p> |
| |
| <p> |
| Below is how you would define all taglibs for use within your application, |
| in reality you would only specify the taglib's that your application will use: |
| </p> |
| |
| <pre> |
| <taglib> |
| <taglib-uri> |
| /WEB-INF/struts-bean.tld |
| </taglib-uri> |
| <taglib-location> |
| /WEB-INF/struts-bean.tld |
| </taglib-location> |
| </taglib> |
| <taglib> |
| <taglib-uri> |
| /WEB-INF/struts-html.tld |
| </taglib-uri> |
| <taglib-location> |
| /WEB-INF/struts-html.tld |
| </taglib-location> |
| </taglib> |
| <taglib> |
| <taglib-uri> |
| /WEB-INF/struts-logic.tld |
| </taglib-uri> |
| <taglib-location> |
| /WEB-INF/struts-logic.tld |
| </taglib-location> |
| </taglib> |
| <taglib> |
| <taglib-uri> |
| /WEB-INF/struts-template.tld |
| </taglib-uri> |
| <taglib-location> |
| /WEB-INF/struts-template.tld |
| </taglib-location> |
| </taglib> |
| </pre> |
| |
| <p> |
| This tells the JSP system where to find the tag library descriptor |
| for this library (in your application's WEB-INF directory, instead of |
| out on the Internet somewhere). |
| </p> |
| </section> |
| |
| <section name="4.5.4 Add Struts Components To Your Application" href="config_add"> |
| |
| <p> |
| To use Struts, you must copy the .tld files that you require into |
| your <code>WEB-INF</code> directory, and copy <code>struts.jar</code> |
| (and all of the <code>commons-*.jar</code> files) into your |
| <code>WEB-INF/lib</code> directory. |
| </p> |
| <p> |
| Next: <a href="resources.html">Struts Resources</a> |
| </p> |
| </section> |
| </section> |
| </chapter> |
| </body> |
| </document> |