3.3. Invoking Code with JSP Scripting Elements

There are a number of different ways to generate dynamic content from JSP, as illustrated in Figure 3-1. Each of these approaches has a legitimate place; the size and complexity of the project is the most important factor in deciding which approach is appropriate. However, be aware that people err on the side of placing too much code directly in the page much more often than they err on the opposite end of the spec-trum. Although putting small amounts of Java code directly in JSP pages works fine for simple applications, using long and complicated blocks of Java code in JSP pages yields a result that is hard to maintain, hard to debug, and hard to divide among different members of the development team. Nevertheless, many pages are quite simple, and the first two approaches of Figure 3-1 (placing explicit Java code directly in the page) work quite well. This section discusses those approaches.

Figure 3-1. Strategies for invoking dynamic code from JSP.


JSP scripting elements let you insert code into the servlet that will be generated from the JSP page. There are three forms:

  1. Expressions of the form <%= Expression %>, which are evaluated and inserted into the servlet’s output.

  2. Scriptlets of the form <% Code %>, which are inserted into the servlet’s _jspService method (called by service).

  3. Declarations of the form <%! Code %>, which are inserted into the body of the servlet class, outside of any existing methods.

Each of these scripting elements is described in more detail in the following sections.

In many cases, a large percentage of your JSP page just consists of static HTML, known as template text. In almost all respects, this HTML looks just like normal HTML, follows all the same syntax rules, and is simply “passed through” to the client by the servlet created to handle the page. Not only does the HTML look normal, it can be created by whatever tools you already are using for building Web pages. For example, I used Macromedia’s HomeSite for most of the JSP pages in this book.

There are two minor exceptions to the “template text is passed straight through” rule. First, if you want to have <% in the output, you need to put <\% in the template text. Second, if you want a comment to appear in the JSP page but not in the resultant document, use

<%-- JSP Comment --%> 

HTML comments of the form

<!-- HTML Comment --> 

are passed through to the resultant HTML normally.

Expressions

A JSP expression is used to insert values directly into the output. It has the following form:

<%= Java Expression %> 

The expression is evaluated, converted to a string, and inserted in the page. That is, this evaluation is performed at run time (when the page is requested) and thus has full access to information about the request. For example, the following shows the date/time that the page was requested.

Current time: <%= new java.util.Date() %> 

Predefined Variables

To simplify these expressions, you can use a number of predefined variables (or “implicit objects”). There is nothing magic about these variables; the system simply tells you what names it will use for the local variables in _jspService. These implicit objects are discussed in more detail later in this section, but for the purpose of expressions, the most important ones are:

  • request, the HttpServletRequest

  • response, the HttpServletResponse

  • session, the HttpSession associated with the request (unless disabled with the session attribute of the page directive—see Section 3.4)

  • out, the Writer (a buffered version called JspWriter) used to send output to the client

Here is an example:

Your hostname: <%= request.getRemoteHost() %> 

JSP/Servlet Correspondence

Now, I just stated that a JSP expression is evaluated and inserted into the page output. Although this is true, it is sometimes helpful to understand in a bit more detail what is going on.

It is actually pretty simple: JSP expressions basically become print (or write) statements in the servlet that results from the JSP page. Whereas regular HTML becomes print statements with double quotes around the text, JSP expressions become print statements with no double quotes. Instead of being placed in the doGet method, these print statements are placed in a new method called _jspService that is called by service for both GET and POST requests. For instance, Listing 3.1 shows a small JSP sample that includes some static HTML and a JSP expression. Listing 3.2 shows a _jspService method that might result. Of course, different vendors will produce code in slightly different ways, and optimizations such as reading the HTML from a static byte array are quite common.

Also, I oversimplified the definition of the out variable; out in a JSP page is a JspWriter, so you have to modify the slightly simpler PrintWriter that directly results from a call to getWriter. So, don’t expect the code your server generates to look exactly like this.

Listing 3.1. Sample JSP Expression: Random Number
<H1>A Random Number</H1> 
<%= Math.random() %> 

