Learning Jakarta Struts 1.2A concise and practical tutorial
This book offers step-by-step instructions on Jakarta Struts Framework as well as on building a web application based on Open Source-Software. As the book progresses, we will develop a Web shop: the classic Book Store. This Web application will help us to integrate the individual components of Struts together into complete and extensive software.
also read:
The crucial point lies in the practical application and not so much in theoretical background. This book will first demonstrate the process of developing an application followed by a short explanation. You can then experiment with the given code.
What This Book CoversEach chapter begins with a short introduction and ends with in-depth questions and a short summary. Each chapter builds up on the previous one. Those readers who are already familiar with struts can skip individual chapters, but they should at least skim through those chapters, so they won’t loose the plot and it will also help them to keep up with the web application development part of the book.
Here is an overview for the content of the each chapter:
Chapter 1 presents an overview of Struts in compact form.
Chapter 2 explains the installation for the Struts and shows the first and very easy example. The aim is to start working and experimenting with the fully running system. If you have worked with Struts before, you can skip this chapter.
Chapter 3 introduces the concept the book is based on—the web application called the “Book Store”. This will be built, expanded and adapted step-by-step in the following chapters. The underlying design will be introduced in this chapter.
Chapter 4 discusses Internationalization—the possibility to adapt the text of the software in different languages. Here is the further information and tricks: Custom Actions are explained and one individual Custom Action will be developed.
Chapter 5 emphasizes the importance of correct logging and use of configuration data for software quality. This chapter presents different approaches for the implementation.
Chapter 6 discusses Forms. Handling forms is a standard problem. Particularly, error handling requires always the same mechanisms. Struts offer various possibilities for simplifying this task. Furthermore, this chapter gives insight on how to access databases.
Chapter 7 introduces Logic Tags that allow us to manage conditional generation of a web page via HTML Tags. Logical statements such as Loops and If – statements are explained in this chapter.
Chapter 8 discusses error handling, the central element of any application. A well designed shop will always display a error message / statement, after all it’s about the customer’s money.
Chapter 9 discusses controller and templates. The basic process for the controller in Model 2-concept is manually implemented and subsequently explained for struts. Templates (Tiles) allow modular building of the web site design and an easy alteration.
Chapter 10 is quite an extensive chapter where the elements of the shop are further expanded and merge together as one package. Authorization is implemented, a shopping cart is built and order process is completed.
Chapter 11 offers interesting additional information on Struts independent of our Shop Model.
Chapter 12 discusses JSTL—the frequently called a successor of struts. Here is a short overview of how these two techniques can be combined together.
Chapter 13 gives useful tools and enhancements for struts as well as practical solutions for frequently seen problems.
Appendix A is the Solutions section. Here you will find answers to several exercises. Do yourselves a favor and look into this section only after you have solved the problem yourselves and then compare the answers.
Appendix B contains the Glossary that explains important concepts.
Appendix C contains Literature where you will find some more book tips.
Internationalization and Taglibs
In this chapter, we create the fundamental structure for the shop, illustrating key concepts of the Struts framework. We also look at configuring our web application to support multiple languages. Finally, the Custom Actions, or Tag Libraries, are introduced.
The Structure for the Shop
We constructed a simple Struts-capable website in Chapter 2. We can use that as a starting point here. Simply stop Tomcat, copy the shop1 folder in webapps, and rename it as shop2.
Internationalization
Internationalization is a complex and involved subject. In brief, it refers to the automatic rendering of an application in the user’s chosen language. It relates not only to the text itself, but also to numbers, date format, and currency values. Special symbols and
alphabetical sorting in different languages bring interesting and unexpected problems with them.
Internationalization and Java
Java offers a variety of internationalization options for applications. The following two tutorials on Sun’s website cover the subject quite well:
- http://java.sun.com/j2ee/1.4/docs/tutorial/doc/WebI18N.html#wp76431
- http://java.sun.com/docs/books/tutorial/i18n/resbundle/concept.html
Let’s take a quick look at a very simple example:
<b>Listing 4.1: Test.java</b> import java.util.Locale; import java.text.NumberFormat; public class Test { public static void main(String args[]) { String amountOut; NumberFormat numberFormatter; Double amount = new Double(345987.246); Locale en = new Locale("en", "US"); Locale de = new Locale("de", "DE"); // US output numberFormatter = NumberFormat.getNumberInstance(en); amountOut = numberFormatter.format(amount); System.out.println(amountOut + " " + NumberFormat.getCurrencyInstance(en).format(amount) + " " + en.toString()); // German output numberFormatter = NumberFormat.getNumberInstance(de); amountOut = numberFormatter.format(amount); System.out.println(amountOut + " " + NumberFormat.getCurrencyInstance(de).format(amount) + " " + de.toString()); } }
This will give you the following output:
345,987.246 $345,987.25 en_US 345.987,246 345.987,25 Ç de_DE
The German currency should, of course, use the Euro symbol; a wrong character appears here as a consequence of the limited character set available in the DOS console.
Java allows us to define the text for several languages with the help of configuration files. A suitable language is chosen depending on the user’s system language. A similar mechanism applies with Struts as well, but instead of the system language, it uses the language specified by the browser (see section 4.4, Custom Actions).
Internationalization and Struts
One of the limitations in Struts is that it does not offer any facility to accept input from languages that have special symbols. This is a particular issue for Asian languages where the browser has to provide support.
In Chapter 1 you saw how a page can be multilingual. How does Struts know where to look for the correct text for the language? The WEB-INF/struts-config.xml file contains the following entry:
<b> <message-resources parameter="resources.application"/> </b>
The first part of the parameter attribute value, resources, indicates the name of the subfolder within WEB-INF/classes that holds the language files. The second part, application, gives the filename “stem” of the language files (without the .properties extension and country code). A full list of country codes is at http://ftp.ics.uci.edu/pub/ietf/http/related/iso639.txt.
So if you wish to store your language files somewhere else, you use this method to specify their location. Don’t forget that you must reload the application context again whenever you adjust any configuration or language files.
You can organize your language keys within the language files in the following form:
classname.definition [.<further subdivision>]
You can group the keys according to how frequently you expect to use them. Have one row of single words, such as general.street=street.
Always make sure to define all the required keys, as it enables error messages to be generated correctly.
The language files used above show the problem with the naming convention. It is often not clear how to name each part and so one tends to choose the first thing that comes to mind. In this case you may end up with many placed under Author, for instance, even
though they would be better placed in the general category. Such little details can be really beneficial as you use the files in a day-to-day context. It is much simpler to correct such mistakes immediately, rather than trying to remember illogical key conventions.
Managing the properties files
Many development environments can help manage the properties files. The Netbeans IDE, which comes with the Java SDK, shows keys sorted alphabetically and you can work with more than one language file at once. In long files, the alphabetical ordering turns out to be difficult to work with, and so you may prefer to use your own sorting and a simple text editor. Experiment with this a little bit!
One time-tested approach has been to separate the language files into smaller files and then consolidate them with Ant. This allows different developers to maintain individual files. The problem is to clearly define the categories for each file and stick to them since
this approach can easily lead to omissions and repetitions.
The Welcome Page for the Shop
In Chapter 1, we wrote a very simple page to demonstrate the use of language files. It is reproduced below:
Listing 4.2: index.jsp
<%@ page language="java" %> <%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %> <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %> <html:html locale="true"> <!-- line 5 --> <head> <html:base/> <title> <bean:message key="index.title"/> <!--line 9 --> </title> </head> <body> <h2><bean:message key="index.title"/></h2> <% out.println(request.getHeader("User-Agent")); %> </body> </html:html>
- Line 1: This is a JSP directive (indicated by the enclosing <%@ … %>) specifying the language used in any scriptlets on the page. As Java is the default language, this line is often omitted, but is necessary if you are using a mixture of languages (for example, Java and JavaScript using JRun instead of Tomcat).
- Lines 2 and 3: These are directives that act somewhat like import statements in normal Java classes. We need them if we wish to use custom actions on the page (see the Custom Actions section).
- Line 5: The locale=”true” in this line indicates that multilingualism is to be applied (see the exercises at the end of the chapter).
- Line 9: This uses a bean tag (see the Custom Actions section), which represents an object of the org.apache.struts.taglib.bean.MessageTag class. The message bean is called with a key attribute of index.title. Struts now searches for suitable language files for the language specified by the browser and inserts the corresponding text in place of the tag.
Visitors to our shop will be greeted with a welcome page in either their preferred language or the default language. Change index.jsp so that a company logo and a copyright notice are displayed:
Listing 4.3: index.jsp
<%@ page language="java" %> <%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %> <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %> <html:html locale="true"> <head> <html:base/> <title> <bean:message key="index.title"/> </title> </head> <body> <h2><bean:message key="index.title"/></h2> <img src="pics/logo.jpg" alt="Logo" /> <br /> <br /> <bean:message key="general.copyright"/> </body> </html:html>
You’ll need to create a new pics folder for the logo directly under the main shop2 folder. Choose a suitable image file to use and place it in the folder with the name logo.jpg. Relevant text for the general.copyright key must also be added to the language files.
Multilingual Images
The Struts tag allows different languages to use different images, each with different alt text:
And then the following lines are required in the language files:
button.clickMe.src=/images/button_clickMe.jpg
button.clickMe.alt=Click Me
See http://jakarta.apache.org/struts/userGuide/
struts-html.html#img for more details.
Exercise 1
Create a second logo for another language. Change index.jsp to display the logo in the user’s language. Be brave: you can mix normal HTML and Struts!
Custom Actions
JSP supports user-defined tags or Custom Actions according to the tag extension mechanism defined by the JSP specification. Custom actions have access to all the information from the Request and Response objects, and can use variables in the session. A set of custom actions is called a Tag Library or Taglib.
As Struts is simply a set of custom actions, it makes sense to know how they are created.
Before going into details we’ll run through a simple example. We’ll create a small action that displays the date according to the user’s local convention (refer to Chapter 12 for more on this topic).
Custom actions are usually developed and deployed in JAR files. In our case though, we will be using the class files compiled from our source code as we write it, so create a subdirectory called mytags under WEB-INF/classes to hold the tag files. Create a new Java file in this directory and name it CountryDate.java. Enter the following code:
Listing 4.4: CountryDate.java
package mytags; import javax.servlet.*; import javax.servlet.jsp.*; import javax.servlet.jsp.tagext.*; import java.text.DateFormat; import java.util.Date; import java.util.Locale; public class CountryDate extends javax.servlet.jsp.tagext.TagSupport { protected PageContext pageContext; public void setPageContext(PageContext pageContext) { this.pageContext = pageContext; } public int doStartTag() throws JspException { Date today = new Date(); ServletRequest request = (ServletRequest)pageContext.getRequest(); Locale user = request.getLocale(); DateFormat dateFormatter = DateFormat.getDateInstance(DateFormat.DEFAULT, user); String now = dateFormatter.format(today); try { pageContext.getOut().write(now); } catch(java.io.IOException ex) { throw new JspException(ex.getMessage()); } return EVAL_BODY_INCLUDE; } }
The CountryDate class extends the interface javax.servlet.jsp.tagext.TagSupport. This ensures that Tomcat will automatically recognize it and call setPageContext() passing in environment information (request, session, etc.).
The doStartTag() method is also defined by the interface. It is called whenever Tomcat encounters the action embedded in a JSP. In this code, this method gets the user’s locale from the browser request, and uses it to create a DateFormat object based on the default
date format for that locale. Finally, we get today’s date—suitably formulated using the format() method of the DateFormat object—and write it to the current output stream. This is usually the response page, which the user sees.
If you try to compile the class now, you will get an error message saying:
C:\Tomcat\webapps\Shop2\WEB-INF\classes>javac mytags/*.java mytags/CountryDate.java:3: package javax.servlet.jsp does not exist import javax.servlet.jsp.*; ^
We see this because the JSP and servlet packages, servlet-api.jar and jsp-api.jar, are not part of the standard Java packages and so must be added to the classpath.
Adding the JSP and servlet packages to the classpath
You can either add servlet-api.jar and jsp-api.jar (found within Tomcat’s
common\lib directory) to your classpath environment variable, or you can
specify them with the -classpath switch every time you compile with javac.A good idea is to make a batch file (a text file with a .bat extension) in your
classes directory containing the following two lines:javac -classpath “%CATALINA_HOME%\common\lib\jsp-api.jar”;
“%CATALINA_HOME%\common\lib\servlet-api.jar” mytags/*.javapause
As a batch file, you can simply double click it from Windows explorer to
compile all the Java files in the mytags subdirectory. Note that if you added jspapi.
jar and servlet-api.jar to your classpath, you can omit the classpath
switch shown above.
In order to use this custom action in a JSP, it must be declared and reported to Tomcat.
The web.xml file, which we got when we copied the struts-blank template, contains various elements. These reference the TLD configuration files that define custom actions. Insert the following lines after the other Taglib entries in the web.xml for shop2:
<taglib> <taglib-uri> http://www.stephanwiesner.de/struts </taglib-uri> <taglib-location> /WEB-INF/taglib.tld </taglib-location> </taglib>
The element is a way to identify a particular Taglib uniquely, allowing two different Taglibs to contain a custom action with the same name but still be used at the same time. It doesn’t have to be a valid URL; a company (or individual) URL is often used because the company can be fairly sure no one else will use that to identify their own Taglib. So naturally, you can replace my name with your name, but remember that the name you choose should be consistent in every place where it’s used. The element specifies the name and path of the Taglib configuration file, here /WEB-INF/taglib.tld. Not surprisingly, you’ll need to create this file as well. It’s an XML file and should have the following content:
<b>Listing 4.5: taglib.tld</b> <?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.// DTD JSP Tag Library 1.1//EN" "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd"> <taglib> <tlibversion>1.0</tlibversion> <jspversion>1.1</jspversion> <shortname>shop</shortname> <uri>http://www.stephanwiesner.de/struts</uri> <info>Taglibs for the Struts book</info> <tag> <name>countryDate</name> <tagclass>mytags.CountryDate</tagclass> <info>Displays a formulated Date</info> </tag> </taglib>
Make sure that the mytags.CountryDate package specification in the element is correct. The element contains some descriptive text. The element defines the name that JSPs must use when they invoke our custom actions.
Now, restart the application context (or Tomcat) and we can use our new custom actionin a JSP:
<b>Listing 4.6: index.jsp</b> <%@ page language="java" %> <%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %> <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %> <b><%@ taglib uri="http://www.stephanwiesner.de/struts" prefix="sw" %></b> <html:html locale="true"> <head> <html:base/> <title><bean:message key="index.title"/></title> </head> <body> <h2><bean:message key="index.title"/></h2> <img src="pics/logo.jpg" alt="Logo"/> <br /> <br /> <bean:message key="general.copyright"/> <br /> <sw:countryDate /> </body> </html:html>
Notice the third taglib page directive (enclosed in <%@ … %>) that imports our custom actions:
<%@ taglib uri="http://www.stephanwiesner.de/struts" prefix="sw" %>
The namespace given in the uri attribute must match exactly with the and elements in the configuration files. The prefix attribute specifies the prefix that will be used in the JSP page code to identify custom actions associated with this URL. So, to use the countryDate custom action, we use the following tag:
<sw:countryDate/>
All this fuss with naming might seem unnecessarily verbose and tiresome. However, imagine another Taglib written by someone else, which also defines a custom action named countryDate, but which has a quite different purpose to ours. Because they are contained in packages that have different URLs, we could use both on the same page without any ambiguity: .
. . <%@ taglib uri="http://www.stephanwiesner.de/struts" prefix="sw" %> <%@ taglib uri="http://www.java.com/jsp" prefix="sun" %> . . . <sw:countryDate /> is not the same as <sun:countryDate />
As you see, custom actions bear many similarities to normal HTML tags and the idea is that they can be used by web designers who know only HTML.
Like JavaBeans, custom actions make for simpler usage of frequently repeated functionality, without the need for Java code in scriplets to be embedded in the HTML. For further information, check out Hans Bergsten’s JavaServer Pages, from O’Reilly
(2000, ISBN 1-56592-746-X) or http://www.javaworld.com/javaworld/jw-08-2000/jw-0811-jsptags.html.
struts-bean.tld
Now that you have a basic knowledge of Taglibs, we are ready to move deeper into Struts. Open up the file WEB-INF/struts-bean.tld in your preferred editor and search for message. You will find an entry, on or around line 149, which defines the action that you have just used:
<bean:message key="index.title"/>
The bean:message tag can take up to five parameterized arguments, numbered 0 to 4. We can assign a key and a scope to it as well.
It is instructive to have a quick skim through the documentation and see how each is used. You’ll find it at
http://127.0.0.1:8080/struts-documentation/userGuide/struts-bean.html.
<b>TagUtils</b> Struts comes with the very useful org.apache.struts.taglib.Tag-Utils class. This class contains a range of helper functions that you will find handy when building taglibs.
Exercise 2
- What happens when you leave out locale=true in a JSP? What if you set locale=false?
- What happens if a key of a message bean has no corresponding entry in the language file?
- Enhance the welcome page. Change the logo and copyright info and write a short multilingual introduction.
- How would you implement one more language (for example, Spanish)? How complex would it be?
- Could you allow the user to choose the language explicitly, and if so how? For example, could you offer a button on the page?
- Think about how you could provide more extensive text in multiple languages, such as a help page? The standard language files do not provide much help here, because they can only handle short texts efficiently. (Hint:Take another look at the first custom action example.)
- Why shouldn’t you work on the file WEB-INF/struts-bean.tld? Think about what would happen if you did add your own settings to that, and then a new version of Struts was released.
Summary
This chapter provided a short introduction to Taglibs and custom actions, and took a first glance at the inner life of Struts. Our shop now has a welcome page, although it’s pretty sparse and not so attractive yet!