Just as this book was going to press, Sun announced a new way to use servlets, called JavaServer Pages (commonly, but not officially, referred to as JSP). JSP's functionality and syntax bear a remarkable resemblance to Active Server Pages (ASP).
JSP operates in many ways like server-side includes. The main difference is that instead of embedding a <SERVLET> tag in an HTML page, JSP embeds actual snippets of servlet code. It's an attempt by Sun to separate content from presentation, more convenient than server-side includes for pages that have chunks of dynamic content intermingled with static content in several different places.
Just like server-side includes and servlet chaining, JSP doesn't require any changes to the Servlet API. But it does require special support in your web server. This support is not included in the Java Web Server 1.1.1 (the unofficially considered reference servlet engine against which this book is written), but it's expected to be introduced in the next version of the Java Web Server, probably 1.2, and in other servlet engines as they keep pace.
Note that the following tutorial is based on the JavaServer Pages draft specification, version 0.91. You may notice small changes in the final specification.
At its most basic, JSP allows for the direct insertion of servlet code into an otherwise static HTML file. Each block of servlet code (called a scriptlet) is surrounded by a leading <% tag and a closing %> tag.[8] For convenience, a scriptlet can use four predefined variables:
[8]An earlier technology, called Page Compilation, uses <JAVA> and </JAVA> tags and a different internal syntax. Page Compilation has been deprecated in favor of JavaServer Pages.
The servlet request, an HttpServletRequest object
The servlet response, an HttpServletResponse object
The output writer, a PrintWriter object
The input reader, a BufferedReader object
Example 2-6 shows a simple JSP page that says "Hello" in a manner similar to Example 2-2, though with a lot less code. It makes use of the predefined request and out variables.
If you have a server that supports JavaServer Pages and want to test this page, you should place the file under the server's document root (probably server_root/public_html) and save it with a special extension. By default, this extension for JSP pages is .jsp. Assuming you have saved the page as hello1.jsp, you can then access it at the URL http://server:port/hello1.jsp. A screen shot is shown in Figure 2-11.
<HTML> <HEAD><TITLE>Hello</TITLE></HEAD> <BODY> <H1> <% if (request.getParameter("name") == null) { out.println("Hello World"); } else { out.println("Hello, " + request.getParameter("name")); } %> </H1> </BODY></HTML>
How does JSP work? Behind the scenes, the server automatically creates, compiles, loads, and runs a special servlet to generate the page's content, as shown in Figure 2-12. You can think of this special servlet as a background, workhorse servlet. The static portions of the HTML page are generated by the workhorse servlet using the equivalent of out.println() calls, while the dynamic portions are included directly. For example, the servlet shown in Example 2-7 might be the background workhorse for hello1.jsp.[9]
[9] If you're interested in seeing the true servlet source code for a JSP page, poke around the directories under your server root. After all, the server needs to save the Java source code somewhere before compiling it! If you find the true servlet source, you're likely to see that it is far more complicated and convoluted than what is shown here.
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class _hello1_xjsp extends HttpServlet { public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); BufferedReader in = request.getReader(); out.println("<HTML>"); out.println("<HEAD><TITLE>Hello</TITLE></HEAD>"); out.println("<BODY>"); out.println("<H1>"); if (request.getParameter("name") == null) { out.println("Hello World"); } else { out.println("Hello, " + request.getParameter("name")); } out.println("</H1>"); out.println("</BODY></HTML>"); } }
The first time you access a JSP page, you may notice that it takes a short time to respond. This is the time necessary for the server to create and compile the background servlet. Subsequent requests should be as fast as ever because the server can reuse the servlet. The one exception is when the .jsp file changes, in which case the server notices and recompiles a new background servlet. If there's ever an error in compiling, you can expect the server to somehow report the problem, usually in the page returned to the client.
In addition to scriptlets, JavaServer Pages allow the use of expressions and directives . A JSP expression begins with <%= and ends with %>. Any Java expression between the two tags is evaluated, the result is converted to a String, and the text is included directly in the page. This technique eliminates the clutter of an out.println() call. For example, <%= foo %> includes the value of the foo variable.
A JSP directive begins with <%@ and ends with %>. A directive allows a JSP page to control certain aspects of its workhorse servlet. Directives can be used to have the workhorse servlet set its content type, import a package, extend a different superclass, implement an interface, and handle either GET or POST requests. A directive can even specify the use of a non-Java scripting language.
In between the directive tags certain key variables can be assigned values using the following syntax:
<%@ varname = "value" %>
Here are the six variables you can set:
Specifies the content type of the generated page. For example:
<%@ content_type = "text/plain" %>
The default content type is "text/html".
Specifies a list of classes the servlet should import. Multiple classes can be given in a comma-separated list or given through multiple import directives. For example:
<%@ import = "java.io.*,java.util.Hashtable" %>
Specifies the superclass the servlet should extend. For example:
<%@ extends = "CustomHttpServletSuperclass" %>
The default superclass is HttpServlet.
Specifies a list of interfaces the servlet should implement. Multiple interfaces can be given in a comma-separated list or given through multiple import directives. For example:
<%@ implements = "Serializable" %>
The default behavior is to not implement anything.
Specifies the servlet method that should contain the generated code and handle client requests. The default is "service", which handles all requests. For example:
<%@ method = "doPost" %>
Specifies the scripting language used by the back-end. The default language is "java". Some servers can choose to allow other languages. For example:
<%@ language = "java" %>
Example 2-8 shows a revised version of the Hello page that uses JSP expressions and directives. It uses a method directive to indicate it should handle POST requests, and it uses an expression to simplify its display of the name parameter.
<%@ method = "doPost" %> <HTML> <HEAD><TITLE>Hello</TITLE></HEAD> <BODY> <H1> <% if (request.getParameter("name") == null) { %> Hello World <% } else { %> Hello, <%= request.getParameter("name") %> <% } %> </H1> </BODY></HTML>
The background workhorse servlet for this JSP page should look nearly identical to Example 2-7, with the only difference that this servlet implements doPost() instead of service().
Sometimes it's necessary for a JSP page to define methods and nonlocal variables in its workhorse servlet. For this there is a construct called a JSP declaration.
A declaration begins with a <SCRIPT RUNAT="server"> tag and ends with a </SCRIPT> tag. In between the tags, you can include any servlet code that should be placed outside the servlet's service method. Example 2-9 demonstrates this with a JSP page that uses a declaration to define the getName() method.
<HTML> <HEAD><TITLE>Hello</TITLE></HEAD> <BODY> <H1> Hello, <%= getName(request) %> </H1> </BODY> </HTML> <SCRIPT RUNAT="server"> private static final String DEFAULT_NAME = "World"; private String getName(HttpServletRequest req) { String name = req.getParameter("name"); if (name == null) return DEFAULT_NAME; else return name; } </SCRIPT>
The background servlet created to generate this page might look like the servlet shown in Example 2-10.
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class _hello3_xjsp extends HttpServlet { public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); BufferedReader in = request.getReader(); out.println("<HTML>"); out.println("<HEAD><TITLE>Hello</TITLE></HEAD>"); out.println("<BODY>"); out.println("<H1>"); out.println("Hello, " + getName(request)); out.println("</H1>"); out.println("</BODY></HTML>"); } private static final String DEFAULT_NAME = "World"; private String getName(HttpServletRequest req) { String name = req.getParameter("name"); if (name == null) return DEFAULT_NAME; else return name; } }
One of the most interesting and powerful ways to use JavaServer Pages is in cooperation with JavaBeans components. JavaBeans are reusable Java classes whose methods and variables follow specific naming conventions to give them added abilities. They can be embedded directly in a JSP page using <BEAN> tags. A JavaBean component can perform a well-defined task (execute database queries, connect to a mail server, maintain information about the client, etc.) and make its resulting information available to the JSP page through simple accessor methods.[10]
[10] For more information on JavaBeans, see http://java.sun.com/bean/and the book Developing Java Beans by Robert Englander (O'Reilly).
The difference between a JavaBeans component embedded in a JSP page and a normal third-party class used by the generated servlet is that the web server can give JavaBeans special treatment. For example, a server can automatically set a bean's properties (instance variables) using the parameter values in the client's request. In other words, if the request includes a name parameter and the server detects through introspection (a technique in which the methods and variables of a Java class can be programatically determined at runtime) that the bean has a name property and a setName(String name) method, the server can automatically call setName() with the value of the name parameter. There's no need for getParameter() .
A bean can also have its scope managed automatically by the server. A bean can be assigned to a specific request (where it is used once and destroyed or recycled) or to a client session (where it's automatically made available every time the same client reconnects). Sessions and session tracking are covered in depth in Chapter 7, "Session Tracking".
A bean can even be implemented as a servlet! If the server detects that a bean implements the javax.servlet.Servlet interface (either directly or by extending GenericServlet or HttpServlet), it will call the bean's service() method once for each request and the bean's init() method when the bean is first created. The utility of this functionality is debatable, but it can be used by beans that need to prepare somehow before handling requests.
Beans are embedded in a JSP page using the <BEAN> tag. It has the following syntax:
<BEAN NAME="lookup name" VARNAME="alternate variable name" TYPE="class or interface name" INTROSPECT="{yes|no}" BEANNAME="file name" CREATE="{yes|no}" SCOPE="{request|session}"> <PARAM property1=value1 property2=value2> </BEAN>
You can set the following attributes of the <BEAN> tag:
Specifies the name of the bean. This is the key under which the bean is saved if its scope extends across requests. If a bean instance saved under this name already exists in the current scope, that instance is used with this page. For example:
NAME="userPreferences"
Specifies the variable name of the bean. This is the name used by the page to refer to the bean and invoke its methods. For example:
VARNAME="prefs"
If not given, the variable name of the bean is set to the value of its name attribute.
Specifies the name of the bean's class or interface type. For example:
TYPE="UserPreferencesBean"
The type defaults to java.lang.Object.
Specifies if the server should set the bean's properties using the parameter values in the client's request. Its value must be "yes" or "no". The default is "yes".
Specifies the serialized file or class file that contains the bean, used when first creating the bean. This is an optional attribute. For example:
BEANNAME="hellobean.ser"
Specifies if the bean should be created if it doesn't already exist. Its value must be "yes" or "no". The default is "yes". If create is set to "no" and a preexisting instance isn't found, an error is returned to the client.
Specifies if the bean should be assigned to a specific request (where it is used once and destroyed or recycled) or to a client session (where it's automatically made available every time the same client reconnects, within a certain time frame). Its value must be "request" or "session". The default is "request".
Parameters can be passed to a bean as a list using a <PARAM> tags placed between the opening <BEAN> tag and the closing </BEAN> tag. The parameter values are used to set the bean's properties using introspection.
Example 2-11 demonstrates the use of a JavaBeans component with a JSP page; it says Hello with the help of a HelloBean.
<%@ import = "HelloBean" %> <BEAN NAME="hello" TYPE="HelloBean" INTROSPECT="yes" CREATE="yes" SCOPE="request"> </BEAN> <HTML> <HEAD><TITLE>Hello</TITLE></HEAD> <BODY> <H1> Hello, <%= hello.getName() %> </H1> </BODY> </HTML>
As you can see, using a JavaBeans component with JavaServer Pages greatly reduces the amount of code necessary in the page. This allows a clean separation of content (the functionality the bean provides) from presentation (the HTML structure of the page). By using a well-defined API to interact with the bean, even nonprogrammers can write JSP pages.
The code for HelloBean is shown in Example 2-12. Its class file should be placed in the server's classpath (something like server_root/classes, although for the Java Web Server you need to first create this directory).
public class HelloBean { private String name = "World"; public void setName(String name) { this.name = name; } public String getName() { return name; } }
This is about as simple a bean as you'll ever see. It has a single name property that is set using setName() and retrieved using getName(). The default value of name is "World", but when a request comes in that includes a NAME parameter, the property is set automatically by the server with a call to setName(). To test the mechanism, try browsing to http://server:port/hellobean.jsp. You should see something similar to the screen shot in Figure 2-13.
Copyright © 2001 O'Reilly & Associates. All rights reserved.
This HTML Help has been published using the chm2web software. |