JavaServer Pages

This month Reuven discusses JSPs, which allow programmers and nonprogrammers alike to create servlets and dynamic pages with a mix of Java and HTML.
Dynamic Content

We can jazz things up a bit by adding one of the special JSP tags to main.jsp. The first tag inserts the results of some Java code into the output sent to the user:

      <Title>Mini-dynamic JSP Title</Title>
      <P>You are connecting from
         <%= request.getRemoteHost() %>.</P>

The expression inside of <%= %> is invoked, and its return value is placed in the output stream. Because a JSP is a servlet in disguise, it has access to the objects normally available to a servlet, such as “request” and “response”. Notice how the Java within <%= %> does not end with a semicolon; I can tell you from personal experience that it's difficult to break the habit of inserting semicolons there, but your JSPs will die if you insist on them.

To perform one or more Java computations without having the results sent to the user's browser, use the basic <% %> tags. These tags can be interspersed with HTML, making it possible to have conditional text appear in the response (see Listing 1).

Listing 1. Using <% %> Tags

If the hostname of the user's computer is available, we print its name. Otherwise, we print the host's IP address. Notice how the if/then/else block is interspersed with the static HTML. The request.getRemoteAddr() call is invoked only if request.getRemoteHost() returns an empty string (“”).

A number of JSP directives are invoked with the <%@ %> tags. All of these directives take effect at the time of JSP-to-servlet translation. A directive keyword is placed immediately after the @ symbol, followed by zero or more attributes.

For example, let's assume we have a standard sitewide menu bar in a JSP named menubar.jsp:

   <td><a href="one">Option 1</a></td>
   <td><a href="two">Option 2</a></td>

We can incorporate that into our document using the “include” directive (see Listing 2).

Listing 2. Using the “Include” Directive

It's important to remember that directives take effect when the JSP is turned into a servlet, not at runtime. Thus, the above example will work fine until you change menubar.jsp. Since the contents of menubar.jsp were incorporated into main.jsp just before the latter was turned into a servlet, the <%@ include %> tag no longer exists and, therefore, will not update things in the way we might expect. The solution is to use a runtime JSP action, described below.

There are two additional special JSP tags. One of them, <%-- --%>, acts as a comment. While it might seem odd to use a JSP comment when HTML comments already exist, the difference is important to remember: JSP comments are removed by the JSP engine when the servlet is created. By contrast, HTML comments are passed through untouched and are visible to any end user who selects the “view source” option on their browser. Given the choice, I tend to put most comments inside of the JSP comment tags, except for those that will help me to debug the JSP's output using the resulting HTML source code.

The final JSP tag, <%! %>, allows you to declare instance variables (also known as fields) for the JSP's resulting servlet. While it might seem tempting to use declaration tags to declare variables you will use in the rest of the JSP, remember that using fields means you must deal with thread safety. Given the headaches associated with threads, it's probably a good idea to avoid them if you can. You can also use the declaration tag to define new methods local to your JSP, although I'm not convinced this is such a good idea.

JSP Actions

Directives are useful if we want to affect the way in which the servlet is built. But what if we want to affect the servlet's actions at runtime?

We could, of course, include Java code to perform these actions. But JSP includes a number of special tags that are translated into Java code in the servlet, allowing you to write code without having to know any Java.

JSP action tags are actually XML and are defined in special XML documents known as tag libraries. So while they might appear to be HTML, they aren't, which often means you must pay particular attention to items such as closing tags and slashes.

The built-in JSP tag library includes a number of functions, one of which looks suspiciously similar to the include directive we saw in Listing 2. Listing 3 shows a version of main.html that uses the <jsp:include> action, rather than the directive, to bring in menubar.jsp.

Listing 3. Using the <jsp:include> Action

The difference between this version and its predecessor is subtle but significant: whereas the include directive incorporates the named page when the JSP is translated into a servlet, the include action works at runtime. If you were to modify menubar.jsp between invocations of main.jsp, the directive version would ignore the new menu bar, while the action version would display the latest version. Of course, this comes at a cost; the <jsp:include> action performs a runtime request, making it slower and less efficient than the directive.

Because pages requested by <jsp:include> have access to all of the request information from the top-level JSP, it's possible to use <jsp:include> to create dynamically changing menu bars, personalization systems and database access libraries.

There are other JSP actions as well. One of them is <jsp:forward>, which passes the request onto another JSP. As with <jsp:include>, this takes place within the servlet engine, meaning HTTP request and user-session information are still available. For example, Listing 4 shows a version of our JSP that forwards users to another page if their hostname is not identifiable.

Listing 4. Sample Version of JSP

If your server does not contain a page named no-reverse.jsp, then the user will get a 404 (file not found) error in their web browser. However, their browser will continue to display the URL of the originally requested page, main.jsp. This is because the JSP forward is performed internally, without the need for an external HTTP forward.