Listing 3.2. Representative Resulting Servlet Code: Random Number
public void _jspService(HttpServletRequest request, 
                        HttpServletResponse response) 
    throws ServletException, IOException {
  response.setContentType("text/html"); 
  HttpSession session = request.getSession(true); 
  JspWriter out = response.getWriter(); // Oversimplified a bit 
  out.println("<H1>A Random Number</H1>");
								out.println(Math.random()); 
  ... 
} 

If you want to see the exact code that your server generates, you’ll have to dig around a bit to find it. In fact, some servers delete the source code files once they are successfully compiled. But here is a summary of the locations used by three common, free development servers.

Tomcat 4.0 Autogenerated Servlet Source Code

install_dir/work/localhost/_

(The final directory is an underscore.)

JRun 3.1 Autogenerated Servlet Source Code

install_dir/servers/default/default-app/WEB-INF/jsp

(More generally, in the WEB-INF/jsp directory of the Web application to which the JSP page belongs.)

ServletExec 4.0 Autogenerated Servlet Source Code

install_dir/Servlets/pagecompile

(More generally, in install_dir/ServletExec Data/virtual-server-name/ web-app-name/pagecompile.)

XML Syntax for Expressions

On some servers, XML authors can use the following alternative syntax for JSP expressions:

<jsp:expression>Java Expression</jsp:expression> 

However, in JSP 1.1 and earlier, servers are not required to support this alternative syntax, and in practice few do. In JSP 1.2, servers are required to support this syntax as long as authors don’t mix the XML version (<jsp:expression> ... </jsp:expression>) and the standard JSP version that follows ASP syntax (<%= ... %>) in the same page. Note that XML elements, unlike HTML ones, are case sensitive, so be sure to use jsp:expression in lower case.

Installing JSP Pages

