2.3 Page Generation

Java Servlet Programming, 2nd Edition > 2. HTTP Servlet Basics > 2.3 Page Generation

 
< BACKCONTINUE >

2.3 Page Generation

The most basic type of HTTP servlet generates a full HTML page. Such a servlet has access to the same information usually sent to a CGI script, plus a bit more. A servlet that generates an HTML page can be used for all the tasks for which CGI is used currently, such as for processing HTML forms, producing reports from a database, taking orders, checking identities, and so forth.

2.3.1 Writing Hello World

Example 2-1 shows an HTTP servlet that generates a complete HTML page. To keep things as simple as possible, this servlet just says "Hello World" every time it is accessed via a web browser.[1]

[1] Fun trivia: the first instance of a documented "Hello World" program appeared in A Tutorial Introduction to the Language B, written by Brian Kernighan in 1973. For those too young to remember, B was a precursor to C. You can find more information on the B programming language and a link to the tutorial at http://cm.bell-labs.com/who/dmr/bintro.html.

Example 2-1. A Servlet That Prints "Hello World"
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class HelloWorld extends HttpServlet {   public void doGet(HttpServletRequest req, HttpServletResponse res)                                throws ServletException, IOException {     res.setContentType("text/html");     PrintWriter out = res.getWriter();     out.println("<HTML>");     out.println("<HEAD><TITLE>Hello World</TITLE></HEAD>");     out.println("<BODY>");     out.println("<BIG>Hello World</BIG>");     out.println("</BODY></HTML>");   } }

This servlet extends the HttpServlet class and overrides the doGet( ) method inherited from it. Each time the web server receives a GET request for this servlet, the server invokes this doGet( ) method, passing it an HttpServletRequest object and an HttpServletResponse object.

The HttpServletRequest represents the client's request. This object gives a servlet access to information about the client, the parameters for this request, the HTTP headers passed along with the request, and so forth. Chapter 4 explains the full capabilities of the request object. For this example, we can completely ignore it. After all, this servlet is going to say "Hello World" no matter what the request!

The HttpServletResponse represents the servlet's response. A servlet can use this object to return data to the client. This data can be of any content type, though the type should be specified as part of the response. A servlet can also use this object to set HTTP response headers. Chapter 5 and Chapter 6, explain everything a servlet can do as part of its response.

Our servlet first uses the setContentType( ) method of the response object to set the content type of its response to text/html, the standard MIME content type for HTML pages. Then, it uses the getWriter( ) method to retrieve a PrintWriter, the international-friendly counterpart to a PrintStream. PrintWriter converts Java's Unicode characters to a locale-specific encoding. For an English locale, it behaves the same as a PrintStream. Finally, the servlet uses this PrintWriter to send its HelloWorld HTML to the client.

That's it! That's all the code needed to say hello to everyone who "surfs" to our servlet.

2.3.2 Running Hello World

When developing servlets you need two things: the Servlet API class files, which are used for compiling, and a servlet container such as a web server, which is used for running the servlets. All popular servlet containers provide the Servlet API class files so you can satisfy both requirements with one download.

There are dozens of servlet containers available for servlet deployment, several of which are listed in Chapter 1. Just be sure when selecting a server to find one that supports Version 2.2 of the Servlet API or later. This was the first Servlet API version to provide support for web applications as discussed in this chapter. A current list of servlet containers and what API level they support is available at http://www.servlets.com.

So, what do we do with our code to make it run in a web server? Well, it depends on the web server. The examples in this book use the Apache Tomcat 3.2 server, the Servlet API reference implementation, written entirely in Java and available under an open source license from http://jakarta.apache.org. The Tomcat server includes plenty of documentation explaining the use of the server, so while we discuss the general concepts involved with managing the server, we're leaving the details to the server's own documentation. If you choose to use another web server, these instructions should work for you, but we cannot make any guarantees.

If you are using the Apache Tomcat server, you should put the source code for the servlet in the server_root/webapps/ROOT/WEB-INF/classes directory (where server_root is the directory where you installed your server). This is a standard location for servlet class files. We'll talk about the reason servlets go in this directory later in the chapter.

