Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Struts
1. Introduction
There is a big difference between a school page and a professionally developed Web site. The page designer (or
HTML developer) must understand colors, the customer, product flow, page layout, browser compatibility,
image creation, JavaScript, and more. Putting a great looking site together takes a lot of work, and most Java
developers are more interested in creating a great looking object interface than a user interface. Java Server
Pages (JSP) technology provides the glue between the page designer and the Java developer.
If you have worked on a large-scale Web application, you understand the term change. Model-View-Controller
(MVC) is an approach put together to help control change. MVC decouples interface from business logic and
data. Struts is an MVC2 implementation that uses Servlets and JSP tags, from the J2EE specifications, as part
of the implementation.
Model-View-Controller (MVC)
MVC helps resolve some of the issues with the single module approach by dividing the problem into three
categories:
• Model
The model contains the core of the application's functionality. The model encapsulates the state of the
application.
• View
The view provides the presentation of the model. It is the look of the application. The view can access
the model getters, but it has no knowledge of the setters. In addition, it knows nothing about the
controller. The view should be notified when changes to the model occur.
• Controller
The controller reacts to the user input. It creates and sets the model.
MVC Model 1
The Model 1 architecture is very simple. A request is made to a JSP or servlet and then that JSP or servlet
handles all responsibilities for the request, including processing the request, validating data, handling the
business logic, and generating a response.
A JSP tag is simply a way of abstracting out code from a JSP file.
JSP tags solved only part of our above listed problems. We still have issues with validation, flow control, and
updating the state of the application. This is where MVC2 comes to the rescue.
MVC Model 2
In this MVC architecture, a central servlet, known as the Controller, receives all requests for the application.
The Controller then processes the request and works with the Model to prepare any data needed by the View
(which is usually a JSP) and forwards the data to a JSP. The JSP then uses the data prepared by the Controller to
generate a response to the browser. In this architecture, the business and presentation logic are separated from
each other. Having the separation of business and presentation code accommodates multiple interfaces to the
application, be they Web, wireless, or GUI (Swing). Additionally, this separation provides excellent reuse of
code.
Note – Model 1 (single page approach) and Model 2 (true MVC approach), so don’t be confuse if you asked for
MVC model 1, you need to explain single page approach.
2. Struts Framework
What a framework means?
• an extensible/generic/flexible architecture following set of standards and patterns
• Focuses on a specific domain (web / j2ee applications etc)
• Provides extension points
• Can be customized and used on projects
Action Form
Client
Browser
2.4 use 2.3 create
3 forward Action Forward 2.2 interact
JSP
3.1 (can) interact Application
[View]
4 update State
[Model]
HTTP Response
• Most of the times we will extend ActionForm for making input page form beans and Action class for
putting the business logic like we did in servlet.
• We can customize controller parts also.
• Most of the API and tags works in internationalized fashion, so they will take data to display as a key
and we will define these key-values into properties file. So by default our application will be
multilingual.
• We can define our validation rules on user inputs into xml, means highly configurable and reusable
validation code.
• We can break our look and feel into tiles and each tile can be configured through xml, means making the
presentation configurable.
• We define the flow inside the struts-config.xml that makes our application flow highly configurable.
3. HelloWorld Setup
Folder Structure
//hello.jsp
<%@ taglib uri="/tags/struts-html" prefix="html"%>
<%@ taglib uri="/tags/struts-bean" prefix="bean"%>
<html>
<head><title>Struts HelloWorld</title></head>
<body>
<html:errors/>
<h1>Struts HelloWorld</h1>
<html:form action="/hello.do">
<bean:message key="hello.msg.label" />
<html:text property="msg" />
<html:submit />
</html:form>
</body>
</html>
//success.jsp
<%@ taglib uri="/tags/struts-html" prefix="html"%>
<%@ taglib uri="/tags/struts-bean" prefix="bean"%>
<html>
<head><title>Struts HelloWorld Success
Page</title></head>
<body>
<h1>Struts HelloWorld Success Page</h1>
<bean:write name="message" />
</body>
</html>
//Message.properties
hello.msg.label=Message :
errors.msg.empty=Empty Message Not Allowed.
// HelloAction.java
package org.test;
import javax.servlet.http.*;
import org.apache.struts.action.*;
return mapping.findForward("success");
}
}//class
//HelloForm.java
package org.test;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.*;
//struts-config.xml
<?xml version="1.0" encoding="ISO-8859-1" ?>
<struts-config>
</struts-config>
//web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app>
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<taglib>
<taglib-uri>/tags/struts-bean</taglib-uri>
<taglib-location>/WEB-INF/tlds/struts-bean.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/tags/struts-html</taglib-uri>
<taglib-location>/WEB-INF/tlds/struts-html.tld</taglib-location>
</taglib>
</web-app>
1. Since the request ends at .do so the ActionServlet will get called. This servlet works as Front
Controller.
2. ActionServlet will take out /welcome from /welcome.do and look for mapping
3. it will found direct forward rule and will forward the request to /hello.jsp
4. when you submit the hello.jsp page in action it calls /hello.do
5. again step 1 and 2 will be repeated
6. Now this time it founds an action class and form associated with this action.
7. instantiate the form bean object, called the setter method for properties name matched and then called
the validate method which returns ActionErrors object
8. it check this object if empty then execution goes to HelloAction execute() method else it forward the
request to input="/hello.jsp"
9. in execute we cast the form, fetch the value and then added into request
request.setAttribute("message", "Your Message " + msg + " received!!!");
execute() returns ActionForward that hold the logical name of the page to be forwarded.
<forward name="success" path="/success.jsp"></forward>
And finally we see the success.jsp as a final output.
Note – Actions are part of model or controller is somewhat debatable but if we look into the functionality of
Action, it is used for get/set data from beans, ejbs or database and provides this data to view for
representation. In this sense it is perfect to say actions are part of model.
But if we say Servlets are replaced by Action and Servlets in struts are used for controlling then Action
seems to the part of controller. But the first discussion is having more weightage.
Big Note –
• Only one instance of your Action class is created and used for all requests.
• Thus they need to be thread safe
• Exceptions thrown from execute() method should be appropriately logged
• Consider using custom actions to simplify coding
4. Internationalization
In above example we used Message.properties that keeps the text values to display on pages and thats why we
used <bean:message key=”hello.msg.label”/> in our jsp.
For different countries language support, we have to create multiple properties file that follow some naming
convention and that is Message_xx.properties. Where xx is the two letter language code.
Step 1 - create a property file for Japanese (language code - ja)
//Message_ja.properties
hello.msg.label=ergtmlkr :
errors.msg.empty=em45549jogfkg knkld 9-9.
Step 3 – refresh the application and see now the value is coming from ja properties file automatically.
I know you will not believe how easy it is to make multilingual application in struts, but it is the fact. This is
one of the benefits of using struts tags, they are language sensitive.
5.1 ForwardAction
This is provided as a simple utility action that can be used for scenarios in which you simply want to link to a
JSP page. Of course, linking directly to the JSP would be a violation of the MVC principles because all requests
are supposed to be routed through the Controller. ForwardAction can be used to create links to JSPs so that
you don’t have to create an action whose only responsibility is to forward a request every time you want to link
to a JSP. With ForwardAction, you simply create an action mapping in the Struts configuration file and specify
the location to which the action will forward.
The ForwardAction creates a request dispatcher and forwards control to a context-relative URI supplied by
the ActionMapping. The context-relative path is given as the ActionMapping’s parameter property:
<action-mappings>
<action path="/welcome"
type="org.apache.struts.actions.ForwardAction"
parameter="/hello.jsp/>
</action-mappings>
The practical upshot is that instead of http://localhost:8080/hello/hello.jsp appearing on the browser’s address
bar, where it could be bookmarked for direct access, the Action URI appears instead:
http://localhost:8080/hello/welcome.do
In this case RequestProcessor’s processForward()/processInclude() method handle this and dispatch the request
to target resource defined in forward/include attribute of action mapping.
This action behaves similarly to ForwardAction, but instead of forwarding to the specified URL, the specified
URL is included. This action is useful when you want to include the contents of one page in another.
<action-mappings>
<action path="/welcome"
type="org.apache.struts.actions.IncludeAction"
parameter="/hello.jsp/>
</action-mappings>
Note -
2. Each of the dispatch methods must use the same signature as the usual Action execute () method.
3. In action mapping define the name of a request parameter, which value will be the method name and it
will be used to select the method. We have to set the value as a hidden parameter or form element or
through java script. Any how the value of the parameter must be there in request.
<action path="/user" type="org.test.UserAction" name="userForm"
scope="request" input="/user.jsp" parameter="method">
<forward name="success" path="/user.jsp"></forward>
</action>
Note – “method” is the name of parameter which will have value create/read/update/delete or
anything match to your method name.
/**************UserAction.java***********************************
public class UserAction extends DispatchAction {
return mapping.findForward("success");
}
public ActionForward delete(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
System.out.println("USer Action : Delete Method");
return mapping.findForward("success");
}
}
Or create a user.jsp like this in which buttons name is “method” and value is method
name.
<%@ taglib uri="/tags/struts-html" prefix="html"%>
<%@ taglib uri="/tags/struts-bean" prefix="bean"%>
<html:form action="/user.do">
<html:submit property="method">
<bean:message key="button.add" />
</html:submit>
<html:submit property="method">
<bean:message key="button.view" />
</html:submit>
<html:submit property="method">
<bean:message key="button.update" />
</html:submit>
<html:submit property="method">
<bean:message key="button.delete" />
</html:submit>
</html:form>
Click the individual button and see the output message in tomcat-
5.4 LookupDispatchAction
A convenient way to select a dispatch method is by linking it with a button, as we did in above example. This
can be problematic in a localized application, since the label of the button may change according to the user’s
locale. For one user, the button may read Delete; for another, it may read Borre.
The LookupDispatchAction solves this problem by mapping the labels back to their original message key. The
key can then be mapped to the appropriate dispatch method. Since the message key may not be an appropriate
name for a Java method, the developer provides a hash table that maps the message keys to the dispatch method
names:
<action-mappings>
<action path="/switch" type="org.apache.struts.actions.SwitchAction"/>
</action-mappings>
Once configured in the Struts configuration file, SwitchAction can be put to use. Simply create a link to the
action and specify the module to switch to and a page to forward to afterward. The module to switch to is
specified with the prefix parameter and the page to forward to afterward is specified with the page parameter.
The following URL illustrates how to use the request parameters:
http://localhost:8080/hello/switch.do?prefix=/dg&page=/discussion.do
This example URL switches to the /dg module, and the /discussion.do page will be forwarded to after the
module has been switched.
Struts Modules
Situation – Suppose our portal has three modules, one is default and other two are dg (discussion group) and
news (news group). All the modules are running independently, means having the separate web folder structure
in web server.
Now we want to merge dg and news with default and want to make one application. So we have to take care of
following things.
1. Single web.xml with other module name and configuration filename information inside this.
2. Whenever forwarding request from one module to other module use one of the approach.
• use the org.apache.struts.actions.SwitchAction
• use a <forward> (global or local) and specify the contextRelative attribute with a value of true,
• can specify the "module" parameter as part of any of the Struts JSP hyperlink tags (Include, Img,
Link, Rewrite, or Forward).
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>config/dg</param-name>
<param-value>/WEB-INF/struts-config-dg.xml</param-value>
</init-param>
<init-param>
<param-name>config/news</param-name>
<param-value>/WEB-INF/struts-config-news.xml</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>2</param-value>
</init-param>
<init-param>
<param-name>detail</param-name>
<param-value>2</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
*************************struts-config-dg.xml ************************
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_2.dtd">
<struts-config>
<!--Action Mapping Definitions -->
<action-mappings>
<action path="/dg" forward="/dg.jsp" />
</action-mappings>
*************************struts-config-news.xml ************************
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_2.dtd">
<struts-config>
<!--Action Mapping Definitions -->
<action-mappings>
<action path="/news" forward="/news.jsp" />
</action-mappings>
Note – you have to copy all the .class and properties files used in module in main WEB-
INF classes folder. You can keep the following type of files in module specific folders
like xmls, images, jsps etc.
*************************dg.jsp************************
<%@ taglib uri="/tags/struts-bean" prefix="bean"%>
<h1>Discussion group</h1>
<bean:message key="dg.msg"/>
*************************dg.properties************************
dg.msg=Hello DG Module
*************************news.properties************************
dg.msg=Hello News Module
</body>
</html>
1. Will Not work – not going through controller, and we have used <bean:message> tag
that will try to pick key value from property file but from which module?? Yes,
from default because we are making direct access to jsp so not going through
controller, so module specific things will not be applicable.
2. will work – going through controller
3. will work – providing information to controller, it require to configure
SwitchAction
Note – you can put your dg and news folder inside WEB-INF that stop direct access.
What you have to do in path attribute you have to provide value “/WEB-INF/dg.jsp” instead
of “/dg.jsp”
Surprised!!!! All will work, you know why, because all request
are going through controller.
6. struts-config.xml
6.1 <global-forwards> if there is global forward then might be something like <local-forward> should also
exist?? Yes, in <action> we used <forward> that was the local forward.
If a logical name used by Action not found locally then it looks inside the <global-forwards> entries.
So <global-forwards> encapsulates a set of forwards, defined by forward tags, which are global to the
application.
<global-forwards>
<forward name="success" path="/success.jsp"/>
<forward name="failure" path="/failure.jsp"/>
</global-forwards>
Local Forward –
<action-mappings>
<action path="/hello" type="org.test.HelloAction" name="helloForm"
scope="request" validate="true" input="/hello.jsp">
<forward name=”success” path=”/hello.jsp”/>
</action-mappings>
6.2 <global-exceptions>
The global-exceptions tag is used to encapsulate a set of exception handlers, defined by exception tags, which
are global to the application. This set of global exception handlers will be used to handle any exceptions being
thrown from actions and that action mappings does not have matching local exception tag.
<global-exceptions>
<exception type="org.test.exception.DataNotFoundException"
key="errors.data.notfound"
path="/error.jsp"/>
</global-exceptions>
The following sections walk through each step of the process in detail.
package org.test.exception;
public class NoDataFoundException extends Exception {
}
import java.sql.ResultSet;
import javax.servlet.http.*;
import org.apache.struts.action.*;
import org.test.exception.NoDataFoundException;
throws Exception {
ResultSet rs = null;
if (rs == null)
throw new NoDataFoundException();
return mapping.findForward("success");
}
}
####error.jsp
errors.data.notfound=Data Not Found
6.3 <plug-in>
Defines a plugin that Struts loads at application startup and unloads at application shutdown.
Each plugin class must implement Struts’ org.apache.struts.action.PlugIn interface. Upon application
startup, the plugin’s init( ) method will be called. Upon application shutdown, the plugin’s destroy( )
method will be called
<plug-in className="org.apache.struts.tiles.TilesPlugin">
<set-property property="definitions-config" value="/WEB-INF/tiles-defs.xml"/>
<set-property property="moduleAware" value="true"/>
</plug-in>
At run time, when Struts parses a configuration file with a definition similar to this, it will use reflection to
look up and invoke the setDefinitionsConfig( ) and setModuleAware( ) methods of the class specified by
the plug-in tag’s className attribute, passing them the defined values.
Step 1 – write a class that implements PlugIn interface
package org.test.plugin;
import javax.servlet.ServletException;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.action.PlugIn;
import org.apache.struts.config.ModuleConfig;
6.4 <data-sources>
As a rule, you should always use a connection pool to access a database. The DataSource interface is the
preferred way to implement a connection pool today. Many containers and database systems now bundle a
DataSource implmentation that you can use. Most often, the DataSource is made available through JNDI. The
JNDI approach makes it easy for your business classes to access the DataSource without worrying about who
set it up.
<data-sources>
<data-source
type="com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource">
<set-property property="url"
value="jdbc:mysql://127.0.0.1:3306/student" />
<set-property property="user" value="root" />
<set-property property="password" value="root" />
<set-property property="maxCount" value="5" />
<set-property property="driverClass"
value="com.mysql.jdbc.Driver" />
<set-property property="minCount" value="1" />
</data-source>
</data-sources>
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
DataSource ds = getDataSource(request);
Connection conn = ds.getConnection();
if (conn != null) {
// access the database
System.out.println("we got the connection and class is "
+ conn.getClass().getName());
}
return mapping.findForward("success");
6.5 <form-beans>
<form-beans>
<form-bean name="helloForm" type="org.test.HelloForm" />
<form-bean name="userForm" type="org.test.UserForm" />
</form-beans>
When HTML forms are submitted to a Struts application, Struts takes the incoming form data and uses it to
populate the form’s corresponding Form Bean. The Struts Controller layer then uses the Form Beans to access
data that must be sent to the Model layer. On the flip side, the Controller layer populates Form Beans with
Model layer data so that it can be displayed with the View layer. Essentially, Form Beans are simple data
containers. They either contain data from an HTML form that is headed to the Model via the Controller or
contain data from the Model headed to the View via the Controller.
In hello.jsp we used <html:form> tag in which action /hello is associated with hello form bean because it
provides name=”helloForm” attribute in struts-config.xml.
<html:form action="/hello.do">
<bean:message key="hello.msg.label" />
<html:text property="msg" />
<br/>
<html:checkbox property="override">Do you want to override the default
message!!!</html:checkbox>
<br/>
<html:submit />
</html:form>
if (override) {
System.out.println("I have deselected the checkbox but still this if
block is running");
}
if (msg != null && msg.length() == 0) {
// add the error message
Sumit Agarwal (MCA Gold Medalist), mail me at jexperts@gmail.com
25
Asking is Good, so keep it up!!!
Now deselect the checkbox and press submit button and see the message on tomcat screen
First reset message appears because when form bean is created, resetted then putted into hello.jsp, second reset
message appears when we clicked submit button, /hello.do action will get called (associated form bean is
created then resetted then populated with the alues given by user). But I have deselected the checkbox then how
if (override) {
System.out.println("I have deselected the checkbox but still this if block is
running");
}
block is executing?
Note - Browsers send the value of a check box only if it is checked when the HTML form is submitted so
nothing is sent for override property field, so no setter get called and if setter will not called then what will be
the default value of property override? Exactly wilt which you have initialized and that is
private boolean override = true;
So now you know why the above if() get executed. What to do for overcome with this problem? Yes override
the reset method because it will executed before populating the value from request and irrespective of what are
the values are coming into request.
public void reset(ActionMapping mapping, HttpServletRequest request) {
So uncomment this override = false; the if block will not get executed.
Here we perform the validation of the values provided by user as an input. You will be
wondering why such validation we are doing again, if we have already done this in
javascript? Think, if javascript was disabled in browser.
In validate we prepare error messages then put into ActionErrors, if ActionErrors is not
blank then controller forward us to resource given in input="/hello.jsp" otherwise
Action’s execute will get called.
Note - If you do not want to call validate() now then you can set validate="false” and
later in action we can call form.validate() any time.
An another benefit of the reset( ) method hook is that it offers a convenient place to reset data between requests
when using Form Beans that are stored in session scope. When Form Beans are stored in session scope, they
persist across multiple requests. This solution is most often used for wizard-style process flows. Sometimes it’s
necessary to reset data between requests, and the reset( ) method provides a convenient hook for doing this.
We can change the form bean scope in action mapping configuration scope=”session”
7. DynaActionForm
Dynamic Form Beans are an extension of Form Beans that allows you to specify their properties inside the
Struts configuration file instead of having to create a concrete class, with a getter and setter method for each
property. The concept of Dynamic Form Beans originated because many developers found it tedious to create
for every page a Form Bean that had a getter and setter method for each of the fields on the page’s HTML form.
Using Dynamic Form Beans allows the properties to be specified in a Struts configuration file. To change a
property, simply update the configuration file. No code has to be recompiled.
The following snippet illustrates how Dynamic Form Beans are configured in the Struts configuration file:
Dynamic Form Beans are declared in the same way as standard Form Beans, by using the form-bean tag. The
difference is that the type of the Form Bean specified with the form-bean tag’s type attribute must be
org.apache.struts.action.DynaActionForm or a subclass thereof. Additionally, the properties for Dynamic
Form Beans are specified by nesting form-property tags beneath the form-bean tag. Each property specifies
its name and class type. Additionally, an initial value for the property can be specified using the form-property
tag’s initial attribute, as shown next:
If an initial value is not supplied for a property, Struts sets the initial value using Java’s initialization
conventions. That is, numbers are set to zero and objects are set to null.
Because you declare Dynamic Form Beans in the Struts configuration file instead of creating concrete classes
that extend ActionForm, you do not define reset( ) or validate( ) methods for the Dynamic Form Beans. The
reset( ) method is no longer necessary for setting default values because the initial attribute on the form-
property tag achieves the same effect. The DynaActionForm class’s implementation of the reset( ) method
resets all properties to their initial value when it is called. You can either code the functionality of the validate(
) method inside action classes or use the Validator framework for validation. These two options eliminate the
need to create a validate( ) method on the Form Bean. If, however, you have a special case where you need to
have an implementation of the reset( ) and/or validate( ) method for your Dynamic Form Bean, you can
subclass DynaActionForm and create the methods there. Simply specify your DynaActionForm subclass as
the type of the Form Bean in the Struts configuration file to use it.
8. Validator Framework
The Validator framework is set up as a pluggable system of validation routines that can be applied to Form
Beans. Each validation routine is simply a Java method that is responsible for performing a specific type of
validation and can either pass or fail. By default, Validator comes packaged with several useful validation
routines that will satisfy most validation scenarios. However, if you need a validation that is not provided by the
framework, you can create your own custom validation routine and plug it into the framework.
So by using this you make your validations configurable. Let’s see by an example.
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property property="pathnames" value="/WEB-INF/validator-rules.xml,
/WEB-INF/validation.xml"/>
</plug-in>
Step 2 – create a form bean class that will extend from ValidatorForm instead of ActionForm.
package org.test;
import org.apache.struts.validator.ValidatorForm;
Step 3 - You configure this Form Bean in the struts-config.xml file the same way you would a regular Form
Bean, as shown here:
Note – if you do not want to create a form bean class specially then you can use DynaValidatorForm.
<form-beans>
<form-bean name="loginForm"
type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="username" type="java.lang.String"/>
<form-property name="password" type="java.lang.String"/>
</form-bean>
</form-beans>
<form name="loginForm">
<field property="username" depends="required">
<arg key="loginForm.username" />
</field>
<field property="password" depends="required,mask">
<arg key="Password" resource=”false”/> no property file will be used
<var>
<var-name>mask</var-name>
<var-value>^[0-9a-zA-Z]*$</var-value>
</var>
</field>
</form>
Based on the type of Form Bean being validated, Validator will attempt to match the name either against a Form
Bean's logical name or against an action's path. Inside the <form> element, <field> elements are used to define
the validations that will be applied to specified Form Bean fields. The <field> element's property attribute
corresponds to the name of a field in the specified Form Bean. The depends attribute specifies the logical
names of validation routines from the validator-rules.xml file that should be applied to the field. The
validations specified with the depends attribute will be performed in the order specified and they all must pass.
Notice that each message has placeholders in the form of {0}, {1}, or {2}. At run time, the placeholders will be
substituted for another value such as the name of the field being validated. This feature is especially useful in
allowing you to create generic validation error messages that can be reused for several different fields of the
same type.
errors.required={0} is required.
When you use the required validation in the validation.xml file, you have to define the value that should be
used to substitute {0} in the error message:
<form name="auctionForm">
<field property="bid" depends="required">
<arg0 key="prompt.bid"/>
</field>
</form>
Sumit Agarwal (MCA Gold Medalist), mail me at jexperts@gmail.com
30
Asking is Good, so keep it up!!!
When using ValidatorForm or DynaValidatorForm based Form Beans, Validator uses the logical name for
the Form Bean from the struts-config.xml file to map the Form Bean to validation definitions in the
validation.xml file. This mechanism is ideal for most cases; however, there are scenarios where Form Beans
are shared among multiple actions. One action may use all the Form Bean's fields and another action may use
only a subset of the fields. Because validation definitions are tied to the Form Bean, the action that uses only a
subset of the fields has no way of bypassing validations for the unused fields. When the Form Bean is validated,
it will generate error messages for the unused fields because Validator has no way of knowing not to validate
the unused fields; it simply sees them as missing or invalid.
To solve this problem, Validator provides two additional ActionForm subclasses that allow you to tie
validations to actions instead of Form Beans. That way you can specify which validations to apply to the Form
Bean based on which action is using the Form Bean. For concrete Form Beans, you subclass
org.apache.struts.validator.ValidatorActionForm, as shown here:
<form-bean name="addressForm"
type="org.apache.struts.validator.DynaValidatorActionForm">
…
</form-bean>
Inside your validation.xml file, you map a set of validations to an action path instead of a Form Bean name,
because if you have two actions defined, Create Address and Edit Address, which use the same Form Bean, as
shown here, each has a unique action path:
<action-mappings>
<action path="/createAddress"
type="com.jamesholmes.minihr.CreateAddressAction"
name="addressForm"/>
<action path="/editAddress"
type="com.jamesholmes.minihr.EditAddressAction"
name="addressForm"/>
</action-mappings>
The following validation.xml file snippet shows two sets of validations that are intended for the same Form
Bean, but are distinguished by different action paths:
<formset>
<form name="/createAddress">
<field property="city" depends="required">
<arg0 key="prompt.city"/>
</field>
</form>
<form name="/editAddress">
<field property="state" depends="required">
<arg0 key="prompt.state"/>
</field>
</form>
</formset>
9 Struts Tiles
Tiles allows you to exploit the concept of JSP includes by providing a framework for defining and dynamically
populating page layouts.
Each page layout is simply a JSP that defines a template frame (or outline) with placeholders for where content
should go. At run time, Tiles replaces the placeholders with their associated content, creating a complete page
and unique instance of the layout. To accomplish this, Tiles uses its concepts of definitions and attributes
header.jsp
layout.jsp
body.jsp
menu.jsp
footer.jsp
A Tiles definition creates a piece of content that Tiles can insert into a JSP using that definition’s name. Each
definition consists of a name (or identifier), a layout JSP, and a set of attributes associated with the definition.
Once defined, a definition can be included in a page or, as is most often the case, be used as the target of Struts
forward. In both cases, when the definition is encountered, Tiles passes to the layout JSP specified by the
definition the set of attributes that were declared for that definition. An attribute value can be the path to a JSP,
a literal string, or a list of either.
To facilitate the use of definitions and attributes, Tiles uses an XML configuration file (tiles-defs.xml) for
storing their definitions. Tiles also provide a JSP tag library for defining definitions and attributes. Additionally,
the Tiles Tag Library is used for inserting attributes into JSPs.
Using Tiles - Using the Tiles framework involves these five steps:
The first, and most often used, way that you can define Tiles definitions and attributes is by placing them in an
XML configuration file named tiles-defs.xml.
<tiles-definitions>
<definition name="search.page" path="/mainLayout.jsp">
<put name="header" value="/header.jsp"/>
<put name="body" value="/search.jsp"/>
<put name="footer" value="/footer.jsp" />
</definition>
</tiles-definitions>
Each definition in the tiles-defs.xml file has its own definition that is declared with a definition tag. The
definition tag assigns a logical name to the definition, with the name attribute, and specifies the path to a layout
JSP for the definition, with the path attribute. The logical name given to the definition will be used to refer to
the definition inside JSPs and the Struts configuration file. Nested inside the definition tag, put tags are used to
specify the definition's list of attributes.
This definition will be stored in a page scope JSP variable named search.page (as specified by the id attribute
of the definition tag) so that it can be accessed from other tags. To use this JSP-based definition, you must use
Tiles' insert tag, as shown next:
Extending Definitions
This functionality is similar to the way inheritance works in Java. When defining a definition, you can specify
that the definition extends another definition, instead of specifying a layout JSP for the definition.
<tiles-definitions>
</tiles-definitions>
//mainLayout.jsp
<html>
<head>
<title><tiles:getAsString name="title"/></title>
</head>
<body>
<tiles:insert attribute="header"/>
<table>
Sumit Agarwal (MCA Gold Medalist), mail me at jexperts@gmail.com
35
Asking is Good, so keep it up!!!
<tr>
<td width="20%"><tiles:insert attribute="menu"/></td>
<td width="80%"><tiles:insert attribute="body"/></td>
</tr>
</table>
<tiles:insert attribute="footer"/>
</body>
</html>
At run time, when a definition uses this layout, it will make a set of attributes available to the page to be
inserted with the Tiles Tag Library's insert tag.
Content JSPs are used to fill in the placeholders created by layouts. These JSPs simply contain the HTML
necessary to fill in a specific section of a layout. You create these JSPs the same way you would create JSPs
that are used for includes. You don't, however, specifically source in any of these JSPs into the layout JSPs, as
you would if you were using includes. Instead, layout JSPs use Tiles tags to insert attributes whose values point
to these content JSPs.
Once you have created Tiles layout JSPs and have defined definitions that use them, you can put the definitions
to use. There are two different ways to use definitions:
The following example illustrates how to insert a Tiles definition into a JSP:
<html>
<head><title>Employee Search</title></head><body>
Notice that the path attribute specifies the name of a Tiles definition. The Tiles request processor will recognize
this and handle processing for this forward. Similarly, for local forwards you can use tiles definition name.
We can reduce the number of action mappings by combining similar action mappings into a single generic
mapping.
many applications use standard conventions for naming action paths, Action classes, and ActionForms, making
their application easier to organize and maintain. Struts 1.2 allows you to leverage these conventions in your
struts-config.xml file. Create your action elements using an asterisk (*) as a wildcard in the path attribute. When
Struts finds the action mapping for a given request path, it attempts to find an exact match. If an exact match is
not found, it attempts a match using the wildcards.
Now if we use some conventions for naming action paths, Action classes, and ActionForms then we do not
require to create seprate mapping for /EditStudent, /EditVendor, /EditProject etc. * will be matched to Student,
Vendor, Project and {1} will be replaced with this matched value. What we need to care the files with matching
names must exist.
The action element attributes that can use wildcard-matched strings via the {n} notation are the following:
• type
• name
• roles
• parameter
• attribute
• forward
• include
• input
11 Struts Token
You need to stop users from inadvertently submitting a form twice Use the Struts token facility to reject a
duplicate request.
1. Before you load the JavaServer Pages (JSP) page that has the html:form tag on it, call saveToken inside
an action.
2. When the user submits the form, call isTokenValid and handle the form only if the token is valid.
// save a token
saveToken(request);
return mapping.findForward("success");
}
}
// save data
BusinessService.saveData( );
}
else {
ActionErrors errors = new ActionErrors( );
errors.add(ActionErrors.GLOBAL_ERROR, new ActionError("Invalid token"));
saveErrors(request, errors);
return mapping.getInputForward();
}
return mapping.findForward("success");
}
}
Trick - When the form is rendered on the JSP page, Struts generates an HTML hidden field containing the
token value. You can generate the token value as request parameter on a hyperlink by setting
transaction=true on the html:link tag. The token value, whether rendered as a hidden field or a request
parameter, is only generated if a token is found in the current request for the JSP.