ALL OF THE INFORMATION IN THIS DOCUMENT IS DEPRECATED, BECAUSE IT IS SPECIFIC TO STRUTS 0.5. BE SURE TO REFER TO THE STRUTS 1.0 VERSION OF THE USER'S GUIDE, WHICH IS AVAILABLE AS PART OF THE STRUTS 1.0 RELEASE DOCUMENTATION.
FIXME - Need a general introduction to the pattern.
The Struts architecture implements the concepts of the Model-View-Controller design pattern by mapping them to web application components and concepts, as outlined in the following diagram:
Each major component of this architecture will be discussed in more detail below.
The Model portion of an MVC-based system can be subdivided into concepts -- the internal state of the system, and the actions that can be taken to change that state. In grammatical terms, we might think about state information as nouns (things) and actions as verbs (changes to the state of those things).
Generally, your application will represent the internal state of the system as a set of one or more JavaBeans, with properties that represent the details of the state. Depending on your application's complexity, these beans may be self contained (and know how to save their state information persistently somehow), or they may be facades that know how to retrieve information from external sources (such as a database) when it is requested. Entity Enterprise JavaBeans (EJBs) are also commonly used to represent internal state.
Large-scale applications will often represent the business logic actions
that are possible in a system as methods that can be called on the beans
maintaining the state information. For example, you might have a shopping
cart bean, stored in session scope for each current user, with properties
that represent the current set of items that the user has decided to
purchase. This bean might also have a checkOut()
method
that authorizes the user's credit card, and sends the order to the
warehouse to be picked and shipped. Other systems will represent the
available actions separately, perhaps as Session Enterprise JavaBeans
(EJBs).
In some smaller scale applications, on the other hand, the available
actions might be embedded within the Action
classes that are
part of the Controller role. This is appropriate when the logic is very
simple, or where reuse of the business logic in other environments is not
contemplated. The Struts framework supports any of these approaches, but
recommends separating the business logic ("what to do") from the role that
Action
classes play ("deciding what to do").
The View portion of a Struts-based application is generally
constructed using JavaServer Pages (JSP) technology. JSP pages can
contain static HTML (or XML) text called "template text", plus the
ability to insert dynamic content based on the interpretation (at page
request time) of special action tags. The JSP environment includes a
set of standard action tags, such as <jsp:useBean>
whose purpose is described in the JavaServer Pages Specification. In
addition, there is a standard facility to define your own tags, which
are organized into "custom tag libraries."
Struts includes an extensive custom tag library that facilitates
creating user interfaces that are fully internationalized, and that
interact gracefully with ActionForm
beans that are part
of the Model portion of the system. The use of these tags is
discussed in detail later.
In addition to JSP pages and the action and custom tags they contain,
it is often necessary for business objects to be able to render
themselves in HTML (or XML), based on their current state at request time.
The rendered output from such objects can be easily included in a
resulting JSP page by using the <jsp:include>
standard action tag.
The Controller portion of the application is focused on receiving
requests from the client (typically a user running a web browser), deciding
what business logic function is to be performed, and then delegating
responsibility for producing the next phase of the user interface to
an appropriate View component. In Struts, the primary component of the
controller is a servlet of class ActionServlet
. This servlet
is configured by defining a set of mappings (described by a Java interface
ActionMapping
). Each mapping defines a path
that is matched against the request URI of the incoming request, and the
fully qualified class name of an Action
class (that is, a
Java class implementing the Action
interface) which is
responsible for performing the desired business logic, and then dispatching
control to the appropriate View component to create the response.
Struts also supports the ability to use ActionMapping
classes that have additional properties beyond the standard ones required
to operate the framework. This allows you to store additional information
specific to your application, but still utilize the remaining features of
the framework. In addition, Struts lets you define logical "names" to which
control should be forwarded so that an action method can ask for the
"Main Menu" page (for example), without knowing what the actual name of the
corresponding JSP page is. These features greatly assist you in separating
the control logic (what do I do next) with the view logic (what is the name
of the corresponding page).
The application requirements document that you are using will likely have focused on the user interface to be created. However, you should ensure that the processing required for each submitted request is also clearly defined. In general, the developer of the Model components will be focusing on the creation of JavaBeans classes that support all of the functional requirements. The precise nature of the beans required by a particular application will vary widely depending on those requirements, but they can generally be classified into several categories discussed below. However, a brief review of the concept of "scope" as it relates to beans is useful first.
Within a web-based application, JavaBeans can be stored in (and accessed from) a number of different collections of "attributes". Each collection has different rules for the lifetime of that collection, and the visibility of the beans stored there. Together, the rules defining lifetime and visibility are called the scope of those beans. The JavaServer Pages (JSP) Specification defines scope choices using the following terms (with the equivalent servlet API concept defined in parentheses):
service()
method)It is important to remember that JSP pages and servlets in the same web application share the same sets of bean collections. For example, a bean stored as a request attribute in a servlet like this:
MyCart mycart = new MyCart(...); request.setAttribute("cart", mycart);
is immediately visible to a JSP page which this servlet forwards to, using a standard action tag like this:
<jsp:useBean id="cart" scope="request" class="com.mycompany.MyApp.MyCart"/>
The Struts framework generally assumes that you have created an
ActionForm
bean (that is, a Java class implementing the
ActionForm
interface) for each input form required in your
application. If you define such beans in your ActionMapping
configuration file (see "Building the Controller Components"), the Struts
controller servlet will automatically perform the following services for
you, before invoking the appropriate Action
method:
<jsp:setProperty>
when you use the
asterisk wildcard to select all properties.ActionForm
bean will be passed to the
Action Class perform()
method when it is called,
making these values immediately available.When you code your ActionForm
beans, keep the following
principles in mind:
ActionForm
interface itself requires no specific
methods to be implemented. It is used to identify the role these
particular beans play in the overall architecture. Typically, an
ActionForm
bean will have only property getter and
property setter methods, with no business logic.ActionForm
bean. The primary reason such beans exist
is to save the most recent values entered by the user for the
associated form -- even if errors are detected -- so that the same
page can be reproduced, along with a set of error messages, so the
user need only correct the fields that are wrong. Validation
of user input should be performed within Action
classes
(if it is simple), or appropriate business logic beans.getXxx()
and
setXxx()
methods) for each field that is present
in the form. The field name and property name must match according
to the usual JavaBeans conventions. For example, an input field named
username
will cause the setUsername()
method
to be called.You should note that a "form", in the sense discussed here, does not
necessarily correspond to a single JSP page in the user interface. It is
common in many applications to have a "form" (from the user's perspective)
that extends over multiple pages. Think, for example, of the wizard style
user interface that is commonly used when installing new applications. Struts
encourages you to define a single ActionForm
bean that contains
properties for all of the fields, no matter which page the field is actually
displayed on. Likewise, the various pages of the same form should all be
submitted to the same Action Class. If you follow these suggestions, the
page designers can rearrange the fields among the various pages, with no
changes required to the processing logic in most cases.
The actual state of a system is normally represented as a set of one or more JavaBeans classes, whose properties define the current state. A shopping cart system, for example, will include a bean that represents the cart being maintained for each individual shopper, and will (among other things) include the set of items that the shopper has currently selected for purchase. Separately, the system will also include different beans for the user's profile information (including their credit card and ship-to addresses), as well as the catalog of available items and their current inventory levels.
For small scale systems, or for state information that need not be kept for a long period of time, a set of system state beans may contain all the knowledge that the system ever has of these particular details. Or, as is often the case, the system state beans will represent information that is stored permanently in some external database (such as a CustomerBean object that corresponds to a particular row in the CUSTOMERS table), and are created or removed from the server's memory as needed. Entity Enterprise JavaBeans are also used for this purpose in large scale applications.
You should encapsulate the functional logic of your application as method calls on JavaBeans designed for this purpose. These methods may be part of the same classes used for the system state beans, or they may be in separate classes dedicated to performing the logic. In the latter case, you will usually need to pass the system state beans to be manipulated to these methods as arguments.
For maximum code re-use, business logic beans should be designed and
implemented so that they do not know they are being executed in a
web application environment. If you find yourself having to import a
javax.servlet.*
class in your bean, you
are tying this business logic to the web application environment. Consider
rearranging things so that your Action
classes (part of the
Controller role, as described below) translate all required information
from the HTTP request being processed into property setter calls on your
business logic beans, after which a call to an execute()
method
can be made. Such a business logic class can be reused in environments
other than the web application for which they were initially constructed.
Depending on the complexity and scope of your application, business logic beans might be ordinary JavaBeans that interact with system state beans passed as arguments, or ordinary JavaBeans that access a database using JDBC calls. For larger applications, these beans will often be stateful or stateless Enterprise JavaBeans (EJBs) instead.
Many web applications will utilize a relational database (accessed through a JDBC driver) to store the persistent data associated with the application. Others will use Entity Enterprise JavaBeans for this purpose, which delegates the decisions for how to maintain persistent state to the EJBs themselves. If you are using Enterprise JavaBeans for this purpose, follow the client design patterns described in the Enterprise JavaBeans specification.
For web applications based on direct database access, a common design problem is how to make an appropriate JDBC Connection object available when access to the underlying database is required. There are several possible approaches to this problem -- the following principles describe a recommended approach to this issue:
<servlet-mapping>
entry pointing at it.init()
method of the startup servlet, configure and
instantiate an instance of your ConnectionPool class, and store it as
a servlet context attribute (which is the same as an application scope
bean from the JSP perspective). It is usually convenient to configure
the connection pool based on initialization parameters passed to the
startup servlet.destroy()
method of the startup servlet, include
logic to gracefully release the connections that have been opened by
the connection pool. This method will get called when the servlet
container shuts down this application.Action
class needs to call a method of a business
logic bean that requires a database connection (such as "insert a new
customer"), it will the following steps:
open()
method of the connection pool object
to give you a connection for use within this Action
class call.close()
method of the allocated connection,
which will cause this connection to be returned to the pool for
later re-use on some other request.Action
class logic always returns the connection,
even if the business logic bean method throws an exception.Following the design pattern recommended above means that you can code
your business logic classes without having to worry about how they acquire a
JDBC Connection to use -- simply include a Connection argument in any method
call that needs to access the database. When your business logic class is
utilized within a web application, it will be the responsibility of the
Action
class to allocate and release an appropriate connection.
When you use the same business logic class, for example, in a batch job, it
will be the responsibility of that application to provide an appropriate
connection (which will not need to be acquired from a pool, because most
batch jobs run in a single-threaded environment).
This chapter focuses on the task of building the View components of the application, which will primarily be created using JavaServer Pages (JSP) technology. In particular, Struts provides support for building internationalized applications, as well as for interacting with input forms. Several other topics related to the View components are briefly discussed.
A few years ago, application developers could count on having to support only residents of their own country, who are used to only one (or sometimes two) languages, and one way to represent numeric quantities like dates, numbers, and monetary values. However, the explosion of application development based on web technologies, as well as the deployment of such applications on the Internet and other broadly accessible networks, have rendered national boundaries invisible in many cases. This has translated (if you will pardon the pun) into a need for applications to support internationalization (often called "i18n" because 18 is the number of letters in between the "i" and the "n") and localization.
Struts builds upon the Java platform to provide assistance for building internationalized and localized applications. The key concepts to become familiar with are:
java.util.Locale
. Each
Locale
represents a particular choice of country and
language (plus an optional language variant), and also a set of
formatting assumptions for things like numbers and dates.java.util.ResourceBundle
class
provides the fundmental tools for supporting messages in multiple
languages. See the Javadocs for the ResourceBundle
class,
and the information on Internationalization in the documentation bundle
for your JDK release, for more information.ResourceBundle
allows you to define resources using the
same "name=value" syntax used to initialize properties files. This is
very convenient for preparing resource bundles with messages that are
used in a web application, because these messages are generally text
oriented.java.text.MessageFormat
class
allows you to replace portions of a message string (in this case,
one retrieved from a resource bundle) with arguments specified at
run time. This is useful in cases where you are creating a sentence,
but the words would appear in a different order in different languages.
The placeholder string {0}
in the message is replaced by
the first runtime argument, {1}
is replaced by the second
argument, and so on.
org.apache.struts.util.MessageResources
lets you treat
a set of resource bundles like a database, and allows you to request
a particular message string for a particular Locale (normally one
associated with the current user) instead of for the default Locale
the server itself is running in.
For an internationalized application, follow the steps described in the Internationalization document in the JDK documentation bundle for your platform to create a properties file containing the messages for each language. An example will illustrate this further.
Assume that your source code is created in package
com.mycompany.mypackage
, so it is stored in a directory
(relative to your source directory) named
com/mycompany/mypackage
. To create a resource bundle called
com.mycompany.mypackage.MyResources
, you would create the
following files in the com/mycompany/mypackage
directory:
prompt.hello=Hello
prompt.hello=BonjourYou can have resource bundle files for as many languages as you need.
When you configue the controller servlet in the web application
deployment descriptor, one of the things you will need to define in
an initialization parameter is the base name of the resource bundle
for the application. In the case described above, it would be
com.mycompany.mypackage.MyResources
.
At one time or another, most web developers have built forms using
the standard capabilities of HTML, such as the <input>
tag. Users have come to expect interactive applications to have certain
behaviors, and one of these expectations relates to error handling -- if
the user makes an error, the application should allow them to fix just what
needs to be changed -- without having to re-enter any of the rest of the
information on the current page or form.
Fulfilling this expectation is tedious and cumbersome when coding with
standard HTML and JSP pages. For example, an input element for a
username
field might look like this (in JSP)
<input type="text" name="username" value="<%= loginBean.getUsername() %>">which is difficult to type correctly, confuses HTML developers who are not knowledgeable about programming concepts, and can cause problems with HTML editors. Instead, Struts provides a comprehensive facility for building forms, based on the Custom Tag Library facility of JSP 1.1. The case above would be rendered like this using Struts:
<struts:text name="username"/>with no need to explicitly refer to the JavaBean from which the initial value is retrieved. That is handled automatically by the framework.
A complete example of a login form will illustrate how Struts
makes dealing with forms much less painful than using straight HTML
and standard JSP facilities. Consider the following page (from the
example application included with Struts) named logon.jsp
:
<%@ page language="java" %> <%@ taglib uri="/WEB-INF/struts.tld" prefix="struts" %> <html> <head> <title><struts:message key="logon.title"/></title> <body bgcolor="white"> <struts:errors/> <struts:form action="logon.do" name="logonForm" type="org.apache.struts.example.LogonForm"/> <table border="0" width="100%"> <tr> <th align="right"> <struts:message key="prompt.username"/> </th> <td align="left"> <struts:text name="username" size="16"/> </td> </tr> <tr> <th align="right"> <struts:message key="prompt.password"/> </th> <td align="left"> <struts:password name="password" size="16"/> </td> </tr> <tr> <td align="right"> <struts:submit> <struts:message key="button.submit"/> </struts:submit> </td> <td align="right"> <struts:reset> <struts:message key="button.reset"/> </struts:reset> </td> </tr> </table> </struts:form> </body> </html>
The following items illustrate the key features of form handling in Struts, based on this example:
taglib
directive tells the JSP page compiler where to
find the tag library descriptor for the Struts tag library. In
this case, we are using struts
as the prefix that identifies
tags from this library, but any desired prefix can be used.MessageResources
object containing
all the resources for this application. For this page to work, the
following message keys must be defined in these resources:
Locale
object in the user's session. This Locale
will be used
to select messages in the appropriate language. This makes it easy to
implement giving the user an option to switch languages -- simply change
the stored Locale
object, and all messages are switched
automatically.<form>
element, based on the specified attributes.
It also associates all of the fields within this form with a session
scoped FormBean that is stored under the key logonForm
.
This bean is used to provide initial values for all of the input
fields that have names matching the property names of the bean.
If an appropriate bean is not found, a new one will be created
automatically, using the specified Java class name.<input>
element of type "text". In this case,
the number of character positions to occupy on the browser's screen
has been specified as well. When this page is executed, the current
value of the username
property of the corresponding bean
(that is, the value returned by getUsername()
).
Struts defines tags for all of the following types of input fields, with hyperlinks to the corresponding reference information.
In every
case, a field tag must be nested within a form
tag, so that
the field knows what bean to use for initializing displayed values.
There are several other tags in the Struts library that are useful in creating user interfaces:
enumerate
.enumerate
tag on a Java2 environment.
text
for
properties that should be read only.In addition to the form and bean interactions described above, Struts
offers an additional facility if your bean knows how to validate the input
fields it has received. To utilize this feature, have your bean class
implement the ValidatingActionForm
interface, rather than the
ActionForm
interface. A ValidatingActionForm adds an additional
method signature:
public String[] validate()
for a method that is called by the controller servlet after the bean
properties have been populated, but before the corresponding action class's
perform()
method is invoked. The validate()
method
has the following options:
null
or a zero-length String array, and the controller servlet
will proceed to call the perform()
method of the appropriate
Action
class.
MessageResources
bundle) that should be displayed. The
controller servlet will store this array as a request attribute suitable
for use by the <struts:errors>
tag, and will forward
control back to the input form (identified by the inputForm
property for this ActionMapping
.
As mentioned earlier, this feature is entirely optional. If your form bean
implements only the ActionForm
interface, the controller servlet
will assume that any required validation is done by the action class.
Although the look and feel of your application can be completely constructed based on the standard capabilities of JSP and the Struts custom tag library, you should consider employing other techniques that will improve component reuse, reduce maintenance efforts, and/or reduce errors. Several options are discussed in the following sections.
Beyond using the custom tags provided by the Struts library, it is easy to create tags that are specific to the application you are building, to assist in creating the user interface. The example application included with Struts illustrates this principle by creating the following tags unique to the implementation of this application:
checkLogon
- Checks for the existence of a particular session
object, and forwards control to the logon page if it is missing. This is
used to catch cases where a user has bookmarked a page in the middle of
your application and tries to bypass logging on, or if the user's session
has been timed out.linkSubscription
- Generates a hyperlink to a details page
for a Subscription, which passes the required primary key values as
request attributes. This is used when listing the subscriptions associated
with a user, and providing links to edit or delete them.linkUser
- Generates a hyperlink to a details page
for a User, which passes the required primary key values as
request attributes.The source code for these tags is in the src/example
directory,
in package org.apache.struts.example
, along with the other Java
classes that are used in this application.
Creating the entire presentation of a page in one JSP file (with custom tags and beans to access the required dynamic data) is a very common design approach, and was employed in the example application included with Struts. However, many applications require the display of multiple logically distinct portions of your application together on a single page.
For example, a portal application might have some or all of the following functional capabilities available on the portal's "home" page:
The development of the various segments of this site is easier if you can divide up the work, and assign different developers to the different segments. Then, you can use the include capability of JavaServer Pages technology to combine the results into a single result page. There are two types of include available, depending on when you want the combination of output to occur:
<%@ include file="xxxxx"
%>
) is processed when the JSP page is compiled. It is
useful when you are including HTML code that will not need to change
at request time. It treats the text being included as static text,
much like the #include
directive in C or C++.<jsp:include page="xxxxx"
flush="true" />
) is processed at request time, and is handled
transparently by the server. Among other things, that means you
can conditionally perform the include by nesting it within a tag
like ifParameterEquals.Some applications require dynamically generated images, like the price charts on a stock reporting site. Two different approaches are commonly used to meet these requirements:
image/gif
),
and send back the bytes of that image to the browser, which will display
them just as if it had received a static file.Now that we understand how to construct the Model and View components
of your application, it is time to focus on the Controller
components. Struts includes a servlet that implements the primary function
of mapping a request URI to an Action
class. Therefore, your
primary responsibilities related to the Controller are:
Action
class (that is, an implementation of the
Action
interface) for each logical request
that may be received.ActionMapping
class (that is, an implementation
of the ActionMapping
interface) that defines the class
names and other information associated with each possible
mapping.The Action
interface defines a single method that must be
implemented by an Action
class, as follows:
public ActionForward perform(ActionServlet servlet, ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException;
The goal of an Action
class is to process this request,
and then to return an ActionForward
object that identifies
the JSP page (if any) to which control should be forwarded to generate
the corresponding response. In the Model 2 design pattern,
a typical Action
class will implement the following
logic in its perform()
method:
Action
class finds that no logon exists, the request should 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 your
application "in the middle" (say, from a bookmark), or because the
session has timed out, and the servlet container created a new one.ValidatingActionForm
interface),
validate the form bean properties as necessary. 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.Action
class itself, but should generally be performed
by calling an appropriate method of a business logic bean.
ActionForward
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 findForward()
on either the
ActionMapping
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).Design issues to remember when coding Action
classes
include the following:
Action
class, and uses it for all requests. Thus,
you need to code your Action
class so that it operates
correctly in a multi-threaded environment, just as you must code a
servlet's service()
method safely.Action
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.perform()
method, and log them to the
application logfile (along with the corresponding stack trace) by
calling:
servlet.log("Error message text", exception);
In addition, you will want to guard against Action
classes
that are too large. The easiest way for this to happen is to embed your
functional logic in the Action
class itself, rather than
coding it in separate business logic beans. Besides making the
Action
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 Action
class) that
is tied to being executed in a web application environment.
The example application included with Struts stretches this design
principle somewhat, because the business logic itself is embedded in the
Action
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.
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 Action
class. The required knowledge has been
encapsulated in a Java interface named ActionMapping
, which
has the following properties:
Action
class used for this mapping. The first time
a particular mapping is used, an instance of this class will be
created and saved for reuse later.ActionForm
for this mapping is stored.
If this property is not defined, no ActionForm
will be
used.ActionForm
class used for this mapping. If you are
using the support for form beans, an instance of this class will be
created and saved (in the current user's session) automatically
whenever necessary.Struts includes a convenient implementation of the
ActionMapping
interface, in a class named
ActionMappingBase
. If you do not need to define any
additional properties for your own mappings, feel free to use
this class as your ActionMapping
class, configured as
described in the following section. However, it is also possible to
define an ActionMapping
implementation (perhaps extending the
ActionMappingBase
class) that contains additional properties.
The controller servlet knows how to configure these custom properties
automatically, because it uses the Struts Digester module to read the
configuration file.
In the example application included with Struts, this feature is used to define two additional properties:
Using these two extra properties, the Action
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
Action
classes themselves. If the names of the "next" JSP
pages were hard coded into the Action
classes, all of these
classes would also need to be modified.
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 ActionMapping
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 API documentation for more information
about Digester.
The developer's responsibility is to create an XML file named
action.xml
, and place it in the WEB-INF directory of your
application. (Note that no DTD for this file is required, because the
actual attributes used can be different for different users.) The
outermost XML element must be <action-mappings>
, and
within this element are nested zero or more <action>
elements -- one per mapping that you wish to define.
The action.xml
file from the example application includes
the following mapping entry for the "log on" function, which we will use
to illustrate the requirements:
<action-mappings> <forward name="logon" path="/logon.jsp"/> <action path="/logon" actionClass="org.apache.struts.example.LogonAction" formAttribute="logonForm" formClass="org.apache.struts.example.LogonForm" inputForm="/logon.jsp"> <forward name="success" path="/mainMenu.jsp"/> </action> </action-mappings>
As you can see, this mapping matches the path /logon
(actually,
because the example application uses extension mapping, the request URI you
specify in a JSP page would end in /logon.do
). When a request
that matches this path is received, an instance of the LogonAction
class will be created (the first time only) and used. The controller servlet
will look for a session scoped bean under key logonForm
, creating
and saving a bean of the specified class if needed.
This action
element also defines a logical name "success",
which is used within the LogonAction
class to identify the
page to be used when a user successfully logs on. Using a logical name like
this allows the action class to be insulated from any changes in the page
names that might occur due to a site redesign.
There is a second forward
element that is declared outside
of any action
, so it is globally available to all actions. In
this case, it defines a logical name for the logon page. In your action
code, when you call mapping.findForward()
, Struts first looks at
the locally defined logical names for this action. If it does not find one,
it then searches the global definitions for you automatically.
The final step in setting up the application is to configure the application
deployment descriptor (stored in file WEB-INF/web.xml
) 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.
Add an entry defining the action servlet itself, along with the appropriate initialization parameters. Such an entry might look like this:
<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/action.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>
The initialization parameters supported by the controller servlet are
described below, which is copied from the Javadocs
for the ActionServlet
class. Square brackets describe the
default values that are assumed if you do not provide a value for that
initialization parameter.
initMapping()
, which logs to System.out
instead of the servlet log. [0]
true
, add HTTP headers
to every response intended to defeat browser caching of any response we
generate or forward to. [false]
true
, set our application
resources to return null
if an unknown message key is used.
Otherwise, an error message including the offending message key will
be returned. [true]
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.
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:
<servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>/execute/*</url-pattern> </servlet-mapping>
which means that a request URI to match the /logon
path
described earlier might look like this:
http://www.mycompany.com/myapplication/execute/logon
where /myapplication
is the context path under which your
application is deployed.
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 *.jsp
pattern so that it is called to process every
JSP page that is requested. To use the *.do
extension (which
implies "do something"), the mapping entry would look like this:
<servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping>
and a request URI to match the /logon
path described
earlier might look like this:
http://www.mycompany.com/myapplication/logon.do
Next, you must add an entry defining the Struts tag library. The entry should look like this:
<taglib> <taglib-uri>/WEB-INF/struts.tld</taglib-uri> <taglib-location>/WEB-INF/struts.tld</taglib-location> </taglib>
which 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).
To use Struts when your application executes, you must copy the
struts.tld
file to your WEB-INF
directory,
and the struts.jar
file to your WEB-INF/lib
directory.