JSTL Core Tags: Flow Control Tags
April 04, 2010 04:12:14 Last update: July 21, 2010 14:52:58
The tags
The
In my opinion, the version without body content is pretty much useless (the
These tags imitate the Java control structure
The
The typical use is like this:
where
If
The iteration status variable
The
Test it
Make these additions to the expanded test application:
<c:if>
The
<c:if> tag may be used with or without body content:
<!-- Without body content, used to export variable named by the var attribute --> <c:if test="testCondition" var="varName" [scope="{page|request|session|application}"]/> <!-- With body content, which is inserted into the page when testCondition evaluated to true. --> <c:if test="testCondition" [var="varName"] [scope="{page|request|session|application}"]> body content </c:if>
In my opinion, the version without body content is pretty much useless (the
<c:set> tag is a lot more meaningful for this purpose). If body content exists, it is inserted into the page if the testCondition is true. Optional attributes var and scope may be specified. If var is specified, a variable whose name is the value of var is exported to the associated scope (pageScope if no scope is specified). The type of the exported variable is Boolean and its value is the value of the testCondition.
<c:choose>, <c:when>, <c:otherwise>
These tags imitate the Java control structure
if...else if ...else. Typically used like this:
<c:choose> <!-- first branch --> <c:when test="condition1"> Branch 1 contents... </c:when> <!-- second branch --> <c:when test="condition2"> Branch 2 contents... </c:when> <!-- everything else --> <c:otherwise> Whatever... </c:otherwise> </c:choose>
<c:forEach>
The
<c:forEach> tag iterates over a collection. The syntax is:
<!-- iterate over a collection --> <c:forEach[var="varName"] items="collection" [varStatus="varStatusName"] [begin="begin"] [end="end"] [step="step"]> body content </c:forEach> <!-- loop over a fixed number of times, similar to: for (int i = 0; i < 10; i++) { ... } --> <c:forEach [var="varName"] [varStatus="varStatusName"] begin="begin" end="end" [step="step"]> body content </c:forEach>
The typical use is like this:
<table> <c:forEach var="product" items="${products}" varStatus="status"> <tr><td>${status.count}</td><td>${product.name}</td></tr> </c:forEach> </table>
where
items is the collection to iterate through, var is the current item, varStatus contains the status of the iteration. All implementations of java.util.Collection are supported, as well as arrays of Objects and arrays of primitives. The begin, end, and step attributes can be used to loop over a subset, or skip any number of items.
If
items is of type java.util.Map, then the current item is of type java.util.Map.Entry (i.e., the current entry, not the key of the current entry).
The iteration status variable
varStatus is of type javax.servlet.jsp.jstl.core.LoopTagStatus. It exposes methods getCount(), getIndex(), isFirst(), isLast(), among others.
<c:forTokens>
The
<c:forTokens> tag tokenizes a String and iterates over it. The only difference from <c:forEach> is that the items attribute provides a String to be tokenized instead of a collection. The syntax is:
<c:forTokens items="stringOfTokens" delims="delimiters" [var="varName"] [varStatus="varStatusName"] [begin="begin"] [end="end"] [step="step"]> body content </c:forTokens>
Test it
Make these additions to the expanded test application:
- Create a new Java class
CoreFlowControl:package jstl.demo.handler; import java.io.IOException; import javax.servlet.*; import javax.servlet.http.*; import jstl.demo.DemoHandler; public class CoreFlowControl implements DemoHandler { public void handleRequest(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException { String[] daysOfTheWeek = new String[] { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; req.setAttribute("store", "open"); req.setAttribute("daysOfTheWeek", daysOfTheWeek); req.setAttribute("first3DaysOfTheWeek", "Sunday Monday Tuesday"); RequestDispatcher d = req.getRequestDispatcher("/coreflowcontrol.jsp"); d.forward(req, resp); } }
- Create a new JSP (
coreflowcontrol.jsp) underwebapp:<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <html> <head> <title>JSTL Core Tags: Flow Control</title> <style type="text/css"> body { font-family: sans-serif; } table { border-collapse: collapse; } td { border-style: solid; border-width: 1px; padding: 4px; } tr.odd { background-color: #ddd; } </style> </head> <body> <h2><c:if> test</h2> <c:if test="${store == 'open'}"> <p>The store is open.</p> </c:if> <h2><c:choose>, <c:when>, <c:otherwise> test</h2> <c:choose> <c:when test="${store == 'open'}"> <p>The store is open.</p> </c:when> <c:when test="${store == 'closed'}"> <p>The store is closed.</p> </c:when> <c:when test="${store == 'open' or store == 'closed'}"> <!-- This block will never be displayed, even though the test condition may become true. This is because when this is true, one of the previous blocks must be true - therefore, this block never gets a chance to display. --> <p>We know the store is open or closed.</p> </c:when> <c:otherwise> <p>We don't know.</p> </c:otherwise> </c:choose> <h2><c:forEach> test</h2> <table> <c:forEach items="${daysOfTheWeek}" var="item" varStatus="status"> <tr class="${status.index %2 != 0 ? 'odd' : ''}"> <td>${status.count}</td><td>${item}</td> </tr> </c:forEach> </table> <h2><c:forTokens> test</h2> <table> <c:forTokens items="${first3DaysOfTheWeek}" delims=" " var="item" varStatus="status"> <tr class="${status.index %2 != 0 ? 'odd' : ''}"> <td>${status.count}</td><td>${item}</td> </tr> </c:forTokens> </table> </body> </html>
- Compile and package the WAR with:
mvn package - Deploy the WAR to a servlet container of your choice (for example, Tomcat 6).
- Test the page with this URL (Tomcat 6 running on port 8080):
http://localhost:8080/jstl-demo/demo/CoreFlowControl
You may adjust the URL if your servlet container runs on a different port or the web app is bound to a different context root.