Java Servlets – Part 1 Article

Tweet

Whether you consider yourself to be an experienced Java developer or not, it’s a safe bet that you’ve heard of Java Applets. Applets are little Java programs that run as part of a Web page. Since they’re sort of ‘mini-applications’, they were dubbed ‘applets’. Java Servlets got their name in a similar way.

Think of Servlets as highly efficient CGI programs written in Java. When a Servlet-capable Web server receives a request for a URL that corresponds to a Java Servlet, the server hands the request off to the Servlet for processing. The Servlet dynamically produces a response to the request (typically an HTML Web page) and sends it back to the requesting browser. If you think of Servlets in this context as ‘mini-servers’, their name makes perfect sense.

In this article, I’ll take you through the basics of writing and deploying Java Servlets on your own Web server. I’ll begin with the assumption that you’re already equipped with a Servlet-capable Web server. While there are many offerings in this arena, the free combination of Apache and Tomcat is the most readily available. Most experienced Java developers prefer one of the slick, commercial solutions such as Caucho Resin, IBM WebSphere, or Allaire JRun (see a complete list); and while most of these are free for non-commercial use, the standard, “nitty gritty” methods supported by Tomcat are what we’ll work with in this article. If you haven’t already set up Apache and Tomcat, now would be a good time. See my JSP Quick-Start Guide for a helpful walkthrough, upon which the assumed configuration in this article is based.

By their very nature as Java programs, Servlets require a significant amount of knowledge to develop with. At the very least, you’ll need to be familiar with the basics of the Java language before you undertake the task of writing your first Java Servlet. The previous articles in this series, Getting Started with Java, Java Language Basics and Object Oriented Concepts in Java Part 1 and Part 2 are definitely required reading if you’re just making your start in Java programming.

If you’re relatively comfortable with the features of the Java language presented in those articles, and you’ve got Apache and Tomcat running together on your server, you’re ready to go! Let’s write a Servlet!

A Simple Servlet

When it comes right down to it, a Servlet is just a Java class, and you should already know how to write a Java class:

public class MyClassName {
// ... properties and methods ...
}

But not just any class will do. Servlets for use on the Web should be subclasses of the javax.servlet.http.HttpServlet class, which is built into every Web server that supports servlets. Although different servers may implement this class differently, the properties and methods supported by it are dictated by the Java Servlet Specification. As of this writing, version 2.2 is the latest release of the spec, though version 2.3 is in the final draft stage. The documentation that makes up the specification includes a reference of all of the classes that Servlet-capable servers must provide.

So creating a Servlet is as simple as creating a subclass of HttpServlet:

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class MyServlet extends HttpServlet {
// ... properties and methods ...
}

Notice that we’re importing the three packages java.io, javax.servlet and javax.servlet.http in the above. javax.servlet.http contains the HttpServlet class that we’re extending, while javax.servlet contains a number of classes related to working with Servlets and java.io contains all the standard Java classes for performing input and output. Since the vast majority of Servlets make use of classes in those latter two packages, it’s best to just include them right off the bat so we don’t forget later.

A Servlet must provide at least one method that is used by the Web server to handle requests. The name of the method(s) depends on the type of request we want to handle. An HTTP GET request is the simplest form of page request, and comes about either as a result of the user typing a URL or clicking on a link. To let your Servlet handle GET requests, you must provide a method called doGet as follows:

public void doGet(HttpServletRequest req, HttpServletResponse rsp)
throws ServletException, IOException {
// ... handle GET requests
}

As you can see, doGet must be a public method that returns nothing (void), and takes two parameters:

  • An HttpServletRequest object (this class is part of the javax.servlet.http package), which in the above example we assign to a variable called req.
  • An HttpServletResponse object (also in javax.servlet.http), which we assign to rsp.

When this method is called, the HttpServletRequest (req) passed as a parameter will be an object that provides access to all the information related to the browser request that triggered this Servlet. Using various methods of HttpServletRequest, you can find out things like the IP address of the requesting browser, or the values sent in the URL query string (e.g. index.html?name=value). Meanwhile the HttpServletResponse (rsp) represents the response to be sent to the browser. It is this object that allows us to send HTML code back to the browser, for instance. But more on req and rsp in a moment.