Servlets require you to set your CLASSPATH, use packages to avoid name conflicts, install the class files in servlet-specific locations, and use special-purpose URLs. Not so with JSP pages. JSP pages can be placed in the same directories as normal HTML pages, images, and style sheets; they can also be accessed through URLs of the same form as those for HTML pages, images, and style sheets. Here are a few examples of default installation locations (i.e., locations that apply when you aren’t using custom Web applications) and associated URLs. Where I list SomeDirectory, you can use any directory name you like. (But you are never allowed to use WEB-INF or META-INF as directory names. For the default Web application, you also have to avoid a directory name that matches the URL prefix of any other Web application. For information on defining your own Web application, see Chapter 4, “ Using and Deploying Web Applications.”)

  • Tomcat Directory

    install_dir/webapps/ROOT

    (or install_dir/webapps/ROOT/SomeDirectory)

  • JRun Directory

    install_dir/servers/default/default-app

    (or install_dir/servers/default/default-app/SomeDirectory)

  • ServletExec Directory

    install_dir/public_html

    (or install_dir/public_html/SomeDirectory)

  • Corresponding URLs

    http://host/Hello.html

    (or http://host/SomeDirectory/Hello.html)

    http://host/Hello.jsp

    (or http://host/SomeDirectory/Hello.jsp)

Note that, although JSP pages themselves need no special installation directories, any Java classes called from JSP pages still need to go in the standard locations used by servlet classes (e.g.,.../WEB-INF/classes; see Sections 1.7 and 1.9).

Example: JSP Expressions

Listing 3.3 gives an example JSP page called Expressions.jsp. I placed the file in a subdirectory called jsp-intro, copied the entire directory from my development directory to the deployment location just discussed, and used a base URL of http://host/jsp-intro/Expressions.jsp. Figures 3-2 and 3-3 show some typical results.

Figure 3-2. Result of Expressions.jsp using JRun 3.1 and omitting the testParam request parameter.


Figure 3-3. Result of Expressions.jsp using ServletExec 4.0 and specifying test+value as the value of the testParam request parameter.


Notice that I included META tags and a style sheet link in the HEAD section of the JSP page. It is good practice to include these elements, but there are two reasons why they are often omitted from pages generated by normal servlets.

First, with servlets, it is tedious to generate the required println statements. With JSP, however, the format is simpler and you can make use of the code reuse options in your usual HTML building tools.

Second, servlets cannot use the simplest form of relative URLs (ones that refer to files in the same directory as the current page) since the servlet directories are not mapped to URLs in the same manner as are URLs for normal Web pages. JSP pages, on the other hand, are installed in the normal Web page hierarchy on the server, and relative URLs are resolved properly as long as the JSP page is accessed directly by the client, rather than indirectly by means of a RequestDispatcher. Even then, there are some techniques you can use to simplify the use of relative URLs. For details, see Section 4.5 (Handling Relative URLs in Web Applications).

Thus, in most cases style sheets and JSP pages can be kept together in the same directory. The source code for the style sheet, like all code shown or referenced in the book, can be found at http://www.moreservlets.com.

Listing 3.3. Expressions.jsp
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> 
<HTML> 
<HEAD> 
<TITLE>JSP Expressions</TITLE> 
<META NAME="keywords" 
      CONTENT="JSP,expressions,JavaServer Pages,servlets"> 
<META NAME="description" 
      CONTENT="A quick example of JSP expressions."> 
<LINK REL=STYLESHEET 
      HREF="JSP-Styles.css" 
      TYPE="text/css"> 
</HEAD> 

<BODY> 
<H2>JSP Expressions</H2> 
<UL> 
  <LI>Current time: <%= new java.util.Date() %> 
  <LI>Server: <%= application.getServerInfo() %> 
  <LI>Session ID: <%= session.getId() %> 
  <LI>The <CODE>testParam</CODE> form parameter: 
      <%= request.getParameter("testParam") %> 
</UL> 
</BODY> 
</HTML> 

Scriptlets

If you want to do something more complex than output a simple expression, JSP scriptlets let you insert arbitrary code into the servlet’s _jspService method (which is called by service). Scriptlets have the following form:

<% Java Code %> 

Scriptlets have access to the same automatically defined variables as do expressions (request, response, session, out, etc.). So, for example, if you want to explicitly send output to the resultant page, you could use the out variable, as in the following example.

<% 
String queryData = request.getQueryString(); 
out.println("Attached GET data: " + queryData); 
%> 

In this particular instance, you could have accomplished the same effect more easily by using the following JSP expression:

Attached GET data: <%= request.getQueryString() %> 

In general, however, scriptlets can perform a number of tasks that cannot be accomplished with expressions alone. These tasks include setting response headers and status codes, invoking side effects such as writing to the server log or updating a database, or executing code that contains loops, conditionals, or other complex constructs. For instance, the following snippet specifies that the current page is sent to the client as plain text, not as HTML (which is the default).

<% response.setContentType("text/plain"); %> 

It is important to note that you can set response headers or status codes at various places within a JSP page, even though this capability appears to violate the rule that this type of response data needs to be specified before any document content is sent to the client. Setting headers and status codes is permitted because servlets that result from JSP pages use a special variety of Writer (of type JspWriter) that partially buffers the document. This buffering behavior can be changed, however; see Section 3.4 for a discussion of the buffer and autoflush attributes of the page directive.

JSP/Servlet Correspondence

It is easy to understand how JSP scriptlets correspond to servlet code: the scriptlet code is just directly inserted into the _jspService method: no strings, no print statements, no changes whatsoever. For instance, Listing 3.4 shows a small JSP sample that includes some static HTML, a JSP expression, and a JSP scriptlet. Listing 3.5 shows a _jspService method that might result. Again, different vendors will produce this code in slightly different ways, and I oversimplified the out variable (which is a JspWriter, not the slightly simpler PrintWriter that results from a call to getWriter). So, don’t expect the code your server generates to look exactly like this.

Listing 3.4. Sample JSP Expression/Scriptlet
<H2>foo</H2> 
<%= bar() %> 
<% baz(); %> 

Listing 3.5. Representative Resulting Servlet Code: Expression/Scriptlet
public void _jspService(HttpServletRequest request, 
                         HttpServletResponse response) 
    throws ServletException, IOException {
  response.setContentType("text/html"); 
  HttpSession session = request.getSession(true); 
  JspWriter out = response.getWriter(); 
  out.println("<H2>foo</H2>");
								out.println(bar());
								baz(); 
  ... 
} 

Scriptlet Example

As an example of code that is too complex for a JSP expression alone, Listing 3.6 presents a JSP page that uses the bgColor request parameter to set the background color of the page. JSP-Styles.css is omitted so that the style sheet does not override the background color. Figures 3-4, 3-5, and 3-6 show the default result, the result for a background of C0C0C0, and the result for papayawhip (one of the oddball X11 color names still supported for historical reasons), respectively.

Figure 3-4. Default result of BGColor.jsp.


Figure 3-5. Result of BGColor.jsp when accessed with a bgColor parameter having the RGB value C0C0C0.


Figure 3-6. Result of BGColor.jsp when accessed with a bgColor parameter having the X11 color name papayawhip.


Listing 3.6. BGColor.jsp
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> 
<HTML> 
<HEAD> 
  <TITLE>Color Testing</TITLE> 
</HEAD> 
<%
								String bgColor = request.getParameter("bgColor");
								if (bgColor == null) { bgColor = "WHITE"; }
								%> 
<BODY BGCOLOR="<%= bgColor %>"> 
<H2 ALIGN="CENTER">Testing a Background of "<%= bgColor %>"</H2> 
</BODY> 
</HTML> 

Using Scriptlets to Make Parts of the JSP Page Conditional

Another use of scriptlets is to conditionally output HTML or other content that is not within any JSP tags. The key to this approach is the fact that code inside a scriptlet gets inserted into the resultant servlet’s _jspService method (called by service) exactly as written and that any static HTML (template text) before or after a scriptlet gets converted to print statements. This means that scriptlets need not contain complete Java statements and that blocks left open can affect the static HTML or JSP outside of the scriptlets. For example, consider the following JSP fragment containing mixed template text and scriptlets.

<% if (Math.random() < 0.5) { %> 
Have a <B>nice</B> day! 
<% } else { %> 
Have a <B>lousy</B> day! 
<% } %> 

You probably find that a bit confusing. I certainly did the first few times. Neither the “have a nice day” nor the “have a lousy day” lines are contained within a JSP tag, so it seems odd that only one of the two becomes part of the output for any given request. But, when you think about how this example will be converted to servlet code by the JSP engine, you get the following easily understandable result.

if (Math.random() < 0.5) {
  out.println("Have a <B>nice</B> day!"); 
} else {
  out.println("Have a <B>lousy</B> day!"); 
} 

XML and Other Special Scriptlet Syntax

There are two special constructs you should take note of. First, if you want to use the characters %> inside a scriptlet, enter %> instead. Second, the XML equivalent of <% Java Code %> is

<jsp:scriptlet>Java Code</jsp:scriptlet> 

In JSP 1.1 and earlier, servers are not required to support this alternative syntax, and in practice few do. In JSP 1.2, servers are required to support this syntax as long as authors don’t mix the XML version (<jsp:scriptlet> ... </jsp:scriptlet>) and the ASP-like version (<% ... %>) in the same page. Remember that XML elements are case sensitive; be sure to use jsp:scriptlet in lower case.

Declarations

A JSP declaration lets you define methods or fields that get inserted into the main body of the servlet class (outside of the _jspService method that is called by service to process the request). A declaration has the following form:

<%! Java Code %> 

Since declarations do not generate any output, they are normally used in conjunction with JSP expressions or scriptlets. The declarations define methods or fields that are later used by expressions or scriptlets. One caution is warranted however: do not use JSP declarations to override the standard servlet life-cycle methods (service, doGet, init, etc.). The servlet into which the JSP page gets translated already makes use of these methods. There is no need for declarations to gain access to service, doGet, or doPost, since calls to service are automatically dispatched to _jspService, which is where code resulting from expressions and scriptlets is put. However, for initialization and cleanup, you can use jspInit and jspDestroy —the standard init and destroy methods are guaranteed to call these two methods when in servlets that come from JSP.

Core Approach

For initialization and cleanup in JSP pages, use JSP declarations to override jspInit and/or jspDestroy .


Aside from overriding standard methods like jspInit and jspDestroy, the utility of JSP declarations for defining methods is somewhat questionable. Moving the methods to separate classes (possibly as static methods) makes them easier to write (since you are using a Java environment, not an HTML-like one), easier to test (no need to run a server), easier to debug (no tricks are needed to see the standard output), and easier to reuse (many different JSP pages can use the same utility class). However, using JSP declarations to define fields, as we will see shortly, gives you something not easily reproducible with separate utility classes: a place to store data that is persistent between requests.

Core Approach

Consider separate helper classes instead of methods defined by means of JSP declarations.


JSP/Servlet Correspondence

JSP declarations result in code that is placed inside the servlet class definition but outside the _jspService method. Since fields and methods can be declared in any order, it does not matter if the code from declarations goes at the top or bottom of the servlet. For instance, Listing 3.7 shows a small JSP snippet that includes some static HTML, a JSP declaration, and a JSP expression. Listing 3.8 shows a servlet that might result. Note that the specific name of the resultant servlet is not defined by the JSP specification, and in fact different servers have different conventions. Besides, as already stated, different vendors will produce this code in slightly different ways, and I oversimplified the out variable (which is a JspWriter, not the slightly simpler PrintWriter that results from a call to getWriter). So, don’t expect the code your server generates to look exactly like this.

Listing 3.7. Sample JSP Declaration
<H1>Some Heading</H1> 
<%! 
  private String randomHeading() {
    return("<H2>" + Math.random() + "</H2>"); 
  } 
%> 
<%= randomHeading() %> 

Listing 3.8. Representative Resulting Servlet Code: Declaration
public class xxxx implements HttpJspPage {
 private String randomHeading() {
								return("<H2>" + Math.random() + "</H2>");
								} 

 public void _jspService(HttpServletRequest request, 
                         HttpServletResponse response) 
  throws ServletException, IOException {
  response.setContentType("text/html"); 
  HttpSession session = request.getSession(true); 
  JspWriter out = response.getWriter(); 
  out.println("<H1>Some Heading</H1>");
								out.println(randomHeading()); 
  ... 
} 

  ... 
} 

Declaration Example

In this example, a JSP fragment prints the number of times the current page has been requested since the server was booted (or the servlet class was changed and reloaded). A hit counter in one line of code!

<%! private int accessCount = 0; %> 
Accesses to page since server reboot: 
<%= ++accessCount %> 

Recall that multiple client requests to the same servlet result only in multiple threads calling the service method of a single servlet instance. They do not result in the creation of multiple servlet instances except possibly when the servlet implements SingleThreadModel (see Section 2.3, “ The Servlet Life Cycle ”). Thus, instance variables (fields) of a normal servlet are shared by multiple requests, and accessCount does not have to be declared static. Now, advanced readers might wonder if the snippet just shown is thread safe; does the code guarantee that each visitor gets a unique count? The answer is no; in unusual situations multiple users could see the same value. For access counts, as long as the count is correct in the long run, it does not matter if two different users occasionally see the same count. But, for values such as session identifiers, it is critical to have unique values. For an example similar to the previous snippet but that guarantees thread safety, see the discussion of the isThreadSafe attribute of the page directive in Section 3.4.

Listing 3.9 shows the full JSP page; Figure 3-7 shows a representative result. Now, before you rush out and use this approach to track access to all your pages, a couple of cautions are in order. First of all, you couldn’t use this for a real hit counter, since the count starts over whenever you restart the server. So, a real hit counter would need to use jspInit and jspDestroy to read the previous count at startup and store the old count when the server is shut down. Even then, it would be possible for the server to crash unexpectedly (e.g., when a rolling blackout strikes Silicon Valley). So, you would have to periodically write the hit count to disk. Finally, some advanced servers support distributed applications whereby a cluster of servers appears to the client as a single server. If your servlets or JSP pages might need to support distribution in this way, plan ahead and avoid the use of fields for persistent data. Use a database instead.

Figure 3-7. Visiting AccessCounts.jsp after it has been requested nine previous times by the same or different clients.


Listing 3.9. AccessCounts.jsp
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> 
<HTML> 
<HEAD> 
<TITLE>JSP Declarations</TITLE> 
<META NAME="keywords" 
      CONTENT="JSP,declarations,JavaServer,Pages,servlets"> 
<META NAME="description" 
      CONTENT="A quick example of JSP declarations."> 
<LINK REL=STYLESHEET 
      HREF="JSP-Styles.css" 
      TYPE="text/css"> 
</HEAD> 
<BODY> 
<H1>JSP Declarations</H1> 
<%! private int accessCount = 0; %> 
<H2>Accesses to page since server reboot: 
<%= ++accessCount %></H2> 
</BODY> 
</HTML> 

XML and Special Declaration Syntax

As with scriptlets, if you want to output %>, enter %> instead. Finally, note that the XML equivalent of <%! Java Code %> is

<jsp:declaration>Java Code</jsp:declaration> 

In JSP 1.1 and earlier, servers are not required to support this alternative syntax, and in practice few do. In JSP 1.2, servers are required to support this syntax as long as authors don’t mix the XML version (<jsp:declaration> ... </jsp:declaration>) and the standard ASP-like version (<%! ... %>) in the same page. Remember that XML elements are case sensitive; be sure to use jsp:declaration in lower case.

Predefined Variables

To simplify code in JSP expressions and scriptlets, you are supplied with eight automatically defined local variables in _jspService, sometimes called implicit objects. Since JSP declarations result in code that appears outside of the _jspService method, these variables are not accessible in declarations. The available variables are request, response, out, session, application, config, pageContext, and page. Details for each are given below.

  • request This variable is the HttpServletRequest associated with the request; it gives you access to the request parameters, the request type (e.g., GET or POST), and the incoming HTTP headers (e.g., cookies).

  • response This variable is the HttpServletResponse associated with the response to the client. Since the output stream (see out) is normally buffered, it is usually legal to set HTTP status codes and response headers in the body of JSP pages, even though the setting of headers or status codes is not permitted in servlets once any output has been sent to the client. If you turn buffering off, however (see the buffer attribute in Section 3.4), you must set status codes and headers before supplying any output.

  • out This variable is the Writer used to send output to the client. However, to make it easy to set response headers at various places in the JSP page, out is not the standard PrintWriter but rather a buffered version of Writer called JspWriter. You can adjust the buffer size through use of the buffer attribute of the page directive. The out variable is used almost exclusively in scriptlets, since JSP expressions are automatically placed in the output stream and thus rarely need to refer to out explicitly.

  • session This variable is the HttpSession object associated with the request. Recall that sessions are created automatically in JSP, so this variable is bound even if there is no incoming session reference. The one exception is when you use the session attribute of the page directive (Section 3.4) to disable session tracking. In that case, attempts to reference the session variable cause errors at the time the JSP page is translated into a servlet.

  • application This variable is the ServletContext as obtained by getServletContext. Servlets and JSP pages can store persistent data in the ServletContext object rather than in instance variables. ServletContext has setAttribute and getAttribute methods that let you store arbitrary data associated with specified keys. The difference between storing data in instance variables and storing it in the ServletContext is that the ServletContext is shared by all servlets in the Web application, whereas instance variables are available only to the same servlet that stored the data.

  • config This variable is the ServletConfig object for this page. The jspInit method would use it to read initialization parameters.

  • pageContext JSP introduced a class called PageContext to give a single point of access to many of the page attributes. The pageContext variable stores the value of the PageContext object associated with the current page. If a method or constructor needs access to multiple page-related objects, passing pageContext is easier than passing many separate references to out, request, response, and so forth.

  • page This variable is simply a synonym for this and is not very useful. It was created as a placeholder for the time when the scripting language could be something other than Java.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.223.190