| [ Team LiB ] |
|
16.6 Mixing Action Elements and Scripting ElementsEven when you use custom actions and the JSTL, you may want occasionally to use small amounts of scripting code., e.g., as a quick fix or for prototyping, when creating a custom action, or an EL function seems like overkill. You can also use Java code to set an action attribute value. 16.6.1 Using an Expression Element to Set an AttributeIn all examples so far, dynamic action attribute values are set using EL expressions, but an alternative is using a Java expression. In either case, the custom action attribute must accept what's formally called a request-time attribute value. Here is an example of how a Java expression can be used to set the value attribute of the standard <jsp:param> action: <jsp:forward page="prodInfo.jsp">
<jsp:param name="id" value='<%= request.getParameter("prodId") %>' />
</jsp:forward>
The value attribute is set to the value of a request parameter. The container evaluates the request-time attribute value when the page is requested, and the corresponding attribute is set to the result of the expression. The Java type for the result of the expression must match the type of the attribute you set this way. In the <jsp:param> value attribute case, the expression must be of type String, but other action attributes may be of any type, including custom classes. This is in contrast to when an EL expression used; the container always tries to convert the EL expression evaluation result type to the attribute type, but with Java expressions it's up to you to make sure they match. Another difference between using Java and EL expressions when assigning an attribute value is that with a Java expression, you can't combine expressions and static text as you can with EL expressions. For instance, this is illegal: <jsp:param name="ranking"
value='Ranking: <%= request.getParameter("ranking") %>' />
Instead, you have to combine the static text and the dynamic value within the expression: <jsp:param name="ranking"
value='<%= "Ranking: " + request.getParameter("ranking") %>' />
One subtle detail in this example is that the attribute value is enclosed with single quotes instead of the usual double quotes. That's because the expression itself must use double quotes around the getParameter( ) argument. An alternative to enclosing the expression in single quotes is to escape the double quotes with backslashes in the expression: <jsp:forward page="prodInfo.jsp"> <jsp:param name="id" value="<%= request.getParameter(\"prodId\") %>"/> </jsp:forward> Request-time attribute values are supported for most of the standard action attributes and can be supported by custom action attributes as well, but it's not a given. In the tables describing action elements that you see throughout this book as well as in Appendix A, B, and E, all attributes that accept a request-time attribute value has a "Yes" in the "Dynamic value accepted" column. One reason for not supporting a request-time attribute value is that some attribute values must be known when the page is converted into a servlet. For instance, the class attribute value in the <jsp:useBean> action must be known in the translation phase so that the JSP container can generate valid Java code for the servlet. Request-time attribute values also require a bit more processing than static string values, so it's up to the action developer to decide if request-time attribute values are supported or not. Whether or not an attribute accepts a request-time attribute value is declared in the Tag Library Descriptor (TLD). I discuss implementation of custom actions and the TLD in Chapter 21, so let's defer the details until then. 16.6.2 Accessing Scoped Variables in Scripting CodeThe term variable is generally used for any dynamic data an application manipulates, but when we talk about JSP and scripting elements, it's important to be more specific. JSP custom actions, including the JSTL actions, can expose data through what is called scoped variables, typically named by a var and an optional scope attribute. A scoped variable is an object that lives in one of the JSP scopes: page, request, session, or application. As mentioned earlier, the scopes are actually collections of named object references that correspond to the attributes that the implicit pageContext, request, session, and application objects provide access to. Another type of variable is a scripting variable. A scripting variable is a variable declared in a JSP scriptlet or declaration, using the language defined for the page (typically Java). To read or manipulate data with scripting code, you need a scripting variable that holds a reference to the object that contains the data. The distinction between the variable types becomes apparent when you mix actions that expose data only as scoped variables with scripting elements. To use the data exposed by the action in a scripting element, you must first tell the container to create a scripting variable for it and assign it the value of the scoped variable. The easiest way to do this is to use the standard <jsp:useBean> action: <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <%@ page import="java.util.Date" %> <fmt:parseDate value="${param.birthDate}" pattern="yyyy-MM-dd" var="birthDate" /> <jsp:useBean id="birthDate" class="java.util.Date" /> <% String ageCategory = null; int thisYear = new Date().getYear( ); int age = thisYear - birthDate.getYear( ); if (age < 10) { ageCategory = "kid"; } else if (age < 20) { ageCategory = "teenager"; } else if (age < 65) { ageCategory = "adult"; } else { ageCategory = "retired"; } %> In this example, <fmt:parseDate> parses a date submitted as a request parameter and saves the result as a java.util.Date in a page scope variable named birthDate. The <jsp:useBean> action finds the scoped variable and creates a scripting variable of the type java.util.Date with the same name as the scoped variable and assigns it the value of the scoped variable. The scriptlet can then use the scripting variable created by the <jsp:useBean> action. Alternatively, you can declare and assign the scripting variable with scripting code: <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <%@ page import="java.util.Date" %> <fmt:parseDate value="${param.birthDate}" pattern="yyyy-MM-dd" var="birthDate" /> <% Date birthDate = (Date) pageContext.getAttribute("birthDate"); String ageCategory = null; int thisYear = new Date().getYear( ); int age = thisYear - birthDate.getYear( ); Compared to using the <jsp:useBean> action, you must first know which implicit object represents the scope the scoped variable is placed in and call its getAttribute( ) method. All implicit objects that represent a JSP scope provide the getAttribute( ) method. As shown here, you must also cast the return value to the correct type, because the getAttribute( ) returns an Object. You can save or replace an object in any scope with the setAttribute( ) method: public void setAttribute(String name, Object value) To remove an object, use the removeAttribute( ) method: public void removeAttribute(String name) One thing to watch for when you use scripting variables and scoped variables to access the same object is illustrated by this page: <%@ page language="java" contentType="text/html" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<html>
<head>
<title>Not *NSYNC</title>
</head>
<body bgcolor="white">
<jsp:useBean id="artistName"
scope="request" class="java.lang.String" />
<% artistName = "U2"; %>
And the winner is ... ${fn:escapeXml(artistName)}
</body>
</html>
The <jsp:useBean> action makes a request scope object (perhaps placed there by a servlet) available through a scripting variable named artistName, a scriptlet assigns a new value to the scripting variable, and finally the value of artistName is added to the response with an EL expression. The question is, does the response contain the original value assigned to the request scope object or the value assigned by the scriptlet code? The answer is: the original value. This is because the EL doesn't have access to scripting variables, only to objects in one of the JSP scopes and the implicit EL variables. To make an object available to the EL from a scriptlet, you need to explicitly save it in the appropriate scope. If you add this line of code in the scriptlet block to replace the scoped variable, the new value is added to the response instead of the original value: <%
artistName = "U2";
request.setAttribute("artistName", artistName);
%>
This is true also for actions that access scoped variables directly, not only for the EL. If you replace the object a scripting variable references, you must also replace the object the scoped variable references by calling setAttribute( ) if you want actions and the EL to reference the new object. For custom actions you can tell the container to automatically declare a scripting variable and assign it a reference to the scoped variable the action exposes; I'll show you how in Chapter 22. In this case, scripting code can access the exposed data directly through the scripting value. JSTL actions, on the other hand, do not use this feature so you must always use <jsp:useBean> or the getAttribute( ) method in a scriptlet to bridge the gap between the two types of variables. |
| [ Team LiB ] |
|