Section 3.2. Servlet Basics


3.2. Servlet Basics

The Servlet API consists of two packages, javax.servlet and javax.servlet.http. The javax is left over from an earlier stage of Java package naming conventions. As mentioned (and as indicated by the fact that this chapter appears in Part I of this book), servlets are a standard part of J2EE.

3.2.1. The Servlet Lifecycle

When a client makes a request involving a servlet, the server loads and executes the appropriate Java classes. Those classes generate content, and the server sends the content back to the client. In most cases, the client is a web browser, the server is a web server, and the servlet returns standard HTML. From the web browser's perspective, this isn't any different from requesting a page generated by a CGI script or, indeed, a static HTML file. On the server side, however, there is

Figure 3-1. The servlet lifecycle


an important difference: persistence.[*] Instead of shutting down at the end of each request, the servlet can remain loaded, ready to handle subsequent requests. Figure 3-1 shows how this all fits together.

[*] Note that we use "persistent" to mean "enduring between invocations," not "written to permanent storage."

The request processing time for a servlet can vary, but it is typically quite fast when compared to a similar CGI program. The real performance advantage of a servlet is that you incur most of the startup overhead only once. Most of the I/O-intensive resources (such as database connection pools) your application will need can be created by the servlet container at startup and shared by all your servlets. Instead of connecting to the databaseor just loading your codethousands of times a day, the container loads it only once. When the container loads a servlet for the first time, it calls the init(ServletConfig) method, which is allowed to complete before the servlet is asked to respond to any requests.[] After the init( ) method runs, the servlet container marks the servlet as available. For each incoming connection directed at a particular servlet, the container calls the service( ) method on the servlet to process the request. The service( ) method can have access to all the resources created in the init( ) method. The servlets destroy( ) method is called to clean up resources when the server shuts down.

[] The init( ) method used to be an important way to create I/O-intensive resources. In more recent versions of the Servlet API, it has largely been supplanted by resource setup at the application level (via ServletContextListener, discussed later in this chapter) and at the container level.

Because servlets are persistent, you can actually remove a lot of filesystem and/or database access altogether. For example, to implement a page counter, you can simply store a number in a static variable rather than consulting a file (or database) for every request. Using this technique, you need to read and write to the disk only occasionally to preserve state. Since a servlet remains active, it can perform other tasks when it is not servicing client requests, such as running a background processing thread (i.e., where clients connect to the servlet to view a result) or even acting as an RMI host, enabling a single servlet to handle connections from multiple types of clients. For example, if you write an order processing servlet, it can accept transactions from both an HTML form and an applet using RMI.

The Servlet API includes numerous methods and classes for making application development easier. Most common CGI tasks require a lot of fiddling on the programmer's part; even decoding HTML form parameters can be a chore, to say nothing of dealing with cookies and session tracking. Libraries exist to help with these tasks, but they are, of course, decidedly nonstandard. You can use the Servlet API to handle most routine tasks, thus cutting development time and keeping things consistent for multiple developers on a project.

3.2.2. Writing Servlets

The three core elements of the Servlet API are the javax.servlet.Servlet interface, the javax.servlet.GenericServlet class, and the javax.servlet.http.HttpServlet class. Normally, you create a servlet by subclassing one of the two classes, although if you are adding servlet capability to an existing object, you may find it easier to implement the interface.

The GenericServlet class is used for servlets that don't implement any particular communication protocol. Here's a basic servlet that demonstrates servlet structure by printing a short message:

 import javax.servlet.*; import java.io.*;   public class BasicServlet extends GenericServlet {     public void service(ServletRequest req, ServletResponse resp)     throws ServletException, IOException {       resp.setContentType("text/plain");     PrintWriter out = resp.getWriter(  );    // We won't use the ServletRequest object in this example     out.println("Hello.");   } }

BasicServlet extends the GenericServlet class and implements one method: service( ). Whenever a server wants to use the servlet, it calls the service( ) method, passing ServletRequest and ServletResponse objects (we'll look at these in more detail shortly). The servlet tells the server what type of response to expect, gets a PrintWriter from the response object, and transmits its output.

Why Two Classes?

The designers of the original Servlet API expected that it would used for a variety of protocols above and beyond simple HTTP, hence the decision to create both a GenericServlet and an HttpServlet class. In practice, this never happened: APIs for other protocols use different mechanisms for content management. Prior to Version 2.3, generic servlets were often used to filter content from other servlets, a role now assumed by the Filter interface. Most servlets subclass HttpServlet.


3.2.3. HTTP Servlets

The HttpServlet class is an extension of GenericServlet that includes methods for handling HTTP-specific data.[*] HttpServlet provides a number of methods, such as doGet( ), doPost( ), and doPut( ), to handle particular types of HTTP requests (GET, POST, and so on). These methods are called by the default implementation of the service( ) method, which figures out what kind of request is being made and then invokes the appropriate method. Here's a simple HttpServlet:

[*] HttpServlet is an abstract class, implemented by your servlet classes.

 import javax.servlet.*; import javax.servlet.http.*; import java.io.*;   public class HelloWorldServlet extends HttpServlet {     public void doGet(HttpServletRequest req, HttpServletResponse resp)     throws ServletException, IOException {       resp.setContentType("text/html");     PrintWriter out = resp.getWriter(  );       out.println("<html>");     out.println(         "<head><title>Have you seen this before?</title></head>");     out.println(         "<body><h1>Hello, World!</h1><h6>Again.</h6></body></html>");   } }

HelloWorldServlet demonstrates many essential servlet concepts. First, HelloWorldServlet extends HttpServlet. This is standard practice for an HTTP servlet. HelloWorldServlet defines one method, doGet( ), which is called whenever anyone requests a URL that points to this servlet. The doGet( ) method is actually called by the default service( ) method of HttpServlet. The service( ) method is called by the web server when a request is made of HelloWorldServlet; the method determines what kind of HTTP request is being made and dispatches the request to the appropriate doXXX( ) method (in this case, doGet( )). doGet( ) is passed two objects, HttpServletRequest and HttpServletResponse, that contain information about the request and provide a mechanism for the servlet to produce output, respectively.

The doGet( ) method itself does three things. First, it sets the output type to text/html, which indicates that the servlet produces standard HTML as its output. Second, it calls the getWriter( ) method of the HttpServletResponse parameter to get a java.io.PrintWriter that points to the client. Finally, it uses the stream to send some HTML back to the client. This isn't really a whole lot different from the BasicServlet example, but it gives us all the tools we'll need later on for more complex web applications. We do have to explicitly set the content type, as there is no default setting, even for HTTP servlets where one might reasonably expect text/html.

If you define a doGet( ) method for a servlet, you may also want to override the getLastModified( ) method of HttpServlet. The server calls getLastModified( ) to find out if the content delivered by a servlet has changed. The default implementation of this method returns a negative number, which tells the server that the servlet doesn't know when its content was last updated, so the server is forced to call doGet( ) and return the servlet's output. If you have a servlet that changes its display data infrequently (such as a servlet that verifies uptime on several server machines once every 15 minutes), you should implement getLastModified( ) to allow browsers to cache responses. getLastModified( ) should return a long value that represents the time the content was last modified as the number of milliseconds since midnight, January 1, 1970, GMT (returned by calling the getTime( ) method java.util.Date).

A servlet should also implement getServletInfo( ), which returns a String that contains information about the servlet, such as name, author, and version (just like getAppletInfo( ) in applets). This method is called by the web server and generally used for logging purposes. It's rarely implemented in the real world, but it really is good practice to do so.



Java Enterprise in a Nutshell
Java Enterprise in a Nutshell (In a Nutshell (OReilly))
ISBN: 0596101422
EAN: 2147483647
Year: 2004
Pages: 269

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net