5.3 JSTL

EL saves the day by beautifully simplifying the JSP, but sometimes we need more than it. For example, can you express if or for in EL? The answer is no. To this end, custom tags are designed. They look like HTML tags, but they can help you express logics (e.g., if and for) while getting away from scripting. Even better, the community has already written a pile of tags you're most likely to need, and bundled then into the JSP Standard Tag Library (JSTL).

How to install JSTL

JSTL is not part of the JSP specification[1], so we have to download both its API and implementation in our project. However, the latest version of JSTL in javax namespace is 1.2.2, and it depends on servlet-api:2.5, el-api:2.2 and jsp-api:2.2. So there may be packages version conflicts problems. To solve those conflicts, we shall exclude them in the dependency:

implementation('org.glassfish.web:javax.servlet.jsp.jstl:1.2.5') {
    exclude group: 'javax.el', module: 'el-api'
    exclude group: 'javax.servlet', module: 'servlet-api'
    exclude group: 'javax.servlet.jsp', module: 'jsp-api'
}

Then in the JSP file, we add the taglib directive:

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

Where prefix is a customized prefix name, and you can use other names if you like; you can think of uri as an address or a namespace, which looks like a URL. It must start with http://java.sun.com/jsp/jstl in JSTL 1.2, and core is one of tag libraries[2].

JSTL examples

In this subsection, we will learn how to use JSTL through examples, and the code can be found at ch5/jstl.

[!NOTE] Similar to HTML tags, different tags in JSTL have different attributes, and some are optional while some are required.

Suppose foo is not the attribute's name, then ${foo} won't output anything. But if we would like to output a default value when it is empty:

<c:out value="${user}" default="Guest"/>

Where <c:out> is a tag defined in JSTL, and c is the prefix we defined in the taglib directive.

Suppose an array is put into the attribute,

String[] books = {"Gone with the Wind", "The Great Gatsby",
        "1587, a Year of No Significance"};
request.setAttribute("bookArray", books);

Let's iterate an array in the attribute.

<c:forEach var="book" items="${bookArray}">
    ${book}
</c:forEach>

Figure 5.5 The forEach tag.

As we see, <c:forEach> can replace for in the scriptlet.

<c:if> is able to replace if:

<c:if test="${balance > 88}">
    You are rich.
</c:if>

Where test attribute accepts a boolean value. Note that if we use a String literal, it should be enclosed with the single quote.

<c:if test="${name == 'Mary'}">
    You are Mary.
</c:if>

However, <c:if> tag cannot express else. If you would like to express if...else, you can use <c:choose> tag:

<c:choose>
    <c:when test="${balance > 88}">
        You are rich.
    </c:when>
    <c:otherwise>
        You are poor.
    </c:otherwise>
</c:choose>

There are a plenty of tags defined in JSTL, but basically, <c:forEach>, c:if> and <c:choose> can cover most of your daily programming tasks.

As a final example, let's try to iterate a Map.

Map<String, Integer> bookCount = new HashMap<>();
bookCount.put("Gone with the Wind", 42);
bookCount.put("The Great Gatsby", 100);
bookCount.put("1587, a Year of No Significance", 130);
request.setAttribute("bookCount", bookCount);
<c:forEach var="book" items="${bookCount}">
    ${book.key}
    ${book.value}
</c:forEach>

[1] In the book, we use Java EE 8 with servlet-api:4.0.1, el-api:3.0.0 and jsp-api:2.3.3, and both APIs and implementations are provided by the container. See more at Apache Tomcat Versions.

[2] There are other tag libraries, such as fmt and sql. It is a convention to use c as the prefix for core tag library. You can even write you own tags, but this is also considered bad.