Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Beginning Apache Struts - From Novice To Professional (2006)

.pdf
Скачиваний:
57
Добавлен:
17.08.2013
Размер:
11.68 Mб
Скачать

118 C H A P T E R 1 0 M O R E T A G S

JSTL and Struts

As we mentioned earlier, JSTL was created to give JSP developers a comprehensive set of tags to perform a variety of generic tasks. The ultimate goal is to allow JSP developers to avoid using scriptlets altogether.

You might ask what makes JSTL a more compelling alternative to scriptlets. Consider Listing 10-5 and then look at Listing 10-6, the JSTL version.

Listing 10-5. Counting to 99

<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html>

<body>

<%

for(int i = 1; i <= 99; i++){

%>

This is iteration number <%= i %>

<%

}

%>

</body>

</html>

Listing 10-6. Counting to 99 with JSTL

<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %> <html>

<body>

<c:forEach var="i" begin="1" end="99" step="1">

This is iteration number <c:out value="${i}"/> </c:forEach>

</body>

</html>

Even in this simple example it’s obvious that the JSTL example (Listing 10-6) is much more readable than Listing 10-5, which uses scriptlets.

Now, like I said, JSTL is a huge body of useful tags and covering them effectively would require an entire book.

Note You could check out Pro JSP 2, 4th Edition (Apress, 2005). This book covers JSP 2.0, JSTL, and much more.

C H A P T E R 1 0 M O R E T A G S

119

What I will discuss here is the intersection between JSTL and Struts tags. Fortunately, this intersection is manageable. JSTL consists of four tag libraries: the Core, Formatting, XML Processing, and Database Access tag libraries. Of these, only the Core and Formatting tag libraries fall into the intersection. From these, only a few tags concern us. They fall into three categories:

Output: Performed by the <c:out> tag. In Struts, you’d use <bean:write>. There are also a number of tags from the Formatting tag library to format text and display resource messages.

Iteration: Performed by the <c:forEach> tag. The analogous Struts tag is

<c:iterate>.

Conditional processing: Performed by the <c:if> and <c:choose>...<c:when> tags. These have a lot of tags from the Struts Logic library as counterparts.

Before I describe these three JSTL tags, let’s take a look at the expression language (EL). Much of the power of JSTL is attributable to the use of EL within its tags.

Note Although I’m introducing EL here with JSTL tags, this is for purely pedagogical reasons. EL is independent of JSTL and is part of the JSP 2.0 specification.

Expression Language (EL)

EL allows the attributes of “EL-enabled” tags to assume dynamic values. Before EL, if you wanted dynamic attributes, you had to embed scriptlets or custom tags within the attribute (see Listing 10-7), resulting in difficult-to-read code.

Listing 10-7 illustrates a typical situation where dynamic attributes are important and how you might use scriptlets to achieve this functionality. The snippet alternately colors the rows of a table gray, using a (fictitious) custom tag, <h:tr>, to write out HTML table rows with some fancy formatting.

Listing 10-7. Alternately Coloring the Rows of a Table Gray

<% for(int i = 0; i < 10; i++){ %>

<h:tr bgcolor="#<%= (i%2 == 0)? 'FFFFFF' : 'DDDDDD' %>" > <td> This is row number <%= i %> </td>

</h:tr> <% } %>

Unless you’re a Perl programmer, I’m sure you’ll agree that Listing 10-7 is difficult to read. EL solves this problem by allowing EL-enabled tags to have dynamic attributes.

120 C H A P T E R 1 0 M O R E T A G S

For example, if <h:tr> were an EL-enabled tag, then Listing 10-7 could be rewritten as shown in Listing 10-8, which is more readable.

Listing 10-8. Alternately Coloring the Rows of a Table Gray, with EL and JSTL

<c:forEach var="i" begin="0" end="9" step="1">

<h:tr bgcolor="#${(i%2 == 0)? 'FFFFFF' : 'DDDDDD'}"> <td> This is row number <c:out value="${i}"/> </td>

</h:tr>

</c:forEach>

Now, EL isn’t just scriptlets with ${...} delimiters instead of <%...%> delimiters. EL includes several keywords and operators that aid in its role of endowing tags with dynamic attributes. We’ll take a look at this next.

Using EL

EL expressions are evaluated within the ${...} delimiters. Within an EL expression, you can use a number of common operators:

Arithmetic operators: +, , % or mod, *, / or div

Logical operators: and or &&, or or ||, not or !

Comparisons: < or lt, <= or le, == or eq, != or ne, > or gt, >= or ge

Conditional evaluation: (condition) ? A : B returns A if condition is true and B otherwise. A or B may be fixed strings (e.g., astring) or a variable or numeric value. However, to make your code readable, keep it simple.

empty operator: Prefix empty to the name of an object to determine if it is empty (an array, Collection, Enumeration, HashMap, or Iterator) or null (any other object).

These operators should require no further explanation, since they are similar to those in Java.

You may also use nested and indexed properties with EL. Nested properties are the same as for Struts: the . separator in a name indicates a nested property. For example:

${myObject.myProperty}

returns the value of myObject.getMyProperty(). No surprises here.

Indexed properties with EL do double duty. You can index with a numeric value, a string, or a variable. Indexing with a string is the same as using a mapped property. Table 10-3 offers some examples.

C H A P T E R 1 0 M O R E T A G S

121

Table 10-3. Indexed Properties and EL

EL Expression

Value

${myArray[2718].name}

myArray[2718].getName()

${myMap['exp'].value}

myMap.get("exp").getValue()

${myArray[myOffset]}

Returns the element on myArray with an index equal to the

 

variable myOffset.

 

 

Lastly, EL exposes several implicit objects, which are built-in objects that your EL expressions will always have access to. There are a quite few of these, and I won’t go through every one. To learn more, refer to Sun’s J2EE tutorial (see “Useful Links”).

Note A common pitfall is to use a variable name coinciding with the name of an implicit object. For example, calling a variable of your own “requestScope” is a no-no. There are also a number of reserved keywords that you must avoid. These are given in Sun’s tutorial (see “Useful Links”).

Among the most important implicit objects are those representing the various scopes. These allow you to explicitly access your variables by scope. These scope objects are pageScope, requestScope, sessionScope, and applicationScope. Suppose you want to access a session-scoped variable named myObject. Here’s how:

${sessionScope.myObject}

Variables on other scopes are accessed in a similar manner.

In this section, we’ll examine the use of EL in the JSTL tags <forEach>, <if>, <choose>...<when>, and <out>, which are relevant to Struts. I hope that after you read this section you will have sufficient exposure to EL to be able to use it well.

The <c:out> Tag

The <c:out> tag outputs text, and is in many instances a replacement for <bean:write>. The usage of this tag is simple, since it has just one value attribute:

<c:out value="${myObject.myProperty}">

A quick look at Appendix C will show you that <bean:write> isn’t a one-trick pony—it has attributes you can use to format the displayed value. You can’t do this with just <c:out>; you’d have to use the JSTL Formatting tag library. Using this tag library requires a more thorough treatment of JSTL than can be done here. Again, check out Pro JSP 2, 4th Edition, if you’re interested in learning more.

122 C H A P T E R 1 0 M O R E T A G S

The <c:forEach> Tag

The <c:forEach> tag is used for iteration. You can use it instead of the Struts <logic:iterate> tag. You’ve seen how to use <c:forEach> to perform iteration over a fixed set of limits (see Listings 10-6 and 10-8). You can also use it to perform iteration over a Java array, Collection, Enumeration, or Iterator. Listing 10-9 shows you how to do this.

Listing 10-9. Using <c:forEach> to Iterate Over an Iteratable Object

<c:forEach var="item" items="${sessionScope.myIteratable}"> <c:out value="${(empty item)? 'nil' : item.myProperty}"/>

</c:forEach>

The two important attributes here are var, which exposes a single element of the iteratable object, and items, which is the name of the iteratable object. Note how Listing 10-9 uses the myIteratable object, specifically with session scope, using the sessionScope implicit object.

Flashback Quiz

Can you remember what the counterparts of var and items were on <logic:iterate>?

There is an additional useful attribute called varStatus, which gives you information on the current iteration. varStatus has four properties:

first and last, which return true or false depending on whether the current iteration is the first or last one in the loop.

count, which gives you the number of the current iteration. This starts at 1.

index, which gives you the absolute index of the current iteration. This starts at 0, and is incremented according to the value of the step attribute.

Listing 10-10 shows varStatus in action.

Listing 10-10. The first, last, count, and index Properties of varStatus

<c:forEach begin="10" end="15" step="2" varStatus="status"> <c:out value="${status.first}"/>

<c:out value="${status.last}"/> <c:out value="${status.count}"/> <c:out value="${status.index}"/><br>

</c:forEach>

C H A P T E R 1 0 M O R E T A G S

123

The output of Listing 10-10 would be

true false 1 0 false false 2 2 false true 3 4

The last two JSTL tags we’ll look at are <c:if> and <c:choose>...<c:when> for conditional processing.

The <c:if> and <c:choose>...<c:when> Tags

<c:if> allows you to process a single block of code if a test passes. The test itself is an EL expression referred to by the test attribute, as shown in Listing 10-11.

Listing 10-11. <c:if> in Action

<c:if test="${(empty user.userid || empty user.password)}"> Please key in your User ID and password.

</c:if>

In Listing 10-11, the message is displayed if the user ID or password are null. The <if> tag doesn’t support an else or if else block. If you want these, then you have to use the clumsier <choose> ... <when> tags (see Listing 10-12). If you’ve used Extensible Stylesheet Language (XSL), this should be very familiar.

Listing 10-12. <c:choose>...<c:when> in Action

<c:choose>

<c:when test="${empty user.userid}"> Please key in your userid.

</c:when>

<c:when test="${empty user.password}"> Please key in your password.

</c:when>

<c:when test="${not user.loggedIn}"> Sorry, couldn't log you in.

</c:when>

<c:otherwise>

You're logged in! </c:otherwise>

</c:choose>

In Listing 10-12 there are two when clauses that test if the user ID and password are null, and another that tests whether the user is logged in. The last otherwise tag is a catchall block. Note that the otherwise block is optional.

124 C H A P T E R 1 0 M O R E T A G S

Now You Do It

Earlier in this chapter, I mentioned that some of the conditional processing tags have JSTL equivalents. Construct JSTL equivalents for

equal, present, empty, lessThan, lessEqual, greaterThan, and greaterEqual

The negatives for all of the above (notEqual, notPresent, etc.)

Refer to Appendix C if you need definitions for these tags. Appendix D contains the answers.

This section ends my treatment of JSTL. In the next section, we’ll describe an extension to the original tag libraries that allows them to process EL.

Struts EL Extensions

In order for EL to work in a custom tag, that tag has to be EL enabled. The current set of Struts tags aren’t EL enabled, so this won’t work:

//won't work!!