Once you have the HelloWorld source code in the right location, you need to compile it. The standard javac compiler (or your favorite graphical Java development environment) can do the job. Just be sure you have the javax.servlet and javax.servlet.http packages in your classpath. With the Tomcat server, all you have to do is include server_root/lib/servlet.jar (or a future equivalent) somewhere in your classpath. The filename and location is server dependent, so look to your server's documentation if you have problems. If you see an error message that says something like Package javax.servlet not found in import that means the servlet packages aren't being found by your compiler; fix your classpath and try again.

Now that you have your first servlet compiled, there is nothing more to do but start your server and access the servlet! Starting the server is easy. Look for the startup.sh script (or startup.bat batch file under Windows) in the server_root/bin directory. This should start your server if you're running under Solaris or Windows. On other operating systems, you may need to make small edits to the startup scripts. In the default configuration, the server listens on port 8080.

There are several ways to access a servlet. For this example, we'll do it by explicitly accessing a URL with /servlet/ prepended to the servlet's class name. You can enter this URL in your favorite browser: http://server:8080/servlet/HelloWorld. Replace server with the name of your server machine or with localhost if the server is on your local machine. You should see a page similar to the one shown in Figure 2-3.

Figure 2-3. The Hello World servlet

If the servlet were part of a package, it would need to be placed in server_root/webapps/ROOT/WEB-INF/classes/package.name and referred to with the URL http://server:8080/servlet/package.name.HelloWorld.

Not all servers by default allow servlets to be accessed using the generic /servlet/ prefix. This feature may be turned off for security reasons, to ensure servlets are accessed only via specific URLs set up during the server administration. Check your server's documentation for details on how to turn on and off the /servlet/ prefix.

2.3.3 Handling Form Data

The "Hello World" servlet is not very exciting, so let's try something slightly more ambitious. This time we'll create a servlet that greets the user by name. It's not hard. First, we need an HTML form that asks the user for his or her name. The following page should suffice:

<HTML> <HEAD> <TITLE>Introductions</TITLE> </HEAD> <BODY> <FORM METHOD=GET ACTION="/servlet/Hello"> If you don't mind me asking, what is your name? <INPUT TYPE=TEXT NAME="name"><P> <INPUT TYPE=SUBMIT> </FORM> </BODY> </HTML>

Figure 2-4 shows how this page appears to the user.

Figure 2-4. An HTML form

This form should go in an HTML file under the server's document_root directory. This is the location where the server looks for static files to serve. For the Tomcat server, this directory is server_root/webapps/ROOT. By putting the file in this directory, it can be accessed directly as http://server:8080/form.html.

When the user submits this form, his name is sent to the Hello servlet because we've set the ACTION attribute to point to the servlet. The form is using the GET method, so any data is appended to the request URL as a query string. For example, if the user enters the name "Inigo Montoya," the request URL is http://server:8080/servlet/Hello?name=Inigo+Montoya. The space in the name is specially encoded as a plus sign by the browser because URLs cannot contain spaces.

A servlet's HttpServletRequest object gives it access to the form data in its query string. Example 2-2 shows a modified version of our Hello servlet that uses its request object to read the name parameter.

Example 2-2. A Servlet That Knows to Whom It's Saying Hello
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class Hello extends HttpServlet {   public void doGet(HttpServletRequest req, HttpServletResponse res)                                throws ServletException, IOException {     res.setContentType("text/html");     PrintWriter out = res.getWriter();     String name = req.getParameter("name");     out.println("<HTML>");     out.println("<HEAD><TITLE>Hello, " + name + "</TITLE></HEAD>");     out.println("<BODY>");     out.println("Hello, " + name);     out.println("</BODY></HTML>");   }   public String getServletInfo() {     return "A servlet that knows the name of the person to whom it's" +            "saying hello";   } }

