Struts Survival Guide
User Manual:
Open the PDF directly: View PDF
.
Page Count: 227
| Download | |
| Open PDF In Browser | View PDF |
S t ru t s
S u rv i v a l G u i d e
Ba s i c s t o Be s t P r a c t i c e s
Covers Struts 1.1
Srikanth Shenoy
Austin
2
ObjectSource LLC books are available for bulk purchases for corporations and other organizations.
The publisher offers discounts when ordered in bulk. For more information please contact:
Sales Department
ObjectSource LLC.
2811 La Frontera Blvd., Suite 517
Austin, TX 78728
Email: sales@objectsource.com
First corrected reprint Copyright ©2004,2005 ObjectSource LLC. All rights reserved.
All rights reserved. No part of this publication may be reproduced, stored in a retrieval system or
transmitted in any form or by any means electronic, mechanical, photocopying, recording or
otherwise, without the prior written permission of the publisher.
Many of the designations used by manufacturers and sellers to distinguish their products are claimed
as trademarks. Where those designations appear in this book, and ObjectSource LLC, was aware of
a trademark claim, the designations have been printed in initial capital letters.
The author and the publisher have taken care in preparation of this book, but make no express or
implied warranty of any kind and assume no responsibility for errors or omissions. In no event shall
the ObjectSource LLC or the authors be liable for any direct, indirect, incidental, special, exemplary or
consequential damages (including, but not limited to, procurement of substitute goods or services;
loss of use, data, or profits; or business interruption) however caused and on any theory of liability,
whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of
use of the information or programs contained herein.
Published by
ObjectSource LLC
2811 La Frontera Blvd., Suite 517,
Austin TX 78728
Printing
RJ Communications
nd
51 East 42 Street, Suite 1202,
NewYork NY 10017
Cover Design
Matt Pramschufer
Budget Media Design
Pleasantville, New York
Library of Congress Catalog Number: 2004100026
ISBN: 0-9748488-0-8 (paperback)
Printed in the United States of America
3
4
5
Table of Contents
Chapter 1. Getting Started ..........................................................................................15
J2EE Platform
15
J2EE web application
16
JSPs
Error! Bookmark not defined.
1.1 Model 1 Architecture
20
Problems with Model 1 Architecture
20
1.2 Model 2 Architecture - MVC
21
Advantages of Model 2 Architecture
22
Controller gone bad – Fat Controller
23
1.3 MVC with configurable controller
23
1.4 First look at Struts
25
1.5 Tomcat and Struts installation
28
1.6 Summary
28
Chapter 2. Struts Framework Components...............................................................30
2.1 Struts request lifecycle
31
ActionServlet
31
RequestProcessor and ActionMapping
33
ActionForm
34
Action
35
ActionForward
36
ActionErrors and ActionError
37
2.2 Struts Configuration File – struts-config.xml
39
2.3 View Components
42
How FormTag works
43
How ErrorsTag works
45
2.4 Summary
47
Chapter 3. Your first Struts application ....................................................................48
3.1 Introduction
48
3.2 Hello World – step by step
49
3.3 Lights, Camera, Action!
61
3.4 Handling multiple buttons in HTML Form
63
3.5 Value replacement in Message Resource Bundle
65
3.6 Summary
67
Chapter 4. All about Actions .......................................................................................68
4.1 ForwardAction
68
MVC compliant usage of LinkTag
69
Using LinkTag’s action attribute
70
Using LinkTag’s forward attribute
70
Using ForwardAction for Integration
71
ForwardAction Hands-on
72
4.2 Protecting JSPs from direct access
72
4.3 IncludeAction
75
4.4 DispatchAction
76
4.5 LookupDispatchAction
80
4.6 Configuring multiple application modules
82
4.7 Roll your own Base Action and Form
85
4.8 Handling Duplicate Form Submissions
88
4.9 What goes into Action (and what doesn’t)
91
4.10 When to use Action chaining (and when not to)
93
6
4.11 Actions for complex transitions
94
Wiring the handlers
94
State aware Forms
95
4.12 Managing struts-config.xml
96
Struts-GUI
96
Struts Console
96
XDoclet
97
4.13 Guidelines for Struts Application Development
98
4.14 Summary
99
Chapter 5. Form Validation ......................................................................................101
5.1 Using Commons Validator with Struts
102
The twin XML files
102
validation-rules.xml – The global rules file
103
validation.xml – The application specific rules file
104
More validation.xml features
106
Using the ValidationForm
108
Configuring the Validator
108
Steps to use Commons Validator in Struts
109
5.2 DynaActionForm – The Dynamic ActionForm
109
DynaValidatorForm
113
5.3 Validating multi-page forms
113
5.4 Validating form hierarchy
116
5.5 Summary
117
Chapter 6. Struts Tag Libraries................................................................................119
6.1 Struts HTML Tags
120
Modifying the Base Tag
120
Form Tag
122
FileTag
122
Smart Checkbox – The state aware checkbox
123
Using CSS with Struts HTML Tags
125
Enhancing the error display with customized TextTag
125
The recommended way to use ImgTag
129
6.2 Using Images for Form submissions
130
ImageButton and JavaScript
133
6.3 Struts Bean Tags
134
Message Tag and Multiple Resource Bundles
134
Write Tag
135
6.4 Struts Logic Tags
135
Nested Logic Tags
136
Iterate Tag
137
6.5 A crash course on JSTL
138
JSTL Binaries – Who’s who
141
6.6 Struts-EL
141
Struts-EL hands-on
142
Practical uses for Struts-EL
143
6.7 List based Forms
143
6.8 Multi-page Lists and Page Traversal frameworks
147
Pager Taglib
148
DisplayTag and HtmlTable frameworks
149
Creating the Model for iteration
150
7
6.9 Summary
153
Chapter 7. Struts and Tiles........................................................................................154
7.1 What is Tiles
154
7.2 Your first Tiles application
157
Step 1: Creating the Layout
158
Step 2: Creating the XML Tile definition file
159
Step 3: Modifying the forwards in struts-config.xml
160
Step 4: Using TilesRequestProcessor
161
Step 5: Configuring the TilesPlugIn
161
7.3 Tiles and multiple modules
163
7.4 Summary
163
Chapter 8. Struts and I18N........................................................................................164
Terminology
164
What can be localized?
165
8.1 The Java I18N and L10N API
166
Accessing Locale in Servlet Container
167
8.2 Internationalizing Struts Applications
171
8.3 Internationalizing Tiles Applications
173
8.4 Processing Localized Input
174
8.5 Character encodings
175
Struts and character encoding
177
native2ascii conversion
178
8.6 Summary
179
Chapter 9. Struts and Exception Handling ..............................................................181
9.1 Exception Handling Basics
182
9.2 Log4J crash course
183
9.3 Principles of Exception Handling
184
9.4 The cost of exception handling
187
9.5 JDK 1.4 and exception handling
188
9.6 Exception handling in Servlet and JSP specifications
189
9.7 Exception handling – Struts way
191
Declarative exception handling
191
Using the ExceptionHandler
193
When not to use declarative exception handling
194
Exception handling and I18N
196
9.8 Logging Exceptions
196
9.9 Strategies for centralized logging
202
9.10 Reporting exceptions
206
9.11 Summary
208
Chapter 10. Effectively extending Struts..................................................................209
Customizing the action mapping
211
10.1 A rudimentary page flow controller
213
10.2 Controlling the validation
215
10.3 Controlling duplicate form submissions
218
10.4 DispatchAction for Image Button form submissions
222
10.5 Summary
224
8
Preface
I started using Struts in late 2000. I was immediately drawn to its power and ease
of use. In early 2001, I landed in a multi-year J2EE project, a large project by any
measures. Struts 1.0 was chosen as the framework for the web tier in that project.
Recently that project upgraded to Struts 1.1. I did the upgrade over a day. It
cannot get any easier!
This book makes no assumptions about your Struts knowledge. It starts with
the basics of Struts, teaches you what is important in Struts from a usage
perspective and covers a lot of practical issues all in a short 200-page book. No
unnecessary explanations. Concise, Clear and straight to the topic.
I am a consultant, not an author by profession. Hence my writing also tends
to reflect my mindset that got shaped by the various assignments I have
undertaken in the past. Large projects and their inbuilt complexities excite me. In
large projects, decoupling layers is a big thing. Also minor decisions during
architecting and designing (probably without the complete knowledge of the
framework used) can impact the project in a big way down the line. Clearly
understanding the strengths and shortcomings of a framework and minor
customizations to the framework go a long way in making the applications
cleaner. In that perspective, I have attempted to give a practical face to this book
based on my experience. Chapters 4, 5, 6, 9 and 10 will be extremely valuable to
all those wishing to use Struts effectively in J2EE projects.
Chapter 9 is based on my article originally published in IBM
developerWorks in May 2002 on Best practices in EJB Exception handling
(http://www-106.ibm.com/developerworks/java/library/j-ejbexcept.html).
This
chapter borrows some of the core concepts from that article and extends and
improvises them to specifically suit the needs of a Struts web application.
I have enjoyed a lot writing this book. Even though I knew Struts well, there
were some crevices that I had not explored and have made me that much better.
If you are a beginner, this book is your fastest track to master Struts. There are a
lot of best practices and strategies related to Struts that makes this book valuable
to even experienced developers and architects.
Srikanth Shenoy
January 2004
9
10
Acknowledgements
A good book is the end result of the efforts of many. For the first edition,
Sandeep Nayak helped by agreeing to be a beta reader and pointing out the
problems in the initial two chapters. The first edition also owes debt to Fulco
Houkes from Neuchâtel, Switzerland who reviewed the book and tried parts of
the source code to ensure it is working.
Likewise I am indebted to booksjustbooks.com, for making their book on
Publishing basics available freely online without which this book wouldn’t have
been a reality. Thanks to RJ Communications for printing this book. Many
thanks to Matt Pramschufer from Budget Media Design for the cover design.
I would like to thank Amazon.com for being a small publisher friendly
retailer. It is impossible to sell the books without having the reach as Amazon
does. This books comes from a independent small publisher lacking the
distribution network that big publishers possess. Hadn't it for Amazon, the first
edition of this book would still be lying in my warehouse and I would not have
been able to offer this ebook free of cost.
I owe thanks to my wife for patiently putting up with me when I was
working evenings and weekends on the book and also editing the book. I also
owe thanks and gratitude to my parents who showed the right path as I was
growing up and instilled in me the passion for perfection, courage to achieve
anything and never give up.
Finally thanks to God through whom all things are made possible.
Srikanth Shenoy
March 2005
11
12
Where to get the Source Code for the book
The source code for this book can be downloaded from the website
http://www.objectsource.com.
Specifically the link for the examples is http://www.objectsource.com/strutssurvival-guide-examples.zip, which also includes a companion workbook for this
Survival Guide. The workbook illustrates the concepts with step by step
instructions.
Also don’t forget to download the PDF slides used in a short Struts Training.
It is located at http://www.objectsource.com/Struts_for_J2EE_DevelopersObjectSource_Training_Material.zip.
13
Author Profile
Srikanth Shenoy is the co-founder and chief mentor at ObjectSource LLC.
ObjectSource is a Austin, TX based company providing J2EE training and
consulting that also publishes great technical books. Srikanth has over 10 years
of experience in the software industry. Previously he worked as J2EE Consultant
and Architect for J2EE and CORBA product vendors and large system
integrators. He has helped clients in the manufacturing, logistics, and financial
sectors to realize the Java's "write once, run anywhere" dream. He has written
articles and papers for IBM developerWorks, The SerververSide and so on
ranging from topics such as EJBs to JavaServer Faces and Maven. Most recently
he created the OTOM framework (http://otom.dev.java.net) - a Java Tool that
allows graphical mapping of one object to another and subsequent code
generation. He also contributes to several other Open Source projects. He can be
reached at shenoy@objectsource.com.
ObjectSource LLC, provides solutions and services including architecture &
design, strategic architecture review, consulting in areas such as J2EE
applications, O-R Mapping (specifically TopLink and Hibernate) and training on
topics such as J2EE, Struts, Hibernate, TopLink, JavaServer Faces and Spring.
14
Struts Survival Guide – Basics to Best Practices
Chapter 1. Getting Started
15
Ch a p te r 1
Getting Started
In this chapter:
1. You will learn about Model 1 and Model 2 (MVC) and their differences.
2. You will understand the shortcomings of Model 1.
3. You will understand the problems with Model 2 – The Fat Controller Antipattern.
4. You will learn how to overcome the problems in Model 2 by using Model
2 with a configurable controller.
5. You will see how Struts fill the gap by providing the configurable
controller and much more to boost developer productivity.
6. You will look at installing Tomcat and Struts on your computer.
What is Struts?
Struts is a Java MVC framework for building web applications on the J2EE
platform.
That’s it! As you can see, whole lot of buzzwords appear in the above sentence.
This chapter analyzes the above definition word-by-word and presents a big
picture of Struts. It also shows how Struts makes it easy to develop web
applications for the J2EE platform. But first, I will start with a quick overview of
the J2EE platform followed by basics of J2EE web application development
before looking at various strategies and frameworks that are available today for
developing the J2EE presentation tier.
J2EE Platform
As you might be already knowing, J2EE is a platform for executing server
side Java applications. Before J2EE was born, server side Java applications were
written using vendor specific APIs. Each vendor had unique APIs and
architectures. This resulted in a huge learning curve for Java developers and
architects to learn and program with each of these API sets and higher costs for
the companies. Development community could not reuse the lessons learnt in the
16
Struts Survival Guide – Basics to Best Practices
trenches. Consequently the entire Java developer community was fragmented,
isolated and stunted thus making very difficult to build serious enterprise
applications in Java.
Fortunately the introduction of J2EE and its adoption by the vendors has
resulted in standardization of its APIs. This in turn reduced the learning curve for
server side Java developers. J2EE specification defines a whole lot of interfaces
and a few classes. Vendors (like BEA and IBM for instance) have provided
implementations for these interfaces adhering to the J2EE specifications. These
implementations are called J2EE Application Servers.
The J2EE application servers provide the infrastructure services such as
threading, pooling and transaction management out of the box. The application
developers can thus concentrate on implementing business logic. Consider a
J2EE stack from a developer perspective. At the bottom of the stack is Java 2
Standard Edition (J2SE). J2EE Application Servers run in the Java Virutal
Machine (JVM) sandbox. They expose the standard J2EE interfaces to the
1
application developers. Two types of applications can be developed and
deployed on J2EE application servers – Web applications and EJB applications.
These applications are deployed and executed in “container”s. J2EE specification
defines containers for managing the lifecycle of server side components. There
are two types of containers - Servlet containers and EJB containers. Servlet
containers manage the lifecycle of web applications and EJB containers manage
the lifecycle of EJBs. Only Servlet containers are relevant to our discussion as
Struts, the theme of this book, is a web application framework.
J2EE web application
Any web application that runs in the servlet container is called a J2EE web
application. The servlet container implements the Servlet and JSP specification.
It provides various entry points for handling the request originating from a web
browser. There are three entry points for the browser into the J2EE web
application - Servlet, JSP and Filter. You can create your own Servlets by
extending the javax.servlet.http.HttpServlet class and implementing
the doGet() and doPost() method. You can create JSPs simply by creating a
text file containing JSP markup tags. You can create Filters by implementing the
javax.servlet.Filter interface.
The servlet container becomes aware of Servlets and Filters when they are
2
declared in a special file called web.xml . A J2EE web application has exactly
1
There are actually three types of applications that can be developed and deployed on
J2EE app servers. The third one is a application conforming to J2EE Connector
Architecture (J2CA). However I will leave this out for simplicity.
2
There are various kinds of Listeners that you can declare in web.xml. You can also
declare Tag Library Definitions (TLD) in web.xml. More details can be found in the
Servlet Specification. Again, I am leaving this out for simplicity.
Chapter 1. Getting Started
17
one web.xml file. The web application is deployed into the servlet container by
bundling it in zipped archive called Web ARchive – commonly referred to as
WAR file.
Listing 1.1 Sample doGet() method in a Servlet handling HttpRequest
public class MyServlet extends HttpServlet {
public void doGet(HttpServletRequest httpRequest,
HttpServletResponse httpResponse)
throws ServletException, IOException {
//Extract data from Http Request Parameters
//Business Logic goes here
//Now write output HTML
OutputStream os = httpResponse.getOutputStream();
os.println(“”);
//Write formatted data to output stream
os.println(“”);
os.flush();
os.close();
}
}
A servlet is the most basic J2EE web component. It is managed by the servlet
container. All servlets implement the Servlet interface directly or indirectly. In
general terms, a servlet is the endpoint for requests adhering to a protocol.
However, the Servlet specification mandates implementation for servlets that
handle HTTP requests only. But you should know that it is possible to implement
the servlet and the container to handle other protocols such as FTP too. When
writing Servlets for handling HTTP requests, you generally subclass HttpServlet
class. HTTP has six methods of request submission – GET, POST, PUT, HEAD
and DELETE. Of these, GET and POST are the only forms of request submission
relevant to application developers. Hence your subclass of HttpServlet should
implement two methods – doGet() and doPost() to handle GET and POST
respectively. Listing 1.1 shows a doGet() method from a typical Servlet.
With this background, let us now dive straight into presentation tier
strategies. This coverage of presentation tier strategies will kick start your
thought process on how and where Struts fits in the big picture.
1.1 Presentation Tier Strategies
Technologies used for the presentation tier can be roughly classified into three
categories:
18
Struts Survival Guide – Basics to Best Practices
Markup based Rendering (e.g. JSPs)
Template based Transformation (e.g. Velocity, XSLT)
Rich content (e.g. Macromedia Flash, Flex, Laszlo)
Markup based Rendering
JSPs are perfect examples of markup based presentation tiers. In markup based
presentation, variety of tags are defined (just like HTML tags). The tag
definitions may be purely for presentation or they can contain business logic.
They are mostly client tier specific. E.g. JSP tags producing HTML content. A
typical JSP is interpreted in the web container and the consequent generation of
HTML. This HTML is then rendered in the web browser. The next few
paragraphs cover the role played by JSPs in comparison to Servlets in J2EE web
application.
In the last section, you saw how Servlets produced output HTML in addition
to executing business logic. So why aren’t Servlets used for presentation tier?
The answer lies in the separation of concerns essential in real world J2EE
projects. Back in the days when JSPs didn’t exist, servlets were all that you had
to build J2EE web applications. They handled requests from the browser,
invoked middle tier business logic and rendered responses in HTML to the
browser. Now that’s a problem. A Servlet is a Java class coded by Java
programmers. It is okay to handle browser requests and have business and
presentation logic in the servlets since that is where they belong. HTML
formatting and rendering is the concern of page author who most likely does not
know Java. So, the question arises, how to separate these two concerns
intermingled in Servlets? JSPs are the answer to this dilemma. JSPs are servlets
in disguise!
The philosophy behind JSP is that the page authors know HTML. HTML is a
markup language. Hence learning a few more markup tags will not cause a
paradigm shift for the page authors. At least it is much easier than learning Java
and OO! JSP provides some standard tags and java programmers can provide
custom tags. Page authors can write server side pages by mixing HTML markup
and JSP tags. Such server side pages are called JSPs. JSPs are called server side
pages because it is the servlet container that interprets them to generate HTML.
The generated HTML is sent to the client browser.
Presentation Logic and Business Logic – What’s the difference?
The term Business Logic refers to the middle tier logic – the core of the system
usually implemented as Session EJBs. The code that controls the JSP
navigation, handles user inputs and invokes appropriate business logic is
referred to as Presentation Logic. The actual JSP – the front end to the user
Chapter 1. Getting Started
19
contains html and custom tags to render the page and as less logic as possible.
A rule of thumb is the dumber the JSP gets, the easier it is to maintain. In
reality however, some of the presentation logic percolates to the actual JSP
making it tough to draw a line between the two.
We just said JSPs are server side pages. Server side pages in other languages
are parsed every time they are accessed and hence expensive. In J2EE, the
expensive parsing is replaced by generating Java class from the JSP. The first
time a JSP is accessed, its contents are parsed and equivalent Java class is
generated and subsequent accesses are fast as a snap. Here is some twist to the
story. The Java classes that are generated by parsing JSPs are nothing but
Servlets! In other words, every JSP is parsed at runtime (or precompiled) to
generate Servlet classes.
Template based Transformation
In Template based transformation, a template engine uses a pre-defined template
to transform a given data model into desired output.
XSLT is a perfect example for template based transformation. XSLT stands
for XML Stylesheet Language Transformation. XSLT is used to transform an
XML document in one format into another XML document in another format.
Since HTML is a type of XML, XSLT can be used for generating HTML from
XML. In a J2EE application, J2EE components can generate XML that
represents the data. Then the XML is transformed into HTML
(presentation/view) by using a stylesheet written using the XML Stylesheet
Language (XSL).
Velocity is another fantastic example of template based transformation
mechanism to generate the view. In fact Velocity is a general purpose Templating
framework that can be used to generate almost anything, not just a replacement
for
JSPs.
For
more
information
on
Velocity
check
out
http://jakarta.apache.org/velocity. Velocity with Struts is not covered in this
edition of the book.
Rich Content in Rich Internet Applications (RIA)
Rich content delivery over the internet to the good old browser is not an entirely
new paradigm, but something that’s drawing a lot of attention lately. The
traditional browser’s presentation capabilities are fairly limited even with the
addition of DHTML and JavaScript. In addition, the browser incompatibilities
cause a lot of headache for developing rich application with just DHTML and
JavaScript.
Enter, Macromedia Flash, a freely available plugin for all the popular
browsers that can render the rich content uniformly across all browsers and
operating systems. This strategy can be of interest to Struts developers because
20
Struts Survival Guide – Basics to Best Practices
Macromedia has also released Flex – a presentation tier solution to deliver
internet applications with rich content using Struts.
Laszlo is another platform to deliver rich internet applications. Laszlo
renders contents using the same flash player, but it is open source. It can be
integrated with Struts too.
NOTE: Struts can be used as the controller framework for any of the view
generation strategies described above. Struts can be combined with JSPs – the
most popular option among developers. Struts can also be combined with
Velocity templating or XSLT. Struts is also an integral part of Macromedia
Flex. Lazlo and Struts can be combined to deliver rich internet applications.
So far, we have looked at various strategies that can be applied in the
presentation tier to generate the view. We also saw that Struts can play an
effective role in each of these strategies as a controller. Well, I didn’t explain
exactly how it plays the role of a controller. It is the topic of next few sections.
We will start by introducing the two modes of designing JSPs - Model 1 and
Model 2 architectures in the next two sections and then arrive at Struts as an
improvement over the Model 2 architecture.
1.2 Model 1 Architecture
Model 1 architecture is the easiest way of developing JSP based web
applications. It cannot get any easier. In Model 1, the browser directly accesses
JSP pages. In other words, user requests are handled directly by the JSP.
Let us illustrate the operation of Model 1 architecture with an example.
Consider a HTML page with a hyperlink to a JSP. When user clicks on the
hyperlink, the JSP is directly invoked. This is shown in Figure 1.1. The servlet
container parses the JSP and executes the resulting Java servlet. The JSP contains
embedded code and tags to access the Model JavaBeans. The Model JavaBeans
contains attributes for holding the HTTP request parameters from the query
string. In addition it contains logic to connect to the middle tier or directly to the
database using JDBC to get the additional data needed to display the page. The
JSP is then rendered as HTML using the data in the Model JavaBeans and other
Helper classes and tags.
Problems with Model 1 Architecture
Model 1 architecture is easy. There is some separation between content
(Model JavaBeans) and presentation (JSP). This separation is good enough for
smaller applications. Larger applications have a lot of presentation logic. In
Model 1 architecture, the presentation logic usually leads to a significant amount
Chapter 1. Getting Started
21
of Java code embedded in the JSP in the form of scriptlets. This is ugly and
maintenance nightmare even for experienced Java developers. In large
applications, JSPs are developed and maintained by page authors. The
intermingled scriptlets and markup results in unclear definition of roles and is
very problematic.
Application control is decentralized in Model 1 architecture since the next
page to be displayed is determined by the logic embedded in the current page.
Decentralized navigation control can cause headaches. All this leads us to Model
2 architecture of designing JSP pages.
Figure 1.1 Model 1 Architecture.
1.3 Model 2 Architecture - MVC
The Model 2 architecture for designing JSP pages is in reality, Model View
Controller (MVC) applied to web applications. Hence the two terms can be used
interchangeably in the web world. MVC originated in SmallTalk and has since
made its way into Java community. Model 2 architecure and its derivatives are
the cornerstones for all serious and industrial strength web applications designed
in the real world. Hence it is essential for you understand this paradigm
thoroughly. Figure 1.2 shows the Model 2 (MVC) architecture.
The main difference between Model 1 and Model 2 is that in Model 2, a
controller handles the user request instead of another JSP. The controller is
implemented as a Servlet. The following steps are executed when the user
submits the request.
1. The Controller Servlet handles the user’s request. (This means the hyperlink
in the JSP should point to the controller servlet).
2. The Controller Servlet then instantiates appropriate JavaBeans based on the
request parameters (and optionally also based on session attributes).
3. The Controller Servlet then by itself or through a controller helper
22
Struts Survival Guide – Basics to Best Practices
communicates with the middle tier or directly to the database to fetch the
required data.
4. The Controller sets the resultant JavaBeans (either same or a new one) in one
of the following contexts – request, session or application.
5. The controller then dispatches the request to the next view based on the
request URL.
6. The View uses the resultant JavaBeans from Step 4 to display data.
Note that there is no presentation logic in the JSP. The sole function of the
JSP in Model 2 architecture is to display the data from the JavaBeans set in the
request, session or application scopes.
Figure 1.2 Model 2 Architecture.
Advantages of Model 2 Architecture
Since there is no presentation logic in JSP, there are no scriptlets. This means
lesser nightmares. [Note that although Model 2 is directed towards elimination of
scriptlets, it does not architecturally prevent you from adding scriptlets. This has
led to widespread misuse of Model 2 architecture.]
With MVC you can have as many controller servlets in your web application.
In fact you can have one Controller Servlet per module. However there are
several advantages of having a single controller servlet for the entire web
application. In a typical web application, there are several tasks that you want to
do for every incoming request. For instance, you have to check if the user
requesting an operation is authorized to do so. You also want to log the user’s
entry and exit from the web application for every request. You might like to
centralize the logic for dispatching requests to other views. The list goes on. If
you have several controller servlets, chances are that you have to duplicate the
Chapter 1. Getting Started
23
logic for all the above tasks in all those places. A single controller servlet for the
web application lets you centralize all the tasks in a single place. Elegant code
and easier to maintain.
Web applications based on Model 2 architecture are easier to maintain and
extend since the views do not refer to each other and there is no presentation
logic in the views. It also allows you to clearly define the roles and
responsibilities in large projects thus allowing better coordination among team
members.
Controller gone bad – Fat Controller
If MVC is all that great, why do we need Struts after all? The answer lies in
the difficulties associated in applying bare bone MVC to real world complexities.
In medium to large applications, centralized control and processing logic in the
servlet – the greatest plus of MVC is also its weakness. Consider a mediocre
application with 15 JSPs. Assume that each page has five hyperlinks (or five
form submissions). The total number of user requests to be handled in the
application is 75. Since we are using MVC framework, a centralized controller
servlet handles every user request. For each type of incoming request there is “if”
block in the doGet method of the controller Servlet to process the request and
dispatch to the next view. For this mediocre application of ours, the controller
Servlet has 75 if blocks. Even if you assume that each if block delegates the
request handling to helper classes it is still no good. You can only imagine how
bad it gets for a complex enterprise web application. So, we have a problem at
hand. The Controller Servlet that started out as the greatest thing next to sliced
bread has gone bad. It has put on a lot of weight to become a Fat Controller.
1.4 MVC with configurable controller
You must be wondering what went wrong with MVC. When application gets
large you cannot stick to bare bone MVC. You have to extend it somehow to deal
with these complexities. One mechanism of extending MVC that has found
widespread adoption is based on a configurable controller Servlet. The MVC
with configurable controller servlet is shown in Figure 1.3.
When the HTTP request arrives from the client, the Controller Servlet looks
up in a properties file to decide on the right Handler class for the HTTP request.
This Handler class is referred to as the Request Handler. The Request Handler
contains the presentation logic for that HTTP request including business logic
invocation. In other words, the Request Handler does everything that is needed to
handle the HTTP request. The only difference so far from the bare bone MVC is
that the controller servlet looks up in a properties file to instantiate the Handler
instead of calling it directly.
Struts Survival Guide – Basics to Best Practices
24
Figure 1.3 MVC with configurable controller Servlet.
Listing 1.1 Configurable Controller Servlet Implementation
public class MyControllerServlet extends HttpServlet {
private Properties props;
public init(ServletConfig config) throws ServletException {
try {
props = new Properties();
props.load(new FileInputStream("C:/file.properties"));
} catch (IOException ioe) {
throw new ServletException(ioe);
}
}
public void doGet(HttpServletRequest httpRequest,
HttpServletResponse httpResponse)
throws ServletException, IOException {
String urlPath = httpRequest.getPathInfo();
String reqhandlerClassName = (String) props.get(urlPath);
HandlerInterface handlerInterface = (HandlerInterface)
Class.forName(reqhandlerClassName).newInstance();
String nextView = handlerInterface.execute(httpRequest);
..
..
RequestDispatcher rd = getServletContext().
getRequestDispatcher(nextView);
rd.forward(httpRequest, httpResponse);
}
Chapter 1. Getting Started
25
}
At this point you might be wondering how the controller servlet would know
to instantiate the appropriate Handler. The answer is simple. Two different HTTP
requests cannot have the same URL. Hence you can be certain that the URL
uniquely identifies each HTTP request on the server side and hence each URL
needs a unique Handler. In simpler terms, there is a one-to-one mapping between
the URL and the Handler class. This information is stored as key-value pairs in
the properties file. The Controller Servlet loads the properties file on startup to
find the appropriate Request Handler for each incoming URL request.
The controller servlet uses Java Reflection to instantiate the Request Handler.
However there must be some sort of commonality between the Request Handlers
for the servlet to generically instantiate the Request Handler. The commonality is
that all Request Handler classes implement a common interface. Let us call this
common interface as Handler Interface. In its simplest form, the Handler
Interface has one method say, execute(). The controller servlet reads the
properties file to instantiate the Request Handler as shown in Listing 1.1.
The Controller Servlet instantiates the Request Handler in the doGet()
method and invokes the execute() method on it using Java Reflection. The
execute() method invokes appropriate business logic from the middle tier and
then selects the next view to be presented to the user. The controller servlet
forwards the request to the selected JSP view. All this happens in the doGet()
method of the controller servlet. The doGet() method lifecycle never changes.
What changes is the Request Handler’s execute() method. You may not have
realized it, but you just saw how Struts works in a nutshell! Struts is a controller
servlet based configurable MVC framework that executes predefined methods in
the handler objects. Instead of using a properties file like we did in this example,
Struts uses XML to store more useful information.
1.4 First look at Struts
In the last section, you have seen the underlying principle behind Struts
framework. Now let us look closely at the Struts terminology for controller
servlet and Handler objects that we mentioned and understand Figure 1.4. Figure
1.4 is a rehash of Figure 1.3 by using Struts terminology. Since this is your first
look at Struts, we will not get into every detail of the HTTP request handling
lifecycle in Struts framework. Chapter 2 will get you there. For now, let us
concentrate on the basics.
Listing 1.2 Sample ActionForm
public class MyForm extends ActionForm {
private String firstName;
Struts Survival Guide – Basics to Best Practices
26
private String lastName;
public MyForm() {
firstName = “”; lastName = “”;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String s) {
this.firstName = s;
}
public String getLastName() {
return lastName;
}
public void setLastName(String s) {
this.lastName = s;
}
}
In Struts, there is only one controller servlet for the entire web application.
This controller servlet is called ActionServlet and resides in the package
org.apache.struts.action. It intercepts every client request and populates
an ActionForm from the HTTP request parameters. ActionForm is a normal
JavaBeans class. It has several attributes corresponding to the HTTP request
parameters and getter, setter methods for those attributes. You have to create
your own ActionForm for every HTTP request handled through the Struts
framework by extending the org.apache.struts.action.ActionForm
class. Consider the following HTTP request for App1 web application –
http://localhost:8080/App1/create.do?firstName=John&lastName=Doe.
The
ActionForm class for this HTTP request is shown in Listing 1.2. The class
MyForm extends the org.apache.struts.action.ActionForm class and
contains two attributes – firstName and lastName. It also has getter and setter
methods for these attributes. For the lack of better terminology, let us coin a term
to describe the classes such as ActionForm – View Data Transfer Object. View
Data Transfer Object is an object that holds the data from html page and
transfers it around in the web tier framework and application classes.
The ActionServlet then instantiates a Handler. The Handler class name is
obtained from an XML file based on the URL path information. This XML file is
referred to as Struts configuration file and by default named as struts-config.xml.
Chapter 1. Getting Started
27
The Handler is called Action in the Struts terminology. And you guessed it right!
This class is created by extending the Action class in
org.apache.struts.action package. The Action class is abstract and
defines a single method called execute(). You override this method in your
own Actions and invoke the business logic in this method. The execute()
method returns the name of next view (JSP) to be shown to the user. The
ActionServlet forwards to the selected view.
Figure 1.4 A first look at Struts architecture.
Now, that was Struts in a nutshell. Struts is of-course more than just this. It is
a full-fledged presentation framework. Throughout the development of the
application, both the page author and the developer need to coordinate and ensure
that any changes to one area are appropriately handled in the other. It aids in
rapid development of web applications by separating the concerns in projects.
For instance, it has custom tags for JSPs. The page author can concentrate on
developing the JSPs using custom tags that are specified by the framework. The
application developer works on creating the server side representation of the data
and its interaction with a back end data repository. Further it offers a consistent
way of handling user input and processing it. It also has extension points for
customizing the framework and much more. In this section, you got a bird’s eye
view of how Struts works. More details await you in the chapters ahead. But you
have to install Tomcat and Struts on your machine to better understand the
chapters ahead. Hence we will cover Tomcat and Struts installation briefly in the
next section.
28
Struts Survival Guide – Basics to Best Practices
1.5 Tomcat and Struts installation
We will use Windows environment to develop Struts application and Tomcat
servlet container to deploy and test Struts applications. Precisely we will use
Tomcat-5.0.14 Beta, the latest milestone release of Tomcat. You can download
Tomcat 5.0.14 from http://jakarta.apache.org/tomcat and follow the link to
download. There are several binaries available – several variations of tar, exe and
zip files. Choose the 5.0.14.zip file and unzip it. A folder called jakarta-tomcat5.0.14 is created automatically. This is the TOMCAT_HOME directory. Under
the TOMCAT_HOME, there are a lot of folders of which two are important – bin
and webapps folders. The bin folder contains two batch files - startup.bat, used
to start the Tomcat and shutdown.bat, used to stop the Tomcat. All the WAR files
are dropped in the webapps directory and get deployed automatically.
Installing Struts is very easy. In the Struts web site,
http://jakarta.apache.org/struts, go to download section and select the 1.1 Release
Build. This is the latest production quality build available. Once you download
the zipped archive of Struts 1.1 release, unzip the file to a convenient location. It
automatically creates a folder named “jakarta-struts-1.1”. It has three subfolders. The lib sub-folder contains the struts.jar – the core library that you want
to use and other jars on which the Struts depends. You would normally copy
most of these jars into the WEB-INF/lib of your web application. The webapps
sub-folder contains a lot of WAR files that can just dropped into any J2EE
application server and tested.
You can test your Tomcat installation and also study Struts at the same time.
Start Tomcat using startup.bat and then drop the struts-documentation.war from
your Struts webapps folder into Tomcat’s webapps folder. The WAR is
immediately deployed. You can access the Struts documentation at the URL
http://localhost:8080/struts-documentation. You should also download the Struts
1.1 source and refer to it and probably study it to get more insights about its
internals. However be sure to read through this book before you dive into the
Struts source code.
1.6 Summary
In this chapter, we refreshed your memory on Model 1 and Model 2 architectures
for JSPs and pointed out the problems with the bare bone MVC in real life –
about how it gets big and ugly. You understood how MVC with configurable
controller could solve the real life problem. You also took a first look at the high
level Struts architecture and saw how it matched the configurable MVC
controller. You also briefly looked at Struts and Tomcat installation and warmed
up for the forthcoming chapters.
Chapter 2. Struts Framework Components
29
30
Struts Survival Guide – Basics to Best Practices
Ch a p te r 2
Struts Framework Components
In this chapter:
1. You will learn more about Struts components and their categories –
Controller and View
2. You will understand the sequence of events in Struts request handling
lifecycle
3. You will understand the role of the following controller classes ActionServlet, RequestProcessor, ActionForm, Action, ActionMapping and
ActionForward in the request handling lifecycle
4. You will also learn about the role of Struts Tags as View components in
rendering the response
5. You will understand the various elements of Struts configuration file –
struts-config.xml
In the last chapter, you had a cursory glance at the Struts framework. In this
chapter you will dive deeper and cover various Struts Framework Components.
Here is something to remember all the time.
1. All the core components of Struts framework belong to Controller
category.
2. Struts has no components in the Model category.
3. Struts has only auxiliary components in View category. A collection of
custom tags making it easy to interact with the controller. The View
category is neither the core of Struts framework nor is it necessary.
However it is a helpful library for using Struts effectively in JSP based
rendering.
Controller Category: The ActionServlet and the collaborating classes
form the controller and is the core of the framework. The collaborating classes
are RequestProcessor, ActionForm, Action, ActionMapping and
ActionForward.
Chapter 2. Struts Framework Components
31
View Category: The View category contains utility classes – variety of
custom tags making it easy to interact with the controller. It is not mandatory to
use these utility classes. You can replace it with classes of your own. However
when using Struts Framework with JSP, you will be reinventing the wheel by
writing custom tags that mimic Struts view components. If you are using Struts
with Cocoon or Velocity, then have to roll out your own classes for the View
category.
Model Category: Struts does not offer any components in the Model
Category. You are on you own in this turf. This is probably how it should be.
Many component models (CORBA, EJB) are available to implement the business
tier. Your model components are as unique as your business and should not have
any dependency on a presentation framework like Struts. This philosophy of
limiting the framework to what is absolutely essential and helpful and nothing
more has prevented bloating and made the Struts framework generic and
reusable.
NOTE: Some people argue that ActionForm is the model component.
However ActionForm is really part of the controller. The Struts documentation
also speaks along similar lines. It is just View Data Transfer Object – a regular
JavaBeans that has dependencies on the Struts classes and used for transferring
the data to various classes within the controller.
2.1 Struts request lifecycle
In this section you will learn about the Struts controller classes –
ActionServlet,
RequestProcessor,
ActionForm,
Action,
ActionMapping
and
ActionForward
–
all
residing
in
org.apache.struts.action package and struts-config.xml – the Struts
Configuration file. Instead of the traditional “Here is the class – go use it”
approach, you will study the function of each component in the context of HTTP
request handling lifecycle in Struts.
ActionServlet
The central component of the Struts Controller is the ActionServlet. It is
a concrete class and extends the javax.servlet.HttpServlet. It performs
two important things.
1. On startup, its reads the Struts Configuration file and loads it into memory in
the init() method.
2. In the doGet() and doPost() methods, it intercepts HTTP request and
handles it appropriately.
Struts Survival Guide – Basics to Best Practices
32
The name of the Struts Config file is not cast in stone. It is a convention
followed since the early days of Struts to call this file as struts-config.xml and
place it under the WEB-INF directory of the web application. In fact you can
name the file anyway you like and place it anywhere in WEB-INF or its subdirectories. The name of the Struts Config file can be configured in web.xml. The
web.xml entry for configuring the ActionServlet and Struts Config file is as
follows.
action
org.apache.struts.action.ActionServlet
config
/WEB-INF/config/myconfig.xml
1
In the above snippet, the Struts Config file is present in the WEB-INF/config
directory and is named myconfig.xml. The ActionServlet takes the Struts
Config file name as an init-param. At startup, in the init() method, the
ActionServlet reads the Struts Config file and creates appropriate Struts
configuration objects (data structures) into memory. You will learn more about
the Struts configuration objects in Chapter 7. For now, assume that the Struts
Config file is loaded into a set of objects in memory, much like a properties file
loaded into a java.util.Properties class.
Like any other servlet, ActionServlet invokes the init() method when
it receives the first HTTP request from the caller. Loading Struts Config file into
configuration objects is a time consuming task. If the Struts configuration objects
were to be created on the first call from the caller, it will adversely affect
performance by delaying the response for the first user. The alternative is to
specify load-on-startup in web.xml as shown above. By specifying load-onstartup to be 1, you are telling the servlet container to call the init() method
immediately on startup of the servlet container.
The second task that the ActionServlet performs is to intercept HTTP
requests based on the URL pattern and handles them appropriately. The URL
pattern can be either path or suffix. This is specified using the servlet-mapping in
web.xml. An example of suffix mapping is as follows.
action
*.do
Chapter 2. Struts Framework Components
33
If the user types http://localhost:8080/App1/submitCustomerForm.do in the
browser URL bar, the URL will be intercepted and processed by the
ActionServlet since the URL has a pattern *.do, with a suffix of "do”.
Once the ActionServlet intercepts the HTTP request, it doesn’t do
much. It delegates the request handling to another class called
RequestProcessor by invoking its process()method. Figure 2.1 shows a
flowchart with Struts controller components collaborating to handle a HTTP
request within the RequestProcessor’s process() method. The next sub
sections describe the flowchart in detail. It is very important that you understand
and even memorize this flowchart. Most of the Struts Controller functionality is
embedded in the process() method of RequestProcessor class. Mastery
over this flowchart will determine how fast you will debug problems in real life
Struts applications. Let us understand the request handling in the process()
method step by step with an example covered in the next several sub sections.
Figure 2.1 Flowchart for the RequestProcessor process method.
RequestProcessor and ActionMapping
The RequestProcessor does the following in its process() method:
Step 1: The RequestProcessor first retrieves appropriate XML block for
the URL from struts-config.xml. This XML block is referred to as
Struts Survival Guide – Basics to Best Practices
34
ActionMapping in Struts terminology. In fact there is a class called
ActionMapping
in
org.apache.struts.action
package.
ActionMapping is the class that does what its name says – it holds the mapping
between a URL and Action. A sample ActionMapping from the Struts
configuration file looks as follows.
Listing 2.1 A sample ActionMapping from struts-config.xml
Step 2: The RequestProcessor looks up the configuration file for the URL
pattern /submitDetailForm. (i.e. URL path without the suffix do) and finds the
XML block (ActionMapping) shown above. The type attribute tells Struts which
Action class has to be instantiated. The XML block also contains several other
attributes. Together these constitute the JavaBeans properties of the
ActionMapping instance for the path /submitDetailForm. The above
ActionMapping tells Struts to map the URL request with the path
/submitDetailForm to the class mybank.example.CustomerAction. The
Action class is explained in the steps ahead. For now think of the Action as your
own class containing the business logic and invoked by Struts. This also tells us
one more important thing.
Since each HTTP request is distinguished from the other only by the path,
there should be one and only one ActionMapping for every path attribute.
Otherwise Struts overwrites the former ActionMapping with the latter.
ActionForm
Another attribute in the ActionMapping that you should know right away is
name. It is the logical name of the ActionForm to be populated by the
RequestProcessor.
After
selecting
the
ActionMapping,
the
RequestProcessor instantiates the ActionForm. However it has to know the
fully qualified class name of the ActionForm to do so. This is where the name
attribute of ActionMapping comes in handy. The name attribute is the logical
Chapter 2. Struts Framework Components
35
name of the ActionForm. Somewhere else in struts-config.xml, you will find a
declaration like this:
This form-bean declaration associates a logical name CustomerForm with the
actual class mybank.example.CustomerForm.
Step 3: The RequestProcessor instantiates the CustomerForm and puts
it in appropriate scope – either session or request. The RequestProcessor
determines the appropriate scope by looking at the scope attribute in the same
ActionMapping.
Step 4: Next, RequestProcessor iterates through the HTTP request parameters
and populates the CustomerForm properties of the same name as the HTTP
request parameters using Java Introspection. (Java Introspection is a special form
of Reflection using the JavaBeans properties. Instead of directly using the
reflection to set the field values, it uses the setter method to set the field value
and getter method to retrieve the field value.)
Step 5: Next, the RequestProcessor checks for the validate attribute in the
ActionMapping. If the validate is set to true, the RequestProcessor invokes
the validate() method on the CustomerForm instance. This is the method
where you can put all the html form data validations. For now, let us pretend that
there were no errors in the validate() method and continue. We will come
back later and revisit the scenario when there are errors in the validate()
method.
Action
Step 6: The RequestProcessor instantiates the Action class specified in the
ActionMapping (CustomerAction) and invokes the execute() method on
the CustomerAction instance. The signature of the execute method is as
follows.
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws Exception
Apart from the HttpServletRequest and HttpServletResponse, the
ActionForm is also available in the Action instance. This is what the
ActionForm was meant for; as a convenient container to hold and transfer data
from the http request parameter to other components of the controller, instead of
having to look for them every time in the http request.
The execute() method itself should not contain the core business logic
irrespective of whether or not you use EJBs or any fancy middle tier. The first
and foremost reason for this is that business logic classes should not have any
dependencies on the Servlet packages. By putting the business logic in the Action
Struts Survival Guide – Basics to Best Practices
36
class, you are letting the javax.servlet.* classes proliferate into your
business logic. This limits the reuse of the business logic, say for a pure Java
client. The second reason is that if you ever decide to replace the Struts
framework with some other presentation framework (although we know this will
not happen), you don’t have to go through the pain of modifying the business
logic. The execute() method should preferably contain only the presentation
logic and be the starting point in the web tier to invoke the business logic. The
business logic can be present either in protocol independent Java classes or the
Session EJBs.
The RequestProcessor creates an instance of the Action
(CustomerAction), if one does not exist already. There is only one instance
of Action class in the application. Because of this you must ensure that the
Action class and its attributes if any are thread-safe. General rules that apply to
Servlets hold good. The Action class should not have any writable attributes
that can be changed by the users in the execute() method.
ActionForward
The execute() method returns the next view shown to the user. If you are
wondering what ActionForward is, you just have found the answer.
ActionForward is the class that encapsulates the next view information.
Struts, being the good framework it is, encourages you not to hardcode the JSP
names for the next view. Rather you should associate a logical name for the next
JSP page. This association of the logical name and the physical JSP page is
encapsulated in the ActionForward instance returned from the execute method.
The ActionForward can be local or global. Look again at the good old
ActionMapping XML block in Listing 2.1. It contained sub elements called
forwards with three attributes – name, path and redirect as shown below.
The name attribute is the logical name of the physical JSP as specified in the
path attribute. These forward elements are local to the ActionMapping in Listing
2.1. Hence they can be accessed only from this ActionMapping argument in
the CustomerAction’s execute() method and nowhere else. On the other
hand, when the forwards are declared in the global forwards section of the strutsconfig.xml, they are accessible from any ActionMapping. (In the next section,
you will look closely at Struts Config file.) Either ways, the findForward()
method on the ActionMapping instance retrieves the ActionForward as
follows.
ActionForward forward = mapping.findForward(“success”);
The logical name of the page (success) is passed as the keyword to the
findForward() method. The findForward() method searches for the
forward with the name “success”, first within the ActionMapping and then in the
global-forwards section. The CustomerAction’s execute() method returns
the ActionForward and the RequestProcessor returns the physical JSP
Chapter 2. Struts Framework Components
37
to the user. In J2EE terms, this is referred to as dispatching the view to the user.
The dispatch can be either HTTP Forward or HTTP Redirect. For instance, the
dispatch to the success is a HTTP Redirect whereas the dispatch to “failure” is a
HTTP Redirect.
Difference between HTTP Forward and HTTP Redirect
HTTP Forward is the process of simply displaying a page when requested
by the user. The user asks for a resource (page) by clicking on a hyperlink or
submitting a form and the next page is rendered as the response. In Servlet
Container, HTTP Forward is achieved by invoking the following.
RequestDispatcher dispatcher =
httpServletRequest.getRequestDispatcher(url);
Dispatcher.forward(httpServletRequest, httpServletResponse);
HTTP Redirect is a bit more sophisticated. When a user requests a
resource, a response is first sent to the user. This is not the requested resource.
Instead this is a response with HTTP code “302” and contains the URL of the
requested resource. This URL could be the same or different from original
requested URL. The client browser automatically makes the request for the
resource again with the new URL. And this time, the actual resource is sent to
the user. In the web tier you can use HTTP redirect by using the simple API,
sendRedirect() on the HttpServletResponse instance. The rest of the
magic is done by HTTP. HTTP Redirect has an extra round trip to the client
and is used only in special cases. Later in this book, we will show a scenario
where HTTP redirect can be useful.
ActionErrors and ActionError
So far, we have covered Struts request handling lifecycle as a happy day
scenario – from the point the user submits an html form till the user sees the next
page. In reality, users of your web application may submit incorrect data or
sometimes no data at all. You have to catch these as close to the user interface as
possible, rather than waiting for the middle tier or the database to tell you that a
column cannot be inserted in the database because it was expecting a non-null
value. There are two consequences of such programming practice.
1. Server time and resources are precious since they are shared. Spending too
much of server’s time and resources on a request, that we know is going to
fail eventually is a waste of server resources.
2. It has a negative impact on the code quality. Since one has to prepare for the
possibility of having null data, appropriate checks have to be put (or
Struts Survival Guide – Basics to Best Practices
38
NumberFormatExceptions have to be caught) everywhere in the code.
Generally business logic is the toughest code of the system and contains
enough if-else blocks as such. More if-else blocks for null checks can only
mean two things – bad code and maintenance nightmare. Not an elegant
programming to say the least. If only you could verify the validity of the user
data as close to the user, then the rest of the code only has to deal with
business logic and not invalid data.
Listing 2.2 validate() method in the CustomerForm
public ActionErrors validate(ActionMapping mapping,
HttpServletRequest request)
{
// Perform validator framework validations
ActionErrors errors = super.validate(mapping, request);
// Only need crossfield validations here
if (parent == null) {
errors.add(GLOBAL_ERROR,
new ActionError("error.custform"));
}
if (firstName == null) {
errors.add("firstName",
new ActionError("error.firstName.null"));
}
return errors;
}
Struts provides validate() method in the ActionForm to deal with
user input validations. Let us now look at how you can validate the user input
and report errors to the framework. We will postpone the discussion of how
Struts reports the errors to the end user when we discuss View Components later
in this chapter. As shown in the flowchart (Figure 2.1), the validate()
method is called after the ActionForm instance is populated with the form
data. A sample validate() method is shown in Listing 2.2.
In the validate() method, you will notice an object called
ActionErrors is instantiated. All error checks are performed with the usual
if-else blocks. If there are errors, then an individual ActionError object is
created for the culprit field and added to the ActionErrors. Think of
ActionErrors as a Map for the individual ActionError objects. You can
associate one or more ActionError objects for each key. The form field name
is generally chosen as the key and can have multiple ActionError objects
associated with it. The ActionError is either specific to a field in the
Chapter 2. Struts Framework Components
39
ActionForm or it is global to the entire form. When the error is specific to a
form field, the field name is used as the key in the ActionErrors. When the
error is global to the form, the key name is always GLOBAL_ERRORS. Both of
the cases are shown in the Listing 2.2.
You might also notice that the ActionError constructor takes a rather
cryptic key as the argument. This key is declared in a properties file whose value
is the actual error message. The properties file is selected based on the user
chosen Locale. The technical term for this properties file where the messages are
externalized is Message Resource Bundle. It is based on the Java’s concept of
Localization using the java.util.ResourceBundle and has a whole lot of
bells and whistles. We will cover Message Resource Bundle in depth in
Chapter10 on Internationalization and Localization. For now it suffices to know
that the properties file also serves another purpose apart from Localization. It lets
you change the messages without recompiling the code, and is quite handy while
maintaining the code. An entry in the Message Resource Bundle properties file
looks like:
error.firstName.null=First Name cannot be null
The RequestProcessor stops any further processing when it gets the
ActionErrors object with ActionError objects. The Action instance
never gets the control (and never gets a chance to return ActionForward).
Hence the RequestProcessor consults the ActionMapping object to find
the page to be displayed. Notice that the ActionMapping has an attribute
named “input”. This attribute specifies the physical page to which the request has
to be forwarded on error. Generally this page is the original page where user
entered the data since it is natural that user would want to reenter the data in the
same page on error and resubmit.
That completes our overview of the working of Struts Controller
components. Now, let us formally look at the Struts configuration file in detail.
2.2 Struts Configuration File – struts-config.xml
As you learnt in Chapter 1, the configurable controller is the answer to the Fat
controller problem. In a Fat Controller, the programmers can code “if” blocks on
need basis. Not so with the configurable controllers. The expressive and
configuration capability is limited to what the built-in controller can support. In
Struts, the built-in controller supports a variety of cases that can arise while
developing web applications. It even provides points to extend the configuration
capabilities. These points known as Extension points, take the configuration
capability to the next dimension. We will deal with extending Struts in Chapter 7.
In this section, we will just look at the normal facilities offered by the strutsconfig.xml.
40
Struts Survival Guide – Basics to Best Practices
The Struts configuration file adheres to the struts-config_1_1.dtd. The struts
config dtd can be found in the Struts distribution in the lib directory. It shows
every possible element, their attributes and their description. Covering all of
them at once would only result in information overload. Hence we will only look
at the five important sections of this file relevant to our discussion and their
important attributes. In fact we have already covered most of these in the
lifecycle discussion earlier, but are summarizing them again to refresh your mind.
The five important sections are:
1. Form bean definition section
2. Global forward definition section
3. Action mapping definition section
4. Controller configuration section
5. Application Resources definition section
Listing 2.3 shows a sample Struts Config file showing all the five sections.
The form bean definition section contains one or more entries for each
ActionForm. Each form bean is identified by a unique logical name. The type is
the fully qualified class name of the ActionForm. An interesting to note is that
you can declare the same ActionForm class any number of times provided each
entry has a unique name associated with it. This feature is useful if you want to
store multiple forms of the same type in the servlet session.
Table 2.1 Important attributes and elements of ActionMapping entry in struts-config.xml
Attribute/Element
name
Path
Type
Name
Scope
Validate
Input
Forward
Description
The URL path (either path mapping or suffix mapping) for which this
Action Mapping is used. The path should be unique
The fully qualified class name of the Action
The logical name of the Form bean. The actual ActionForm associated
with this Action Mapping is found by looking in the Form-bean definition
section for a form-bean with the matching name. This informs the
Struts application which action mappings should use which
ActionForms.
Scope of the Form bean – Can be session or request
Can be true or false. When true, the Form bean is validated on
submission. If false, the validation is skipped.
The physical page (or another ActionMapping) to which control should
be forwarded when validation errors exist in the form bean.
The physical page (or another ActionMapping) to which the control
should be forwarded when the ActionForward with this name is
selected in the execute method of the Action class.
The ActionMapping section contains the mapping from URL path to an Action
class (and also associates a Form bean with the path). The type attribute is the
fully qualified class name of the associated Action. Each action entry in the
action-mappings should have a unique path. This follows from the fact that each
Chapter 2. Struts Framework Components
41
URL path needs a unique handler. There is no facility to associate multiple
Actions with the same path. The name attribute is the name of the Form bean
associated with this Action. The actual form bean is defined in Form bean
definition section. Table 2.1 shows all the relevant attributes discussed so far for
the action entry in action-mappings section.
Listing 2.3 Sample struts-config.xml
Form bean Definitions
Global Forward Definitions
Action Mappings
Controller Configuration
42
Struts Survival Guide – Basics to Best Practices
Message Resource Definition
In the ActionMapping there are two forwards. Those forwards are local
forwards – which means those forwards can be accessed only within the
ActionMapping. On the other hand, the forwards defined in the Global Forward
section are accessible from any ActionMapping. As you have seen earlier, a
forward has a name and a path. The name attribute is the logical name assigned.
The path attribute is the resource to which the control is to be forwarded. This
resource can be an actual page name as in
or it can be another ActionMapping as in
The /logoff (notice the absence of “.do”) would be another ActionMapping in
the struts-config.xml. The forward – either global or local are used in the
execute() method of the Action class to forward the control to another
physical page or ActionMapping.
The next section in the config file is the controller. The controller is optional.
Unless otherwise specified, the default controller is always the
org.apache.struts.action.RequestProcessor. There are cases when
you want to replace or extend this to have your own specialized processor. For
instance, when using Tiles (a JSP page template framework) in conjunction with
Struts, you would use TilesRequestProcessor.
The last section of immediate interest is the Message Resource definition. In
the ActionErrors discussion, you saw a code snippet that used a cryptic key as the
argument for the ActionError. We stated that this key maps to a value in a
properties file. Well, we declare that properties file in the struts-config.xml in the
Message Resources definition section. The declaration in Listing 2.1 states that
the Message Resources Bundle for the application is called
ApplicationResources.properties and the file is located in the java package
mybank.
If you are wondering how (and why) can a properties file be located in a java
package, recall that any file (including class file) is a resource and is loaded by
the class loader by specifying the package. An example in the next chapter will
really make things clearer.
2.3 View Components
In Struts, View components are nothing but six custom tag libraries for JSP
views – HTML, Bean, Logic, Template, Nested, and Tiles tag libraries. Each one
caters to a different purpose and can be used individually or in combination with
others. For other kinds of views (For instance, Template based presentation) you
Chapter 2. Struts Framework Components
43
are on your own. As it turns out, majority of the developers using Struts tend to
use JSPs. You can extend the Struts tags and also build your own tags and mix
and match them.
You already know that the ActionForm is populated on its way in by the
RequestProcessor class using Java Introspection. In this section you will
learn how Struts tags interact with the controller and its helper classes to display
the JSP using two simple scenarios – how FormTag displays the data on the
way out and how the ErrorsTag displays the error messages. We will not
cover every tag in Struts though. That is done in Chapter 6.
What is a custom tag?
Custom Tags are Java classes written by Java developers and can be used
in the JSP using XML markup. Think of them as view helper beans that can be
used without the need for scriptlets. Scriptlets are Java code snippets
intermingled with JSP markup. You need a Java developer to write such
scriptlets. JSP pages are normally developed and tweaked by page authors,
They cannot interpret the scriptlets. Moreover this blurs the separation of
duties in a project. Custom Tags are the answer to this problem. They are
XML based and like any markup language and can be easily mastered by the
page authors. You can get more information on Custom Tags in Chapter 6.
There are also numerous books written about JSP fundamentals that cover this
topic very well.
Listing 2.4 CustomerDetails JSP
Continue
How FormTag works
Consider a case when the user requests a page CustomerDetails.jsp. The
CustomerDetails JSP page has a form in it. The form is constructed using the
Struts Survival Guide – Basics to Best Practices
44
Struts html tags and shown in Listing 2.4. The represents the
org.apache.struts.taglib.html.FormTag class, a body tag. The
represents the org.apache.struts.taglib.html.TextTag
class, a normal tag. The resulting HTML is shown in Listing 2.5.
The FormTag can contain other tags in its body. SubmitTag generates the
Submit button at runtime. The TextTag generates html textbox at
runtime as follows.
The FormTag has an attribute called action. Notice that the value of the
action attribute is /submitDetailForm in the JSP snippet shown above. This
represents the ActionMapping. The generated HTML
When the container encounters the FormTag, it invokes the
doStartTag() method. The doStartTag() method in the FormTag class
does exactly what the RequestProcessor does in the execute() method.
1. The FormTag checks for an ActionMapping with /submitDetailForm in its
path attribute.
2. When it finds the ActionMapping, it looks for an ActionForm with the
name CustomerForm, (which it gets from the ActionMapping) in the
request or session scope (which it gets from ActionMapping).
3. If it does not find one, it creates a new one and puts it in the specified
context. Otherwise it uses the existing one. It also makes the Form name
available in the page context.
4. The form field tags (e.g. TextTag) access the ActionForm by its name
from the PageContext and retrieve values from the ActionForm
Chapter 2. Struts Framework Components
45
attributes with matching names. For instance, the TextTag retrieves the value of the attribute firstName
from the mybank.example.CustomerForm and substitutes as the
value. If the CustomerForm existed in the request or session and the
firstName field in the CustomerForm had a value “John”, then the
TextTag will generate HTML that looks like this:
If the firstName field was null or empty in the CustomerForm instance,
the TextTag will generate HTML that looks like this
And thus the ActionForm is displayed as a HTML Form.
The moral of the story is that ActionForms should be made available in
advance in the appropriate scope if you are editing existing form data. Otherwise
the FormTag creates the ActionForm in the appropriate scope with no data.
The latter is suited for creating fresh data. The FormTag reads the same old
ActionMapping while looking for the ActionForm in the appropriate scope. It
then displays the data from that ActionForm if available.
How ErrorsTag works
When dealing with ActionErrors, you learnt that the validation errors in an
ActionForm are reported to the framework through the ActionErrors
container. Let us now see what facilities the framework provides to display those
errors in the JSP. Struts provides the ErrorsTag to display the errors in the JSP.
When the ActionForm returns the ActionErrors, the RequestProcessor
sets it in the request scope with a pre-defined and well-known name (within the
Struts framework) and then renders the input page. The ErrorsTag iterates over
the ActionErrors in the request scope and writes out each raw error text to the
HTML output.
You can put the ErrorsTag by adding in the JSP. The tag
does not have any attributes. Neither does it have a body. It displays the errors
exactly in the location where you put the tag. The ErrorsTag prints three
elements to the HTML output – header, body and footer. The error body consists
of the list of raw error text written out to by the tag. A sample error display from
struts-example.war (available with Struts 1.1 download) is shown in Figure 2.2.
You can configure the error header and footer through the Message Resource
Bundle. The ErrorsTag looks for predefined keys named errors.header and
errors.footer in the default (or specified) Message Resource Bundle and their
values are also written out AS IS. In the struts-example.war, these are set as
follows:
Struts Survival Guide – Basics to Best Practices
46
errors.header=Validation Error
You must correct the following error(s) before proceeding:
errors.footer=
For each ActionError, the ErrorsTag also looks for predefined keys
errors.prefix and errors.suffix in the default (or specified) Message
Resource Bundle. By setting errors.prefix= and errors.suffix =
, the generated HTML looks like follows and appears in the browser as
shown in Figure 2.2.
Validation Error
You must correct the following error(s) before proceeding:
- From Address is required.
- Full Name is required.
- Username is required
Figure 2.2 Struts error display.
Note that all the formatting information is added as html markup into these
values. The bold red header, the line breaks and the horizontal rule is the result of
html markup in the errors.header and errors.footer respectively.
Tip: A common problem while developing Struts applications is that
does not seem to display the error messages This generally
means one of the following:
The properties file could not be located or the key is not found. Set the
Chapter 2. Struts Framework Components
47
for debugging.
Another reason for not seeing the error messages has got to do with the
positioning of the tag itself. If you added the tag itself in the
instead of a , the html browser cannot display the messages even
though the tag worked properly by writing out the errors to the response
stream.
The View Components was the last piece of the puzzle to be sorted out. As it
turns out, all the work is performed in the controller part of the framework. The
View Tags look for information in the request or session scope and render it as
HTML. Now, that is how a view should be – as simple as possible and yet
elegant. Struts lets you do that, easy and fast.
2.4 Summary
In this chapter you learnt the Struts request lifecycle in quite a bit of detail. You
also got a good picture of Struts framework components when we covered the
controller and view components. You also got to know relevant sections of
struts-config.xml – the Struts configuration file. Armed with this knowledge we
will build a Hello World web application using Struts framework in the next
chapter.
48
Struts Survival Guide – Basics to Best Practices
Ch a p te r 3
Your first Struts application
In this chapter:
1. You will build your first Struts web application step by step
2. You will build a Web ARchive (WAR) and deploy the web application in
Tomcat
In the last two chapters you have learnt a lot about Struts. In this chapter will take
you step by step in building your first Struts application and deploying it onto
Tomcat.
3.1 Introduction
You
can
access
the
sample
application
by
typing
http://localhost:8080/App1/index.jsp in the browser. The index.jsp contains a
single hyperlink. The link is http://localhost:8080/App1/CustomerDetails.jsp. On
clicking the link, CustomerDetails.jsp is displayed. CustomerDetails.jsp contains
an HTML Form with two buttons – Submit and Cancel. When the user submits
the Form by clicking Submit, Success.jsp is shown if the form validations go
through. If the validations fail, the same page is shown back to the user with the
errors. If the user clicks Cancel on the form, the index.jsp is shown to the user.
Figure 3.1 The JSP flow diagram for the Hello World Struts application.
Chapter 3. Your First Struts Application
49
Directory Structure overview
This is the first time you are building a sample application in this book.
Hence we will introduce you to a standard directory structure followed
throughout the book when developing applications. Then we will move on to the
actual steps involved. Figure 3.2 shows the directory structure.
The structure is very logical. The toplevel directory for every sample
application is named after the
application itself. In this case all the
files are located under the directory
named App1. The directory src/java
beneath App1 contains the Java
source files (CustomerForm.java and
CustomerAction.java) and also the
application’s
Message
Resource
Bundle (App1Messages.properties).
Another directory called web-root
beneath App1 contains all the JSPs
(index.jsp, CustomerDetails.jsp and
Success.jsp) and images (banner.gif).
The web-root contains a WEB-INF
sub directory with files web.xml and
struts-config.xml.
Figure 3.2 The directory structure used
throughout the book for sample Struts
applications.
3.2 Hello World – step by step
Here are the steps involved in creating the Struts application.
1. Add relevant entries into the web.xml
a. Add ActionServlet Configuration with initialization parameters
b. Add ActionServlet Mapping
c. Add relevant taglib declaration
2. Start with a blank template for the struts-config.xml. In the struts-config.xml,
add the following
a. Declare the RequestProcessor
b. Create a properties file and declare it as Message Resource Bundle
c. Declare the Message Resource Bundle
d. Declare the Form-bean
Struts Survival Guide – Basics to Best Practices
50
e. Declare the ActionMapping for the Form-bean
f. Add the forwards in the ActionMapping
3. Create the Form-bean class
4. Create the Action class
5. Create the JSP with Struts tags
6. For every tag in the JSP, add key value pairs to the
Message Resource Bundle (properties file) created in Step 3b
7. Add Validation in the Form-bean
8. Define the error messages in the Message Resource Bundle
9. Create the rest of the JSPs.
Listing 3.1 web.xml for the Struts Application
Hello World Struts Application
action
org.apache.struts.action.ActionServlet
config
/WEB-INF/struts-config.xml
debug
3
detail
3
1
(continued..)
Chapter 3. Your First Struts Application
51
Listing 3.1 web.xml for the Struts Application (Continued)
action
*.do
index.jsp
/WEB-INF/struts-html.tld
/WEB-INF/struts-html.tld
/WEB-INF/struts-bean.tld
/WEB-INF/struts-bean.tld
Step 1. As you already know from Chapter 2, the first step in writing a Struts
application is to add the ActionServlet entry in web.xml and also map the
servlet to the url-pattern *.do. This is shown in Listing 3.1. You already know the
meaning of the initialization parameter named config. Here we will introduce two
more initialization parameters. They are debug and detail.
The debug initialization parameter lets you set the level of detail in the debug
log. A lower number means lesser details and a higher number implies detailed
logging. It is absolutely essential that you use this logging feature especially in
the beginning and also while setting up Struts application for the first time. The
debug messages give you enough insight to resolve any configuration related
issues. Use them to their fullest capability. In Listing 3.1, we have set the value
of debug to 3.
The detail initialization parameter lets you set the level of detail in the
digester log. Digester is the component that parses the Struts Config file and
loads them into Java objects. Some of the errors can be traced by looking at the
log created by the Digester as it parses the XML file.
Later in this chapter, you will also use two of the Struts Tag libraries to
construct the JSP. Hence the relevant tag library definition files – struts-html.tld
and struts-bean.tld are also declared in web.xml.
Struts Survival Guide – Basics to Best Practices
52
Another setting of interest in web.xml is the .
Typically you would want to type http://localhost:8080/App1 in the browser
URL bar and go to index.jsp automatically. This goal is achieved by declaring
index.jsp as one of the welcome files.
Step 2. Select a blank template for struts-config.xml and add the following
Listing 3.2 struts-config.xml with all entries for App1
Step 2a. Declare the controller element in Struts Config file. The
element
tells
the
Struts
framework
to
use
org.apache.struts.action.RequestProcessor for this application. For
Chapter 3. Your First Struts Application
53
a simple Struts application like App1, this RequestProcessor will suffice. You
will use specialized sub classes of RequestProcessor as controllers later in
this book. The struts-config.xml is shown in Listing 3.2
Step 2b. Create a properties file under mybank.app1 java package and name it
as App1Messages.properties. You will later add key value pairs into this file.
Instead of hard coding field names in the JSP, you will use key names from this
file to access them. In this way, the actual name can be changed outside the JSP.
For now, add the following entry into the Struts Config file.
This is the instruction to the Struts controller to use the App1Message.properties
file as the Message Resource Bundle.
Step 2c.Define the form bean by adding a form-bean entry in the form-beans
section.
Step 2d. Define an ActionMapping by adding the following to the actionmappings
Step 2e. Add the local forwards to the ActionMapping
At this point, the struts-config.xml looks as shown in Listing 3.3. All entries
in bold are added for App1.
Step
3.
Create
the
Form-bean by extending ActionForm in
org.apache.struts.action package. Listing 3.3 shows the Form bean. For
every field in the HTML Form, there is an instance variable with getter and setter
methods in the Form bean. The Struts controller populates the HTML Form by
calling the getter methods on the Form bean. When the user submits the HTML
Struts Survival Guide – Basics to Best Practices
54
Form, the Struts controller populates the Form bean with data from HTML Form
by calling setter method on the Form bean instance.
Step 4. Next, create the Action bean by extending the
org.apache.struts.action.Action class. Let us call it CustomerAction.
Every class that extends Action implements the execute() method. As you
saw earlier in Chapter 2, the RequestProcessor calls the execute() method
after populating and validating the ActionForm. In this method you typically
implement logic to access middle-tier and return the next page to be displayed to
the user. Listing 3.4 shows the execute() method in CustomerAction. In this
method, an operation is performed to check is the Cancel button was pressed. If
so, the “mainpage” (Global Forward for index.jsp) is shown to the user. The
isCancelled() method is defined in the parent Action class. If the operation
requested is not Cancel, then the normal flow commences and the user sees
Success.jsp.
Listing 3.3 CustomerForm – Form Bean for App1
public class CustomerForm extends ActionForm {
private String firstName;
private String lastName;
public CustomerForm() {
firstName = “”;
lastName = “”;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String s) {
this.firstName = s;
}
public String getLastName() {
return lastName;
}
public void setLastName(String s) {
this.lastName = s;
}
}
Step 5. Create the JSP using Struts html and bean tags.
Chapter 3. Your First Struts Application
55
All Struts html tags including the FormTag are defined in struts-html.tld.
These tags generate appropriate html at runtime. The TLD file struts-html.tld and
struts-bean.tld are declared at the top of JSP and associated with logical names
“html” and “bean” respectively. The JSP then uses the tags with the prefix of
“html:” and “bean:” instead of the actual tag class name. Listing 3.5 shows the
CustomerDetails.jsp. Let us start from the top of this Listing.
Listing 3.4 CustomerAction – Action Bean for App1
public class CustomerAction extends Action {
public ActionForward execute(ActionMapping mapping,
ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws Exception
{
if (isCancelled(request)) {
System.out.println(Cancel Operation Performed”);
return mapping.findForward(“mainpage”);
}
CustomerForm custForm = (CustomerForm) form;
String firstName = custForm.getFirstName();
String lastName = custForm.getLastName();
System.out.println(“Customer First name is “ + firstName);
System.out.println(“Customer Last name is “ + lastName);
ActionForward forward = mapping.findForward(“success”);
return forward;
}
}
: Under normal circumstances, this JSP tag just generates
opening and closing html tags for the page i.e. and . However
the real advantage of this tag is when the browser has to render the HTML based
on the locale. For instance, when the user’s locale is set to Russia, the tag
generates instead of the plain old , so that the
browser can attempt to render the Russian characters (if any) in the best possible
manner. Setting tells Struts to look for the
locale specific resource bundle (More on this later).
: As you might be already aware of, one of the best practices
in authoring pages is to use relative URLs instead of absolute ones. In order to
use relative URLs in HTML, you need to declare the page context root with the
declaration tag. All URLs (not starting with “/”) are
Struts Survival Guide – Basics to Best Practices
56
assumed to be relative to the base href. This is exactly what the
tag generates.
Listing 3.5 CustomerDetails.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
:
:
: The FormTag represented by generates the
HTML representation of the Form as follows: