JSP Standard Tag Library

Many developers criticized the original JSP specification because it lacked some important basic capabilities. As we saw earlier in the chapter, you can implement complex logic within JSPs by embedding scriptlets. This approach works (at least, it’s functional and produces web pages that look about right), but it makes JSPs look a lot less like HTML and a lot more like Java code. As a result, the range of people who can work on them is sharply limited. To make things even worse, because developers were virtually forced into embedding large amounts of Java code into each page (at least if the page were in any way complex), business logic had a tendency to creep down into the presentation layer.

The JSP EL removes some of the need for scriptlets (you can now display a variable without embedding Java code directly) but doesn’t help implement page logic. That’s where the JSP Standard Tag Library (JSTL ) comes in. JSTL is not directly part of the JSP standard, but it’s an associated standard, and JSTL Version 1.1 (which is compatible with JSP 2.0) is also included in J2EE 1.4. In this section, we’ll discuss the most commonly used JSTL tags for variable handling, flow control, and internationalization.

The JSTL tags are easy to incorporate into your web applications. J2EE 1.4- compatible containers include all the necessary jar files. Standalone servlet/JSP containers, such as Tomcat, don’t, so you’ll need to obtain both the jstl.jar file and an implementation of the tags themselves separately. The reference implementation for JSTL grew out of the Jakarta taglibs project, and can be downloaded from http://jakarta.apache.org/taglibs/index.html. Put both jar files (the implementation from Jakarta is in standard.jar) into your WEB-INF/lib directory.

Once the JSTL tags are available to the web application, you need to map them to a namespace for each JSP. This is easy enough; just add the following line to the top of each page:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core"
    prefix="c" %>

By convention, the JSTL tags are given the prefix c.

Variables and Flow Control

The <c:set> and <c:remove> tags provide basic variable handling for JSPs. In general, these tags should be used carefully: you very rarely need to manipulate variables within the JSP itself, other than possibly for page layout purposes, and in most cases the EL will suffice. But if you must, the following JSP file retrieves a variable from the request parameter (using the built-in param object and an EL expression), sets it to a session variable, displays the variable, and then removes the variable from the session:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core"
    prefix="c" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
 
<html>
    <c:set var="username" scope="session" value="${param.username}"/>
    <c:out value="${username}" escapeXML="false"/>
    <c:remove var="username"/>
</html>

This JSP also uses the <c:out> tag to display the variable. This tag was, before JSP 2.0, the only nonscriptlet method to display a variable in a JSP. Now that we have the EL, the use of <c:out>, which is much clunkier, can be reduced but not quite eliminated. Unlike a regular EL expression, the <c:out> tag escapes all XML characters into XML/HTML-safe entities. The > character becomes &lt; and so on. If you expect to display variables that might include HTML or XML reserved characters, you should use <c:out> rather than embedding the bare expression into the page.

Flow control

JSTL includes tags for loops and conditional logic, freeing the page author from the tyranny of scriptlets. We saw one of these tags, <c:if> , in the previous section. The <c:if> tag evaluates an EL expression to true or false and, if true, processes the JSP code contained within the tag.

There is no corresponding else tag—you need to use another <c:if> with an inverse condition or, if there are multiple conditions, the <c:choose> tag. In the following extremely contrived example, we display one message if a variable is 1 or below, another if it is 2 or 3, and a final message if it’s greater than 3. The first two determinations are made using the <c:when> tag, which evaluates a conditional within a choose block, and the final message is displayed using a <c:otherwise> tag, which provides an optional fall-through action:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core"
    prefix="c" %>
 
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
 
<c:set var="niftylevel" value="5"/>
 
<c:choose>
    <c:when test="${niftylevell < 2}">
        Not terribly nifty.
    </c:when>
    <c:when test="${niftylevel > 1 and niftylevel < 4}">
        Nifty, but could be niftier.
    </c:when>
    <c:otherwise>
        Remarkably nifty.
    </c:otherwise>
</c:choose>

Processing stops when a condition is met—so setting the niftylevel variable to 3 after printing out the first message does not cause the second message to print.

Finally, JSTL includes a very robust loop tag, <c:forEach> . This tag accepts any standard Collection implementation, any standard Map implementation, arrays of primitive types, and even strings containing comma-separated values.[22]

In this example, the request attribute catalog contains an ArrayList holding a set of Product objects. The JSP works through the list, creating a temporary page variable named product and printing out each list entry.

<%@ taglib uri="http://java.sun.com/jsp/jstl/core"
    prefix="c" %>
 
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head><title>Widget Catalog</title></head>
  <body>
    <ul>
    <c:forEach var="product" items="${catalog}">
        <li>${product.name}: $${product.price}</li>
    </c:forEach>
    </ul>
  </body>
</html>

URL management

JSTL provides basic support for URL management. This functionality is important if you are using URL rewriting to track sessions and can also simplify page design if you’re assembling complex URLs. The <c:url> tag simply accepts a (content-relative) URL and an optional set of request parameters and displays a properly formatted URL.

For example, in our catalog example, we could replace the contents of the <c:forEach> tag with the following code to produce a URL that would link to a product detail page, passing in the product’s Stock Keeping Unit (SKU) code as a URL parameter named productID:

<c:url var="producturl" value="/product" >
  <c:param name="productID" value="${product.SKU}" />
</c:url>
<li><a href="${producturl}">${product.name}</a> - $${product.price}</li>

Internationalization

JSTL includes tags that support the Java internationalization standards. Unlike the tags we’ve looked at so far, the internationalization formatting tags reside in the fmt package rather than the core package.

Java’s internationalization functions, in a proverbial nutshell, let developers move the display constants from an application to an external properties file, also known as a resource bundle. The properties file can then be translated into other languages, making it easy to write multilingual applications. The strings are kept in the standard properties file format:

first.name=First Name
last.name=Last Name

To use these two properties in a JSP file, we first make the properties file accessible to the web application by placing it in the classpath. If we name the file messages.properties and place it in WEB-INF/classes, we have created a resource bundle named messages. To provide other languages, we provide other files with the same base name followed by the two-character language code for the language in question. A German language resource bundle would be named messages_dk.properties and an explicitly English language bundle would be called messages_en.properties.

The <fmt:message> and <fmt:bundle> tags handle message display. Consider the JSP in Example 4-1.

Example 4-1. message.jsp

<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt"
    prefix="fmt" %>
 
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head><title>Message Bundle Example</title></head>
    <body>
        <form>
            <fmt:bundle basename="messages">
            <table>
                <tr><td>
                    <fmt:message key="first.name"/>
                </td><td><input type="text" name="firstname"></td></tr>
                <tr><td>
                    <fmt:message key="last.name"/>
                </td><td><input type="text" name="lastname"></td></tr>
            </table>
            </fmt:bundle>
            <input type="submit" value="Submit">
        </form>
    </body>
</html>

The <fmt:bundle> tag sets the message bundle using the basename attribute. The two <fmt:message> tags retrieve the messages from the resource bundle by name. The resulting page looks like Figure 4-4.

Internationalized screen (in English)

Figure 4-4. Internationalized screen (in English)

It’s possible to skip the <fmt:bundle> tag, either by using the <fmt:setBundle> tag (which sets the bundle for the entire page) or by including a bundle attribute on the <fmt:message> tag itself.



[22] Iterator and Enumeration objects are also supported, but with limits, since both types of objects can be processed only once.

Get Java Enterprise in a Nutshell, Third Edition now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.