This servlet is nearly identical to the HelloWorld servlet. The most important change is that it now calls req.getParameter("name") to find out the name of the user and that it then prints this name instead of the harshly impersonal (not to mention overly broad) "World." The getParameter( ) method gives a servlet access to the parameters in its query string. It returns the parameter's decoded value or null if the parameter was not specified. If the parameter was sent but without a value, as in the case of an empty form field, getParameter( ) returns the empty string.

This servlet also adds a getServletInfo( ) method. A servlet can override this method to return descriptive information about itself, such as its purpose, author, version, and/or copyright. It's akin to an applet's getAppletInfo( ). The method is used primarily for putting explanatory information into a web server administration tool. You'll notice we won't bother to include it in future examples because it is clutter in the way of learning.

The servlet's output looks something like what is shown in Figure 2-5.

Figure 2-5. The Hello servlet using form data

2.3.4 Handling POST Requests

You've now seen two servlets that implement the doGet( ) method. Now let's change our Hello servlet so that it can handle POST requests as well. Because we want the same behavior with POST as we had for GET, we can simply dispatch all POST requests to the doGet( ) method with the following code:

public void doPost(HttpServletRequest req, HttpServletResponse res)                               throws ServletException, IOException {   doGet(req, res); }

Now the Hello servlet can handle form submissions that use the POST method:

<FORM METHOD=POST ACTION="/servlet/Hello">

In general, it is best if a servlet implements either doGet( ) or doPost( ). Deciding which to implement depends on what sort of requests the servlet needs to be able to handle, as discussed earlier. The code you write to implement the methods is almost identical. The major difference is that doPost( ) has the added ability to accept large amounts of input.

You may be wondering what would have happened had the Hello servlet been accessed with a POST request before we implemented doPost( ). The default behavior inherited from HttpServlet for both doGet( ) and doPost( ) is to return an error to the client saying the requested URL does not support that method.

2.3.5 Handling HEAD Requests

A bit of under-the-covers magic makes it trivial to handle HEAD requests (sent by a client when it wants to see only the headers of the response). There is no doHead( ) method to write. Any servlet that subclasses HttpServlet and implements the doGet( ) method automatically supports HEAD requests.

Here's how it works. The service( ) method of the HttpServlet identifies HEAD requests and treats them specially. It constructs a modified HttpServletResponse object and passes it, along with an unchanged request, to the doGet( ) method. The doGet( ) method proceeds as normal, but only the headers it sets are returned to the client. The special response object effectively suppresses all body output.

Although this strategy is convenient, you can sometimes improve performance by detecting HEAD requests in the doGet( ) method, so that it can return early, before wasting cycles writing output that no one will see. Example 2-3 uses the request's getMethod( ) method to implement this strategy (more properly called a hack) in our Hello servlet.

Example 2-3. The Hello Servlet Modified to Return Quickly in Response to HEAD Requests
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class Hello extends HttpServlet {   public void doGet(HttpServletRequest req, HttpServletResponse res)                                throws ServletException, IOException {     // Set the Content-Type header     res.setContentType("text/html");     // Return early if this is a HEAD     if (req.getMethod().equals("HEAD")) return;     // Proceed otherwise     PrintWriter out = res.getWriter();     String name = req.getParameter("name");     out.println("<HTML>");     out.println("<HEAD><TITLE>Hello, " + name + "</TITLE></HEAD>");     out.println("<BODY>");     out.println("Hello, " + name);     out.println("</BODY></HTML>");   } }

Notice that we set the Content-Type header, even if we are dealing with a HEAD request. Headers such as these are returned to the client. Some header values, such as Content-Length, may not be available until the response has already been calculated. If you want to be accurate in returning these header values, the effectiveness of this shortcut is limited.

Make sure that you end the request handling with a return statement. Do not call System.exit( ). If you do, you risk exiting the web server.


Last updated on 3/20/2003
Java Servlet Programming, 2nd Edition, © 2001 O'Reilly

< BACKCONTINUE >


Java servlet programming
Java Servlet Programming (Java Series)
ISBN: 0596000405
EAN: 2147483647
Year: 2000
Pages: 223

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