Once again, the preceding example had to use two c:if tags, although the bodies are different in this case. However, this is still somewhat clumsy, as the same check is being performed twice: once to see whether it is true and once to see whether the reverse is true. This double check is needed because the c:if tag is capable of deciding only between two alternatives: to include its body or not to include it. Another set of tags allows multiway branching, or choosing from among several mutually exclusive possibilities.
Unlike the other tags seen so far, three tags work together to obtain the desired result. The outermost tag, c:choose, has no parameters; it merely serves as a container for a collection of two other tags: c:when and c:otherwise. Each individual c:when tag acts a lot like a c:if tag. Both tags take a parameter called test, which should be a script, and render their body content if the condition in the script is true. The difference is that multiple c:if tags will each be checked in turn, whereas a c:choose tag will stop after finding the first c:when tag with a test that is true.
In other words, consider a set of possible values for a bean property, such as the colors red, green, and blue. The following snippet of code would check each of these possibilities regardless of the value:
<c:if test="${bean.color == 'red'}">...</c:if> <c:if test="${bean.color == 'green'}">...</c:if> <c:if test="${bean.color == 'blue'}">...</c:if>
The following snippet will check whether the color is red; if so, it will stop and will not then have to check whether it is green and then blue:
<c:choose> <c:when test="${bean.color == 'red'}">...</c:when> <c:when test="${bean.color == 'green'}">...</c:when> <c:when test="${bean.color == 'blue'}">...</c:when> </c:choose>
Clearly, the second option is more efficient. In addition, using the c:choose tag groups related code in one place and so makes JSPs easier to read and understand.
The c:choose tag works with another tag: c:otherwise. This tag also has no parameters; its body will be evaluated if none of the c:when tags has a true condition.
It is now clear how it would be possible to avoid doing the check twice in Listing 4.11—by using one c:when and a c:otherwise—rather than by using two c:if tags. This is shown in Listing 4.13.
Listing 4.13 The choose tag
<c:choose> <c:when test="${empty album.tracks}"> There are no tracks! What a boring CD. </c:when> <c:otherwise> Here are the tracks: <ul> <c:forEach items="${album.tracks}" var="track"> <li><c:out value="${track}"/> </c:forEach> </ul> </c:otherwise> </c:choose>
This code is a little more verbose than Listing 4.12 but has the advantage of avoiding one redundant test. Using the c:choose tag also makes it clear that the conditions are mutually exclusive, and hence only one of the bodies will ever be rendered.
Chapter 2 briefly mentions the jsp:forward tag, which sends the user from one page to another. This tag can be combined with the c:choose tag to provide a type of control called dispatching, whereby one page determines where the appropriate content lives and sends the user to that page. This is illustrated in Listing 4.14.
Listing 4.14 Using the choose tag as a dispatcher
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %> <c:choose> <c:when test="${param.whichPage == 'red'}"> <jsp:forward page="red.jsp"/> </c:when> <c:when test="${param.whichPage == 'green'}"> <jsp:forward page="blue.jsp"/> </c:when> <c:when test="${param.whichPage == 'blue'}"> <jsp:forward page="blue.jsp"/> </c:when> <c:otherwise> <jsp:forward page="select_page.jsp"/> </c:otherwise> </c:choose>
This page looks for a form parameter, whichPage, which should be red, green, or blue, and, based on this value, sends the user to one of three pages. If no value has been provided, the otherwise tag forces the user to "select_page.jsp", which contains the form to be filled out.