If you’re worried about the throws ServletException, IOException portion of the function declaration, don’t be. We haven’t covered this in any of the previous articles in this series, but it’s really pretty simple. All this does is indicate the types of Exceptions (errors) that may occur as a result of calling this method. In this case, when the Web server calls the doGet function in order to process a GET request, it must be prepared for the fact that a ServletException or an IOException may occur, and it must handle these errors gracefully. While this sounds scary, it actually makes our job easier. An IOException, for example, could occur if the Web browser was closed before it finished downloading the response our Servlet was sending it. But since the doGet function is declared such that it may throw (cause) IOExceptions, we don’t have to worry about these errors, since the Web server will handle them for us when they do occur!

Now, in this example, we’ll make our Servlet send a simple HTML page to the browser in response to its request. Here’s the complete code for the doGet method:

public void doGet(HttpServletRequest req, HttpServletResponse rsp)
throws ServletException, IOException {
rsp.setContentType("text/html");
PrintWriter out = rsp.getWriter();
out.println("<html>");
out.println("<head><title> Simple Servlet </title></head>");
out.println("<body>");
out.println("<p>This is a simple Servlet!</p>");
out.println("</body></html>");
}

This again isn’t as complicated as it may seem at first glance. Let’s step through the body of this method one line at a time:

rsp.setContentType("text/html");

On this line, we are calling the setContentType method of the rsp variable (which you’ll recall contains an HttpServletResponse object). This method sets the HTTP Content-Type header to the "text/html" MIME type, which tells the Web browser to expect an HTML Web page. Any Servlet that generates a Web page must start by setting this content type. Likewise, a Servlet that generates a plain text file would set the Content-Type to "text/plain", and a Servlet that generated a GIF file would use "image/gif".

PrintWriter out = rsp.getWriter();

Now, since we’re going to generate a Web page, we’ll want to send HTML code to the Web browser. HTML code is simply plain text, and the standard Java I/O class for outputting plain text data is java.io.PrintWriter. On this line, we declare a variable called out to store a PrintWriter (recall that we imported the java.io package, so we can refer to this class directly without giving its fully qualified name). To obtain a PrintWriter object that is set up to output text as the response to the Web browser, we simply call the getWriter method of rsp, which contains our response object, and assign the returned value to our new out variable.

out.println("<html>");

The rest of the doGet method simply uses the PrintWriter (out) to output HTML code to the browser. Just as in the sample programs in previous articles, where we could output text to the screen with System.out.println (System.out is also a PrintWriter), we can output lines of text to the Web browser with the println method of our out object. Recall that println automatically starts a new line at the end of the String that it is told to output. If you don’t want to start a new line in the HTML code, you can use the print method instead of println.

Download the full MyServlet.java file or type it out from the listings above and save it somewhere convenient on your computer (I use a directory called D:JavaDev, for example). Next, we’ll see how to compile and deploy a Servlet.

Compiling a Servlet

All of the Java programs we’ve seen so far were very simple to compile. Unfortunately, if you try to compile the MyServlet.java file we produced in the previous section, you’ll get a number of pretty ugly error messages:

