Section 3: Processing
Requests with Action Objects |
|---|
| 3.1 The Six Basic Steps | 3.2 Example 1: One Result Mapping |
|---|---|
| 3.3 Example 2: Multiple Result Mappings | 3.4 Source Code |
| Struts Tutorial Table of Contents | More Info |
| 3.1 The Six Basic Steps in Using Jakarta Struts |
|---|
With Struts, the normal processing flow is that a form
submits data to a URL of the form blah.do.
That address is mapped
by struts-config.xml to an
Action
object, whose
execute
method handles the request. One of the arguments to
execute is a form bean that is automatically created
and whose properties are automatically populated with the
incoming form data. The Action object then invokes
business logic and data-access logic, placing the results
in normal beans stored in request, session, or application
scope. The Action uses mapping.findForward to return
a condition, and the conditions are mapped by struts-config.xml
to various JSP pages. The system forwards the request to the
appropriate JSP page, where the
bean:write tag is used
to output properties of the form bean and results beans.
Optionally, both the input form and the final JSP pages
can use
bean:message to output standard messages
and labels as defined in a system property file.
Here are the minimum steps needed to create an application that
follows this process. This section will focus on the basic
flow and the Action objects;
the next section
will show how to use beans.
Action classes to handle requests for
blah.do.
ActionForm and will represent the
data submitted by the user. It is automatically populated
when the input form is submitted. Beans will be discussed
in the next section.
Action object to handle requests.Action object that handles
requests for various URLs. The Action objects themselves need to
do the real work: invoke the appropriate business- and data-access-logic,
store the results in beans, and designate the type of situation (missing data,
database error, success category 1, success category 2, etc.) that
is appropriate for the results. The
struts-config.xml file then decides
which JSP page should apply to that situation.
ACTION corresponds to
one of the *.do addresses listed in
struts-config.xml. At a minimum,
the input form should look like this: <FORM ACTION=".../blah.do" ...>...</FORM>
html:form tag to build this input form.
bean:write tag,
but in JSP 2.0 the JSP 2.0 expression language is a viable alternative.
In complex cases, the JSP pages also use
the
JSP Standard Tag Library (JSTL) or the
Struts looping/logic tags.
Action, since it is
the Action that invokes
the logic that creates the data that the JSP pages will display.
So, the JSP pages are placed in WEB-INF,
where RequestDispatcher
can forward to them but where clients cannot access them
directly. If the JSP pages makes sense independently of the Action
(e.g., if they display session data), then the JSP pages should be
placed in a regular subdirectory of the Web application, and
the forward entries in
struts-config.xml should say
<forward ... redirect="true"/>.
| 3.2 Example 1: One Result Mapping |
|---|
In this example, the URL
http://hostname/struts-test/actions/register1.do
should be handled by
the class RegisterAction1 (which extends
Action and is in
the coreservlets package).
RegisterAction1 always returns "success",
and this return value results in the JSP page
/WEB-INF/results/result1.jsp being
displayed to the client.
Action object to handle requests.
Action classes to handle requests for
blah.do. In this
case, we designate that RegisterAction1
should handle requests for /actions/register1.do
(notice that .do is implied automatically).
To accomplish this, we add an action
entry to
action-mappings, where
action has the following attributes.
Action,
minus the .do extension. Thus,
path="/actions/register1" refers to
http://hostname/webAppName/actions/register1.do.
See this section for a discussion of why
it is useful to use /actions/register1
instead of just register1 in the path.
Action object that
should be invoked when a request for the specified path is received.
action element looks like this:<action path="/actions/register1"
type="coreservlets.RegisterAction1">
...
</action>
forward element to say
that result1.jsp applies
when RegisterAction1 returns "success",
as follows:<forward name="success"
path="/WEB-INF/results/result1.jsp"/>
struts-config.xml <?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE struts-config PUBLIC ... > <struts-config> <action-mappings> <action path="/actions/register1" type="coreservlets.RegisterAction1"> <forward name="success" path="/WEB-INF/results/result1.jsp"/> </action> </action-mappings> </struts-config>
Action
object to handle requests.Action subclass should:
package coreservlets;This means that the class file should go in your_web_app/WEB-INF/classes/coreservlets/.
import javax.servlet.http.*; import org.apache.struts.action.*;
Action class. In this case, we have
public class RegisterAction1 extends Action {...}
execute method. This method is defined
as follows.
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
...
}
mapping.findForward. The execute method
should have one or more return values. These values will then
be mapped to specific JSP pages by forward entries in
struts-config.xml.
In this case, we simply return "success" in all situations.
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
return(mapping.findForward("success"));
}
Action will do nothing but return "success".
Here is the code (download the source code here).
RegisterAction1.java package coreservlets; import javax.servlet.http.*; import org.apache.struts.action.*; public class RegisterAction1 extends Action { public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { return(mapping.findForward("success")); } }
ACTION as follows.
Theregister1.jsp (Excerpt) <!DOCTYPE ...> <HTML> <HEAD><TITLE>New Account Registration</TITLE></HEAD> <BODY BGCOLOR="#FDF5E6"> <CENTER> <H1>New Account Registration</H1> <FORM ACTION="../actions/register1.do" METHOD="POST"> Email address: <INPUT TYPE="TEXT" NAME="email"><BR> Password: <INPUT TYPE="PASSWORD" NAME="password"><BR> <INPUT TYPE="SUBMIT" VALUE="Sign Me Up!"> </FORM> </CENTER> </BODY></HTML>
POST method is used because the form contains
a password field, and .do
must be listed explicitly in the URL even though
it is omitted in the action declaration in
struts-config.xml. (However,
the html:form tag shown in the Section 5
will automatically add .do
to the URL.) See this section for a discussion of why
it is useful to place the forms in a subdirectory instead of in the
top-level Web application directory.
execute method
of the Action. In
struts-config.xml, each JSP page is
declared in a forward entry within the appropriate action.
In this simple case, the only return value is "success",
so /WEB-INF/results/result1.jsp is used in all cases.
This JSP page displays a simple message, as shown below (download the
source code here).
result1.jsp <!DOCTYPE ..."> <HTML> <HEAD><TITLE>Success</TITLE></HEAD> <BODY BGCOLOR="#FDF5E6"> <CENTER> <H1>You have registered successfully.</H1> (Version 1) </CENTER> </BODY></HTML>
ACTION
resulting in the URL
http://localhost/struts-test/actions/register1.do. This address is
mapped by struts-config.xml
to the RegisterAction1 class, whose
execute method is invoked. This method returns a
mapping.findForward with
a value of "success", and that value is mapped by
struts-config.xml
to /WEB-INF/results/result1.jsp,
which is the final result displayed to the user.
However, since the JSP page is invoked with RequestDispatcher.forward,
not response.sendRedirect, the URL displayed to the user is
register1.do, not
result1.jsp. See the following screen shot.
| Option 1: No Subdirectories | Option 2: Subdirectories |
|---|---|
Action path gives a name only:<action |
Action path gives a pseudo-directory name:<action |
| Form placed in top-level Web application directory: http://hostname/struts-test /register1.jsp |
Form placed in Web application subdirectory: http://hostname/struts-test /forms/register1.jsp |
Form specifies only blah.do:<FORM |
Form specifies path with .. or
/webAppName/:<FORM
|
Although the first option is simpler, there are several reasons why I think the second option is preferable:
| 3.3 Example 2: Multiple Result Mappings |
|---|
In this example, the URL
http://hostname/struts-test/actions/register2.do should be handled by
the class RegisterAction2. The
execute method of RegisterAction2
returns "success",
"bad-address", or "bad-password", and
these return values result in the JSP pages
/WEB-INF/results/result2.jsp,
/WEB-INF/results/bad-address2.jsp,
and /WEB-INF/results/bad-password2.jsp, respectively.
The main new feature in this example is the use of multiple
forward entries within the action element.
Action classes to handle requests for blah.do.
In this case, we use the action element to
designate that RegisterAction2
should handle requests for /actions/register2.do
(again, note that .do is implied, not
listed explicitly).
forward elements, one for each
possible return value from the execute method of the
Action object.
struts-config.xml (Excerpt) <?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE struts-config PUBLIC ... > <struts-config> <action-mappings> ... <action path="/actions/register2" type="coreservlets.RegisterAction2"> <forward name="bad-address" path="/WEB-INF/results/bad-address2.jsp"/> <forward name="bad-password" path="/WEB-INF/results/bad-password2.jsp"/> <forward name="success" path="/WEB-INF/results/result2.jsp"/> </action> </action-mappings> </struts-config>
Action
object to handle requests.mapping.findForward entries. We
return "bad-address" if the email address is
missing, is less then three characters long, or does
not contain an "@" sign. We return
"bad-password" if the password is missing or
is less than six characters long. Otherwise
we return "success". In this
simple example we use request.getParameter explicitly,
but in later examples we let Struts automatically
populate a bean from the request data.
Here is the code (download the source code here).
RegisterAction2.java package coreservlets; import javax.servlet.http.*; import org.apache.struts.action.*; public class RegisterAction2 extends Action { public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { String email = request.getParameter("email"); String password = request.getParameter("password"); if ((email == null) || (email.trim().length() < 3) || (email.indexOf("@") == -1)) { return(mapping.findForward("bad-address")); } else if ((password == null) || (password.trim().length() < 6)) { return(mapping.findForward("bad-password")); } else { return(mapping.findForward("success")); } } }
ACTION as follows.
register2.jsp (Excerpt) <!DOCTYPE ...> <HTML> <HEAD><TITLE>New Account Registration</TITLE></HEAD> <BODY BGCOLOR="#FDF5E6"> <CENTER> <H1>New Account Registration</H1> <FORM ACTION="../actions/register2.do" METHOD="POST"> Email address: <INPUT TYPE="TEXT" NAME="email"><BR> Password: <INPUT TYPE="PASSWORD" NAME="password"><BR> <INPUT TYPE="SUBMIT" VALUE="Sign Me Up!"> </FORM> </CENTER> </BODY></HTML>
bad-address2.jsp <!DOCTYPE ...> <HTML> <HEAD><TITLE>Illegal Email Address</TITLE></HEAD> <BODY BGCOLOR="#FDF5E6"> <CENTER> <H1>Illegal Email Address</H1> Address must be of the form username@host. Please <A HREF="../forms/register2.jsp">try again</A>. </CENTER> </BODY></HTML>bad-password2.jsp <!DOCTYPE ...> <HTML> <HEAD><TITLE>Illegal Password</TITLE></HEAD> <BODY BGCOLOR="#FDF5E6"> <CENTER> <H1>Illegal Password</H1> Password must contain at least six characters. Please <A HREF="../forms/register2.jsp">try again</A>. </CENTER> </BODY></HTML>result2.jsp <!DOCTYPE ...> <HTML> <HEAD><TITLE>Success</TITLE></HEAD> <BODY BGCOLOR="#FDF5E6"> <CENTER> <H1>You have registered successfully.</H1> (Version 2) </CENTER> </BODY></HTML>
ACTION results in the URL
http://localhost/struts-test/actions/register2.do. This address is
mapped by struts-config.xml to the RegisterAction2 class, whose
execute method is invoked. This method examines the
email address, determines it is illegal because it lacks an "@" sign,
and returns mapping.findForward with
a value of "bad-address". That value is mapped by struts-config.xml
to /WEB-INF/results/bad-address2.jsp,
which is the final result displayed to the user
for this input.
ACTION results in the URL
http://localhost/struts-test/actions/register2.do. This address is
mapped by struts-config.xml
to the RegisterAction2 class, whose
execute method is invoked. This method examines the
password, determines it is too short,
and returns mapping.findForward with
a value of "bad-password". That value is mapped by struts-config.xml
to /WEB-INF/results/bad-password2.jsp,
which is the final result displayed to the user
for this input.
ACTION results in the URL
http://localhost/struts-test/actions/register2.do. This address is
mapped by struts-config.xml
to the RegisterAction2 class, whose
execute method is invoked. This method finds no
problem with either the email address or the password, so
returns mapping.findForward with
a value of "success". That value is mapped by struts-config.xml
to /WEB-INF/results/result2.jsp,
which is the final result displayed to the user
for this input.
| 3.4 Source Code for this Section |
|---|
The following list gives the source code for all files described in this section, listed in the order that they appear.
To download the code, right-click on the links and choose "Save Target As". Be sure to reproduce the same directory structure as given here. The easiest approach is to download and unjar the entire struts-test WAR file, but this takes some time since this WAR file includes the Struts JAR files, not just the example code.
Action subclass.
Action subclass.
| More Information |
|---|
|
|