4.2. JSP ActionsIf you've spent any time working with servlets, our examples up to this point really haven't been anything new. Essentially, we've replaced reams of println( ) calls with template text in a JSP. This certainly saves time, but we aren't doing anything different. For one thing, at the beginning of this chapter, we promised that JSP allowed nonprogramming web designers and content creators to help create dynamic content. The techniques we've just seen let you do that, but you have to teach them Java first, which pretty much defeats the purpose. HTML developers may not be confident tackling server-side Java code, but they're certainly comfortable with markup tags. Web browsers, after all, just treat tags as instructions. If a browser sees a <b> tag, it turns the running text to boldface until it sees another </b> tag. Scriptlets in JSP do the same thing, except in two steps: the server processes the script, possibly producing more HTML, and the browser then views it. This is not a difficult concept, but we haven't gotten around the fact that the first set of instructions is provided as Java code and hence requires a Java programmer with some time on her hands. JSP solves this problem with action tags . An action tag looks like a regular HTML tag and doesn't follow the <% %> syntax conventions we've seen before. JSP actions are divided into two categories: built-in functions, which we'll discuss in this section, and custom tags, which we'll discuss later in the chapter. Built-in JSP actions provide access to many of the features we've already seen with scriptletsfor instance, there is another type of include we can perform with actions: <jsp:include page="/headers/header.jsp"/> If you think this looks like an XML tag, you're right: the syntax requirements are the same as for namespace-enabled XML. The jsp namespace is reserved for JSP built-in actions (we'll see the real value of this in the next section). The tag name is specified after the namespace and the action to be performed. Tags can then have zero or more attributes (such as page, name, id). Tags can be closed with a standard closing tag (such as </jsp:include>) or with a / before the final >, for tags that don't have any elements within them. The difference between the <%@ include %> directive and the <jsp:include> action is that the directive happens once at compile time for the page while the action happens at request time, each time the page is processed for a client. The <jsp:include> tag itself includes the contents of the specified relative URL (it must be from the same server) in the output of the current page.[*] Parameters for the included page can be included by nesting a <jsp:param> tag into the include:
<jsp:include page="/headers/header.jsp"> <jsp:param name="company" value="The Company"/> </jsp:include> The <jsp:forward> tag works similarly, but transfers control to the destination page rather than including its content: <jsp:forward page="/login/access.jsp" /> or, with parameters: <jsp:forward page="/login/access.jsp"> <jsp:param name="redirect" value="<%= request.getRequestURI( )%>" /> </jsp:forward> The preceding example uses a JSP expression to generate the parameter value. One caution on <jsp:forward>: if any output has been written to the client (either because the output buffer was flushed or because buffering was turned off via a page directive), an attempt to use <jsp:forward> produces an IllegalStateException. 4.2.1. JSP Tags and JavaBeansJSP actions combine with Java beans to provide data to page designers. Programmers can write a Java bean that handles data access and business logic (including accessing Enterprise JavaBeans) and make that information available to a JSP, without embedding all of the necessary JDBC (or whatever) code within the JSP itself. As a Java class, Java beans can be instantiated in scriptlets. If we want to use a bean named ProductBean in the com.company package, we could write a JSP like this: <% com.company.ProductBean product = new com.company.ProductBean( ); product.setProductId("DH2309-AX"); %> The ProductBean, after setting the product ID, retrieves the necessary product information, which is exposed via other properties. So if the bean has a Price property, we could retrieve it with: <%= product.getPrice( ) %> However, JSPs offer another way to access the bean, using the <jsp:useBean> tag: <jsp:useBean /> It's that simple. Once the bean is created, properties can be set using the <jsp:setProperty> tag: <jsp:setProperty name="product" property="ProductID" value="DH2309-AX"/> The <jsp:setProperty> tag can be nested within the <jsp:useBean> tag or used later. Properties are retrieved in the same way, using the <jsp:getProperty> tag: <jsp:getProperty name="product" property="Price"/> There's one more trick to the <jsp:setProperty> tag. If the value attribute is not included, the JSP will search the incoming request parameters for a name=value pair with the same name as the bean property currently being set and will use the value from the request. For example, the request http://shop.company.com/schlock/product.jsp?ProductId=DH2309-AX has a ProductId parameter containing the ID for the product we want to display. If the product.jsp file contains these lines: <jsp:useBean /> <jsp:setProperty name="product" property="ProductId" /> the ProductId property is set to DH2309-AX. For further convenience, we can use the special property name (*), which populates every property of the bean from the request parameters. 4.2.2. Scoping BeansThe Java bean used in the last example existed within the scope of the current page. This means that it was created when the client requested the page and destroyed when the page was destroyed. For some applications, this is fine: a Java bean that retrieves and displays information about a particular product in an online catalog doesn't need to hang around, although it should use efficient strategies to speed its interior execution.[*] But what about a bean that retrieves information about the current user-display preferences, identity, and so on? This information is used by every page the user accesses, but doesn't change except in very specific situations. We want to create the bean once and store it in the user's session, where it can remain until the user leaves the site.
One way to accomplish this is to use a scriptlet to add the bean directly to the user's session using the implicit JSP session object and then to retrieve it manually for each page that uses it. However, the <jsp:useBean> tag offers a way around this, via the scope argument, which will apply to every instance of that particular Java bean class with the specified ID. By default, beans have a page scope, but they also can be set to have a user scope, so the same instance is used whenever a <jsp:useBean> tag is invoked for that class and ID. The application scope goes even further, applying to the web application as a whole by inserting the bean instance into the ServletContext object associated with the web application. This allows servlets to access beans created by JSPs and vice versa. The other available scope is request. Elements scoped to the request level will be available for the duration of the current request. This means they can be accessed by other JSPs referenced via <jsp:include> or <jsp:forward>. |