<bean:write name=${(empty obj)? obj2.prop : obj.prop />

A set of EL-enabled Struts tags is available with the latest Struts distribution. You’ll find these new tags in the ./contrib/struts-el/lib/ folder of the distribution. Also available in this folder is an implementation of JSTL. If you use these Struts EL tag libraries, you can use EL expressions in your Struts tags.

Of course, you’d have to use the corresponding Struts-EL tag, not the original Struts tag. The following snippet illustrates this:

//OK

<bean-el:write name=${(empty obj)? obj2.prop : obj.prop />

Of course, just changing the prefix won’t work—you’d have to change the taglib declaration in the JSP and put in a new <taglib> section in web.xml to point to the Struts-EL bean tag library.

The Struts-EL tag libraries only implement a selection of tags from the original Struts tag libraries. The tags not implemented are assumed to have counterparts in JSTL.

Note In order to use the JSTL and Struts-EL tags, you have to have a servlet container that implements the JSP 2.0 specs, which necessitates EL support. Tomcat 5.x is JSP 2.0 conformant.

C H A P T E R 1 0 M O R E T A G S

125

Lab 10a: The LILLDEP Full Listing Page

In this lab, you will create a page that lists all the entries in the LILLDEP database.

Step 1: Complete ListingAction

Complete the implementation of the Action subclass ListingAction so that it prepares an Iterator over the LILLDEP database. The following line of code shows how to get an Iterator containing all Contacts in the database:

Iterator everything = ContactPeer.doSelect(new Criteria());

(Refer to the sections on Lisptorq in Appendix A for details.) Ensure that your ListingAction implementation does the following:

Forwards to the page named success.

Puts the Iterator of Contacts on the request object (refer to the earlier section on <logic:iterator> to see how this is done). Instead of using an ad hoc name for the object, use a suitable name on the interface JSPConstants. This is helpful because all names shared between JSP and Action classes are stored in one file, JSPConstants.

Step 2: Complete listing.jsp

Complete the implementation of listing.jsp, using <logic:iterate> to list the following fields in a table:

name

email

company

address

postcode

website

When users click on website, it should take them to the company’s website.

Step 3: Amend web.xml

Put in a declaration in web.xml for the Struts Logic tag library.

126 C H A P T E R 1 0 M O R E T A G S

Step 4: Amend struts-config.xml

Put in a new action mapping in struts-config.xml:

The path should be /Listing.

This action mapping should tie together ListingAction and listing.jsp.

Question: Will you need a form bean for this action mapping? (See Appendix D for the answer.)

Compile, redeploy, and test your work. The main full.jsp page has a link on the toolbar called Full Listing that invokes the handler Listing.do.

Note Remember that you will have to reenter contacts because redeployment destroys the old database.

Lab 10b: Simplifying ContactForm

In the earlier section on the nested tag library, I mentioned that you can use the Nested tag library or nested properties to simplify ActionForm subclasses.

This is certainly the case for ContactForm, which has many getters and setters. Most of these can be removed if you use the nested library or nested properties.

Complete the following steps.

Step 1: Amend ContactForm

Remove all getters and setters on ContactForm except getModel() and setModel(). Question: If you compiled and deployed LILLDEP now, would it work? Why or why not? (See Appendix D for the answer.)

Step 2: Amend full.jsp and mnc.jsp

Use either the Nested tag library or nested properties to ensure that all fields and error messages display correctly on both these forms.

Question: In either approach, what is the new base object? (See Appendix D for the answer.)

Note If you choose to use the Nested tag library, remember to add a section in web.xml to declare it.

Compile, redeploy, and test your work.

C H A P T E R 1 0 M O R E T A G S

127

Lab 10c: Using JSTL

In this lab, I’d like you to use JSTL’s <c:forEach> tag rather than the <logic:iterate> tag in listing.jsp.

Step 1: Install the JSTL and Struts EL Tag Libraries

Open the Struts distribution found in the Source Code section of the Apress website at http://www.apress.com; it’s contained in a zip file named jakarta-struts-1.2.6.zip.

1.Copy all the JAR files in the .\contrib\struts-el\lib\ folder to LILLDEP’s \lib folder, taking care to overwrite the existing files.

2.Copy all TLD files to LILLDEP’s \web\WEB-INF\ folder. Again, overwrite the older files.

Step 2: Amend web.xml

Add a <taglib> entry declaring the JSTL core tag library, c.tld. The recommended URI is http://java.sun.com/jstl/core, but of course, you’re free to use anything you like.

Step 3: Amend listing.jsp

In listing.jsp, use JSTL’s <c:forEach> tag rather than the <logic:iterate> tag. Remember to add to add a taglib declaration for the JSTL core tag library at the start of the page.

As usual, compile, redeploy, and test your work.

Useful Links

Struts Apache online reference for the Logic tag library: http://struts.apache.org/ struts-doc-1.2.x/userGuide/dev_logic.html

Struts Apache online reference for the Nested tag library: http://struts.apache. org/struts-doc-1.2.x/userGuide/dev_nested.html

Pro JSP 2, 4th Edition, by Simon Brown, Sam Dalton, Daniel Jepp, Dave Johnson, Sing Li, and Matt Raible (Apress, 2005)

JSTL specs: www.jcp.org/en/jsr/detail?id=052