D:javadev> javac MyServlet.java
MyServlet.java:2: package javax.servlet does not exist
import javax.servlet.*;
^
MyServlet.java:3: package javax.servlet.http does not exist
import javax.servlet.http.*;
^
MyServlet.java:5: cannot resolve symbol
symbol  : class HttpServlet
location: class MyServlet
public class MyServlet extends HttpServlet {
^
...

Now, the best tactic I find when tackling compilation errors is to look at the errors listed at the top first, since those errors could actually be causing some of the other errors that are appearing lower down. In this case, for example, the four “cannot resolve symbol” errors you’re likely to see are actually a result of the two “package does not exist” errors at the top. Looking more closely, you’ll notice that the compiler is choking on the two import commands that we used to import the javax.servlet and javax.servlet.http packages. Since it can’t import those packages, we won’t be able to use any of the classes that reside in them, and it turns out that all of the “cannot resolve symbol” errors refer to places where we’re trying to do so.

So why can’t it find those two packages? Well, these two packages aren’t actually built into Java like java.io is. Instead, they come with the Servlet-capable Web server (e.g. Tomcat). So before the Java compiler will be able to compile our Servlet, we need to let it know where to find the classes in these two packages.

The classes required are normally stored in a file called servlet.jar. The exact location of this file will depend on the particular Web server software you use, but in the case of Tomcat you can find it in the lib subdirectory of the main Tomcat installation directory (e.g. d:Program FilesApache Groupjakarta-tomcat-3.2.3libservlet.jar). For the Java compiler to be able to compile Servlets, you need to add this file to your Java class path. By default, Java looks for classes in the current directory (".") only. Thus, "." is the default class path. If you change the class path to include the servlet.jar file (".;d:...libservlet.jar" under Windows, ".:/usr/.../lib/servlet.jar" in Unix), then the Servlet should compile just fine.

You can specify a class path to use when you run javac.exe as follows:

d:javadev> javac -classpath ".;d:Program FilesApache Group
jakarta-tomcat-3.2.3libservlet.jar" MyServlet.java

Obviously, the path to servlet.jar can be quite long and painful to type every time you want to compile a Servlet. As an alternative, you can set an environment variable called CLASSPATH to your desired class path. Set this the same way you do the PATH environment in the particular operating system you are using (instructions for adjusting the PATH environment variable in various operating systems are provided in the install instructions for the JDK if you need them). To temporarily set the CLASSPATH environment variable under Windows, you can use the SET command on the MS-DOS Command Prompt:

d:javadev> SET CLASSPATH=.;d:Program FilesApache Group
jakarta-tomcat-3.2.3libservlet.jar
d:javadev> javac MyServlet.java

Whichever way you go about setting your class path, you should now be able to successfully compile MyServlet.java to obtain MyServlet.class (or download it here).

Deploying a Servlet

In its default configuration, Tomcat expects you to place compiled Servlets in the webappsROOTWEB-INFclasses subdirectory of the Tomcat installation directory to deploy them. Place your compiled MyServlet.class file in that directory, then (assuming Tomcat is running on your local computer) load http://localhost:8080/servlet/MyServlet. If you did everything right, you should see a Web page a lot like this one:

A Simple Servlet in ActionIf you have Apache installed to interface with Tomcat using mod_jk, you should also be able to view your Servlet with http://localhost/servlet/MyServlet (or http://localhost:8000/servlet/MyServlet if you have configured Apache to run on port 8000).

Most of the time, that’s all you need to do to deploy a Servlet! There are some situations, however, where you’d like to make your Servlet available from a different address. One common case is when you assign a package name to a Servlet. For example, consider what would happen if placed the MyServlet class in the package com.sitepoint.web by adding the line

package com.sitepoint.web;

to the top of the MyServlet.java file. To deploy the MyServlet.class file, you would place it in webappsROOTWEB-INFclassescomsitepointweb (recall that the locations of .class files must reflect their package names), and load it with its fully-qualified class name (http://localhost:8080/servlet/com.sitepoint.web.MyServlet). Already this is a fairly ugly URL, and things can get a lot messier with log package or class names.

For this reason, you may want to assign an alternate name to your Servlet. This is done with the web.xml file in the WEB-INF directory (e.g. webappsROOTWEB-INFweb.xml). This is an XML file that lets you configure the Servlets you have deployed. Since XML files are plain text, you can simply open it in Notepad to make the required changes. When you first install Tomcat, web.xml doesn’t contain any configuration information:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
"http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
<web-app>
</web-app>

By adding tags between <web-app> and </web-app>, you can add configuration information for your servlets. Here’s how to assign the name ‘my’ to MyServlet:

<web-app>
<servlet>
<servlet-name>
my
</servlet-name>
<servlet-class>
MyServlet
</servlet-class>
</servlet>
</web-app>

If you save the above changes, then shutdown and restart Tomcat, you will be able to access your Servlet as http://localhost:8080/servlet/my. This may not seem like a big deal, but when your Servlet’s class name is 25 characters in length and is deeply nested in a package, you’ll appreciate being able to give it a nice, short name.

Assigning your Servlet a name also lets you use that name to specify additional configuration parameters for your Servlet. The <servlet-mapping> tag, for instance, lets you map your Servlet to any URL or URL pattern on your server:

<web-app>
<servlet>
<servlet-name>
my
</servlet-name>
<servlet-class>
MyServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>
my
</servlet-name>
<url-pattern>
/my.html
</url-pattern>
</servlet-mapping>
</web-app>

The above code will let you access you Servlet as http://localhost:8080/my.html — completely hiding the fact that you’re using a Servlet at all! You can also specify a <url-pattern> with a wildcard character such as /my/*, which would use your Servlet to display any URL that started with "http://localhost:8080/my/", or *.blah, which would map all requests for filenames ending in .blah to your Servlet. Since the HttpServletRequest object that your Servlet receives lets your Servlet examine the URL that was requested, you could conceivably map a single Servlet to /* and have it handle every request on your Website, sending different responses depending on the URL requested!

If you have Apache set up as your main Web server using mod_jk to forward requests for Servlets and JavaServer Pages (JSPs) to Tomcat, you’ll find that <url-pattern> doesn’t work as expected. This is because, by default, Apache will only forward requests for files ending in .jsp or files in the /servlet directory to Tomcat for processing. To forward additional URL patterns to Tomcat, you must use the JkMount directive in your Apache configuration file. Make sure you do this after the line where you Include Tomcat’s mod_jk.conf-auto file (which loads the module required for JkMount to work). For example, to map /my/*.blah (all .blah files in the /my directory) to Tomcat, you would add the following:

JkMount /my/*.blah ajp13

Note that we specify the more efficient ajp13 protocol for communication between Apache and Tomcat for this mapping (Tomcat’s mod_jk.conf-auto file currently uses the older, less efficient ajp12 for its default mappings). With that change made, restart Tomcat and Apache and your mapping should now work through your Apache server.

As you can see, all this deployment and configuration of Servlets is a fairly messy business when done by standard methods. Commercial Web servers like those I mentioned in the introduction often provide nice, graphical administration interfaces that make all these low-level modifications for you in the background. The format of the web.xml file, however, is defined in the Servlet standard, and is supported by all Servlet-enabled servers, even if easier methods are provided for managing the settings it contains.

A Dynamic Example

The simple Servlet (MyServlet) that we have worked with so far isn’t terribly exciting, because it displays the same thing every time it is loaded. The power of Servlets is that they can generate a new dynamic response every time they are loaded. Common uses of Servlets include retrieving dynamic content from a database, displaying XML documents as HTML using XSL stylesheets, and processing form submissions and taking appropriate actions (e.g. ecommerce applications).

For our first dynamic Servlet, we’ll display the current server date and time. Here’s the code for the servlet (Time.java):

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.Date;

public class Time extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse rsp)
throws ServletException, IOException {
rsp.setContentType("text/html");
PrintWriter out = rsp.getWriter();

Date now = new Date(); // The current date/time

out.println("<html>");
out.println("<head><title> Time Check </title></head>");
out.println("<body>");
out.println("<p>The time is: " + now + "</p>");
out.println("</body></html>");
}
}

All in all, this Servlet is very similar to MyServlet. Let’s look at what’s new:

import java.util.Date;

We import Java’s built-in Date class from the java.util package. You can read up on this class in the Java API documentation if you’re curious about its properties and methods.

Date now = new Date(); // The current date/time

We create a new variable called now and store a new Date object in it. When a Date object is created, it contains the date and time at which it was created, and will display them when it is printed out as part of a String:

out.println("<p>The time is: " + now + "</p>");

Compile this file (or download Time.class) and deploy it as shown in the previous section. Now, when you load http://localhost:8080/servlet/Time you’ll see a page like this one:

The Time Check ServletClick Reload a few times in your browser and watch the page change each time.

Summary and Resources for Further Reading

In this article, we learned the basics of Java Servlets — small Java programs that run inside your Web server and process browser requests and return dynamically-generated Web pages in response. We saw how to write, compile, and deploy a simple Servlet using standard methods supported by all Servlet-enabled Web servers. Finally, we saw a slightly more complex example that displays the current time whenever it is loaded.

There’s a lot more to Servlets than what we saw here! In Part 2, we’ll see how to use the HttpServletRequest object to process form submissions with a Servlet. We’ll also look at the HttpServletResponse object to see what else it’s able to do. Finally, we’ll learn a few more tricks that can be used in web.xml to fine-tune the Servlets installed on our Web server.

Java Servlet Programming 2nd EditionFor a complete and thorough look at Servlets and everything they’re capable of, I recommend Jason Hunter and William Crawford’s excellent book, Java Servlet Programming 2nd Edition. Not only does it cover everything there is to know about Servlets with an incredible level of detail, but it does so while supporting every point with practical examples and lucid, and sometimes humorous discussion. The book also delves into many of the technologies that are built on top of the Servlets framework, such as JavaServer Pages (JSP), the Element Construction Set (ECS), and the Tea Framework.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Vibhuti Goel

    Thank you so much!! Finally compiled my servlet after 2 days of struggle….phew!!!!!

  • James

    Very well done! I am learning servlets with the book “Core Servlets & JavaServer Pages” by Hall & Brown. It is absolutely horrid. I have a better understanding after going through your web pages than I did after reading several chapters of my book. Thanks!

  • arjun

    CLEAR explanation! I am new to servlets,I got clear about it now!thanks !

  • http://sureshsvn.com suresh svn

    Great Article. Well Written !

  • ANKUR

    VERY CLEAR EXPLAINED..THANKU