Core JSTL[c] Mastering the JSP Standard Tag Library
As websites grow, it's often convenient to encapsulate distinct functionality in separate Web applications. For example, if you develop open -source software, you may find it convenient to implement a Web application that documents your product and another Web application that provides examples that potential customers can try. From the perspective of a single Web application, other Web applications in the same website are known as foreign contexts. Websites that have multiple Web applications often need to share resources between those applications. This section shows you how to use <c:import> to access resources in a foreign context. Before we proceed with the example, however, you should know that not all JSP containers support accessing resources that reside in foreign contexts. The example discussed in this section was tested with Tomcat 4.1, which lets you enable cross-context access with a special attribute that you specify when you declare your Web applications. Other JSP containers, such as Resin, do not support cross-context access.
Two Web applications are used in the following example. Those Web applications and their pertinent JSP files are depicted in Figure 5-4. Figure 5-4. Two Web Applications and Their Contents
In the following example, index.jsp from the webappTwo application accesses companyHeader.jsp , companyFooter.jsp , and create_html_select.jsp from the webappOne application. Tomcat 4.1 requires you to specify those contexts with a crossContext attribute in the Context element in server.xml . Here is an excerpt from server.xml for the Web applications shown in Figure 5-4: ... <Context path="/core-jstl/url/webappOne" docBase="C:/core-jstl/webappOne" crossContext="true" /> <Context path="/core-jstl/url/webappTwo" docBase="C:/core-jstl/webappTwo" crossContext="true" /> ... The webappTwo application, which consists of a single JSP page ” index.jsp ”is shown in Figure 5-5. That application lets you make a donation by filling out a form, as shown in the top picture in Figure 5-5. If you specify less than $1000 for your donation, the JSP page is redisplayed with the original information that you entered and you are asked to increase your donation, as you can see from the bottom picture in Figure 5-5. Figure 5-5. Accessing Resources in a Foreign Context with <c:import> and <c:param>
The JSP page shown in Figure 5-5 is listed in Listing 5.6. There are three points of interest in the preceding JSP page. First, that JSP page uses <c:import> to import a header and a footer from the webappOne application. Second, the JSP page also uses <c:import> to import a JSP page from webappOne that creates HTML select elements. Finally, the JSP page uses <fmt:formatNumber> to format the donation amount as currency; we discuss formatting actions in "Formatting Actions" on page 308. The header and footer imported from webappOne are simple JSP pages that are listed in Listing 5.7 and Listing 5.8, respectively. Listing 5.6 Accessing Foreign Contexts
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title> Using <c:import> to Access Foreign Contexts </title> </head> <body> <%@ taglib uri='http://java.sun.com/jstl/core' prefix='c' %> <%@ taglib uri='http://java.sun.com/jstl/fmt' prefix='fmt'%> <%-- Import a header shared among Web applications for this Web site --%> <c:import url='/WEB-INF/jsp/shared/regions/companyHeader.jsp' context='/core-jstl/url/webappOne'/> <p> <%-- If the user didn't give enough, ask for more --%> <c:if test='${param.amount < 1000}'> We know you can afford more than <fmt:formatNumber value='${param.amount}' type='currency'/> <c:out value='${param.first}'/>. Please increase your donation. </c:if> <%-- Create a page-scoped variable -- for readability only -- that represents the context-relative URL for create_html_select.jsp, which resides in the /core-jstl/url/webappOne context --%> <c:set var='create_html_component'> /WEB-INF/jsp/shared/components/create_html_select.jsp </c:set> <%-- This form does not specify an action, so this JSP page is reloaded when the submit button is activated --%> <form method='post'> <table> <tr> <td>First Name:</td> <td><input type='text' name='first' value='<c:out value="${param.first}"/>'/> </td> </tr> <tr> <td>Last Name:</td> <td><input type='text' name='last' value='<c:out value="${param.last}"/>'/> </td> </tr> <tr> <td>Credit Card Type:</td> <td> <c:import url='${create_html_component}' context='/core-jstl/url/webappOne'> <c:param name='selectName' value='cardType'/> <c:param name='items' value='Visa, Master Card, Discover'/> </c:import> </td> </tr> <tr> <td>Credit Card Number:</td> <td><input type='text' name='cardNumber' value='<c:out value="${param.cardNumber}"/>'/> </td> </tr> <tr> <td>Donation Amount:</td> <td> <c:import url='${create_html_component}' context='/core-jstl/url/webappOne'> <c:param name='selectName' value='amount'/> <c:param name='items' value='10,100,1000,10000'/> <c:param name='formatDisplay' value='currency'/> </c:import> </td> </tr> </table> <p><input type='submit' value='Make Donation'/> </form> <%-- Import a footer shared among Web applications for this Web site --%> <c:import url='/WEB-INF/jsp/shared/regions/companyFooter.jsp' context='/core-jstl/url/webappOne'/> </body> </html> Listing 5.7 /WEB-INF/jsp/shared/regions/companyHeader.jsp (from/core-jstl/url/webappOne context)
<font size='5'> Donations Inc. </font> <hr> Listing 5.8 /WEB-INF/jsp/shared/regions/companyFooter.jsp (from/core-jstl/url/webappOne context)
<%@ taglib uri='http://java.sun.com/jstl/core' prefix='c' %> <hr> <jsp:useBean id='now' class='java.util.Date'/> <i>Thanks for stopping by on <c:out value='${now}'/></i> As you can see from Figure 5-5 on page 217, the HTML select elements created by that JSP page retain their values when the page is reloaded. As discussed in "Retaining Values for HTML Option Elements" on page 129, that behavior can be implemented with the <c:if> and <c:out> actions; for example, you could implement the donation amount element like this: <%-- Create the HTML select element for the donation amount --%> <select name ='amount'> <%-- For each item displayed by this select element, ... --%> <c:forEach var='item' items='10,100,1000,10000'> <%-- Create the starting option element--%> <option <%-- If the current item is the same as the last amount specified, generate a "select" string contained in the option start tag --%> <c:if test='${param.amount == item}'> selected </c:if> <%-- Generate the value for the option element --%> value='<c:out value="${item}"/>' <%-- Close off the option element start tag --%> > <%-- Generate the display value as currency for the option element body --%> <fmt:formatNumber value='${item}' type='currency'/> <%-- Generate the option element end tag --%> </option> </c:forEach> </select> The preceding code fragment creates an HTML select element for donation amounts. That select element retains the previously entered donation amount and formats the displayed amount as currency. It's not overly difficult to create that HTML select element with the preceding code, but nonetheless, you must remember the algorithm and know how to use the <c:forEach>, <c:out>, <c:if> and <fmt:formatNumber> actions. It would be beneficial if you could encapsulate that algorithm in a JSP page so you don't have to recall the algorithm every time you need to create an HTML select element that retains its values. The JSP page listed in Listing 5.6 on page 218 uses <c:import> and <c:param> to import a JSP page that creates HTML select elements. Here's how the JSP page listed in Listing 5.6 on page 218 imports that JSP page: <html> ... <body> ... <%-- Create a page-scoped variable -- for readability only -- that represents the context-relative URL for create_html_select.jsp, which resides in the /core-jstl/url/webappOne context --%> <c:set var=' create_html_component '> /WEB-INF/jsp/shared/components/create_html_select.jsp </c:set> <%-- This form does not specify an action, so this JSP page is reloaded when the submit button is activated --%> <form method='post'> <table> ... <tr> <td>Donation Amount:</td> <td> <c:import url='${create_html_component}' context='/core-jstl/url/webappOne'> <c:param name='selectName' value='amount'/> <c:param name='items' value='10,100,1000,10000'/> </c:import> </td> </tr> ... </table> ... </form> ... </body> </html> The preceding code fragment creates a scoped variable, solely for readability, that contains a string representing the URL of the JSP page ” create_html_select.jsp ”that creates HTML select elements that retain their values. That URL is a context-relative path, out of necessity because the JSP page that it references resides in a foreign context. The scoped variable is subsequently used to specify the url attribute for the <c:import> action, which also specifies the foreign context with its context attribute. The <c:import> action contains two <c:param> actions that specify a selectName request parameter whose value is amount and an items request parameter whose value is the comma-separated string 10,100,1000,10000 . The create_html_select.jsp JSP page is listed in Listing 5.9. Listing 5.9 /WEB-INF/jsp/shared/components/create_html_select.jsp (from/core-jstl/url/webappOne context)
<%-- This handy JSTL component creates an HTML select element that retains its value if its page is reloaded. This component can be passed the following request parameters: selectName: The name of the select element items: The option values formatValue: How option values should be formatted formatDisplay: How option display values should be formatted The items parameter must be a comma-separated string, and the formatValue and formatDisplay parameters must be one of the following: number, percent, or currency. Here's an example of how you'd use this component: <form> <table> <tr> <td>Select a value:</td> <td> <c:import url='create_html_select.jsp'> <c:param name='selectName' value='amount'/> <c:param name='items' value='1,2,3,4,5'/> <c:param name='formatValue' value='currency'/> <c:param name='formatDisplay' value='currency'/> </c:import> </td> </tr> </table> <p><input type='submit'/> </form> The preceding code creates an HTML select element with the values 1-5. Those values are formatted as currency, so they look like this for the US English locale: .00, .00, ... .00. --%> <%@ taglib uri='http://java.sun.com/jstl/core' prefix='c' %> <%@ taglib uri='http://java.sun.com/jstl/fmt' prefix='fmt'%> <%-- Set a page-scoped variable representing the last value selected for the HTML select element generated by this component --%> <c:set var='lastValue' value='${param[param.selectName]}'/> <%-- Create the HTML select element --%> <select name='<c:out value="${param.selectName}"/>'> <c:forEach var='item' items='${param.items}'> <%-- Start the option starting tag --%> <option <%-- If this item was the last item selected, add the string selected to the option starting tag --%> <c:if test='${item == lastValue}'> selected </c:if> <%-- If the option's value should be formatted, format it with the formatting type (number, percent, or currency) specified with the formatValue parameter --%> <c:choose> <c:when test='${not empty param.formatValue}'> <fmt:formatNumber var='value' value='${item}' type='${param.formatValue}'/> <c:out escapeXml='false' value='value=${value}'/> </c:when> <c:otherwise> value='<c:out value="${item}"/>' </c:otherwise> </c:choose> <%-- Close off the <option> starting tag --%> > <%-- If the option's display value should be formatted, format it with the formatting type (number, percent, or currency) specified with the formatDisplay parameter --%> <c:choose> <c:when test='${not empty param.formatDisplay}'> <fmt:formatNumber var='value' value='${item}' type='${param.formatDisplay}'/> <c:out value='${value}'/> </c:when> <c:otherwise> <c:out value='${item}'/> </c:otherwise> </c:choose> <%-- Add the <option> end tag --%> </option> </c:forEach> </select> The preceding JSP page encapsulates the creation of HTML select elements that retain their values. That JSP page can be passed four request parameters that represent the name of the select element, the items it displays, and how the element's values and display values should be formatted. That JSP page represents a reusable component that can be used by multiple Web applications; therefore, the example in this section shows how to access that component from a foreign context. If your JSP container does not support accessing resources in foreign contexts, you can still take advantage of components like the preceding JSP page by accessing them with an absolute URL. |