If 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 scriptlets—for 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.[20] 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
.
JSP 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 id="product" class="com.company.ProductBean" />
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 id="product" class="com.company.ProductBean" /> <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.
The 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.[21] 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>
.
[20] In pure servlets, this is the functionality handled by the
RequestDispatcher
object.
[21] For instance, if the bean retrieves product information from a SQL database, it should use a connection-pooling strategy, possibly via JDBC 2.0, to avoid the overhead of creating a new connection for each database access.
Get Java Enterprise in a Nutshell, Third Edition now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.