Servlets
Servlets are classes that handle HTTP requests and generate a response for the client. To have a Servlet ready for deployment, you need to do four things:
- Write the servlet class (must extend HttpServlet)
- Declare the servlet in your web.xml deployment descriptor
- Define one or more url patterns that the servlet responds to
- Package your whole application in a WAR file.
| Base Interface | HTTP-specific Class | Purpose |
|---|---|---|
| Servlet | HttpServlet | Base interface to implement for handling requests |
| ServletRequest | HttpServletRequest | Represents the request |
| ServletResponse | HttpServletResponse | Creates a response |
| ServletConfig | - | Retrieving initialization parameters, servlet name |
| ServletContext | - | Access to web container features: resources, attributes, logging, dispatcher |
| Filter | - | Modify a request before processing, or a response after processing |
| *Listener | Http*Listener | Notifications about various events in the application |
| - | HttpSession | Keeps state for a single client |
package com.jarfiller.example;
import javax.servlet.http.*;
import javax.servlet.*;
import java.io.*;
// Simple dummy servlet with the most important methods
public class SkeletonServlet extends HttpServlet {
public SkeletonServlet() { // default constructor required (more)
}
@Override
public void init(ServletConfig config) // invoked before first request (more)
throws ServletException {
super.init(config); // required when overriding init!
// do all initialization here
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
// handle HTTP GET requests here
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
// handle HTTP POST requests here
}
@Override
public void destroy() { // invoked before server discards the servlet (more)
// release resources here
}
}
Service Dispatching in the HttpServlet
The skeleton servlet above showed you methods like doGet and doPost to process requests. They are provided by the HttpServlet class, and overriding those methods is what you should do in 99% of all servlets.
However, the actual Servlet interface is protocol agnostic and thus does not know anything about the HTTP protocol and its commands, nor will it provide HttpServletRequest and HttpServletResponse objects, which are also HTTP-specific. Instead, Servlet has a single method called service which will be invoked for every request:
void service(ServletRequest req, ServletResponse res);
HttpServlet overrides service and will call one of the doCommandName methods (doGet...), depending on the command of the request. It will also cast the generic request and response objects into HTTP-specific responses.
Servlets are multi-threaded. This means that the web server will call the service methods (doGet, doPost...) from several threads, and thus your servlet implementation must be thread-safe.
The next section shows you two easy ways to make your servlets multi-threaded.
Two Simple Ways to Write Thread-Safe Servlets
Here are two recipes that allow you to write thread-safe servlets without knowing anything about multi-threading (more).
Recipe 1: Synchronize your Servlet
To make your servlet thread-safe, just declare all overriden methods as synchronized (init, destroy, doGet...). This is the easiest way, but also means that you can process only one request at a time. Synchronizing the whole servlet is only feasible for low-volume sites.
The following example shows how to synchronize a Servlet so that only one thread runs in it at a time. Note that there is no constructor, but Java's default constructor will be taken. If you would provide an constructor, you'd need to put the code into a synchronize block with 'this' as synchronization object (more).
public class SynchronizedSkeletonServlet extends HttpServlet {
@Override
public synchronized void init(ServletConfig config) {
super.init(config);
// do all initialization here
}
@Override
protected synchronized void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException {
// handle HTTP GET requests here
}
}
Recipe 2: Restrict Usage of Fields
Alternatively, restrict the use of fields and follow these simple five rules (more):
- All fields in the Servlet class must be volatile.
- Only init can set and modify fields (including objects reachable by those fields).
- The service methods (doGet, doPost...) can read the volatile fields, but must not modify any field.
- Data in attributes, sessions etc must be treated like volatile members: write them in the init method, read-only access in the service methods.
- Constant fields with final modifier are allowed, but can only be modified in the constructor.
Of course, the easiest way to achieve this is to have no fields in your servlet class, and to work only with local variables.
This example shows a simple servlet that initializes a local field in init.
public class RedirectServlet extends HttpServlet {
private volatile String newLocation;
@Override
public void init(ServletConfig config) {
super.init(config);
newLocation = config.getInitParameter("redirectUrl");
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException {
response.sendRedirect(newLocation); // sends client to the configured URL
}
}
To deploy your servlet in a web container, you need to package it as a web application and store it in a WAR file. WARs are JARs with a special file layout and a ".war" extension. They also require a deployment descriptor file called web.xml which must be located at /WEB-INF/web.xml in the WAR.
Web Application Layout
| Path Pattern | Description |
|---|---|
| /* | Static content (HTML, images, stylesheets..) and JSPs (more) |
| /WEB-INF/* | All data except static content |
| /WEB-INF/web.xml | Deployment descriptor (shown below) |
| /WEB-INF/classes/ | The application's Java classes (e.g. your servlet class) |
| /WEB-INF/lib/*.jar | Libraries required by the application |
| /META-INF/* | optional JAR descriptors, vendor extensions (more) |
There are no required files or directories for WARs. A WAR containing only static files does not need WEB-INF at all.
Creating the Web Application / WAR
To create a WAR, you need to
- Copy your classes, libraries and static files into the directory structure shown above
- Create a deployment descriptor at /WEB-INF/web.xml (see below)
- Put the whole directory into a WAR archive (more)
If you use an IDE (such as Eclipse or Netbeans), the IDE will help you assemble the WAR, so you don't have to do this manually.
Also, many application servers allow you to copy the directory directly instead of the deploying a WAR file. This makes deployment faster during development.
You need to declare all servlets in the web.xml deployment descriptor.
Here is a very simple web.xml, declaring only one servlet and mapping it onto a path:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"> <!-- Declare the servlet class --> <servlet> <servlet-name>timeServlet1</servlet-name> <servlet-class>com.jarfiller.example.TimeServlet</servlet-class> </servlet> <!-- Declare the URL path handled by this servlet (more) --> <servlet-mapping> <servlet-name>timeServlet1</servlet-name> <!-- much match servlet-name above! --> <url-pattern>/now</url-pattern> </servlet-mapping> </web-app>
For details on web.xml, visit Jarfiller's Web.xml Reference.
Example Application Layout
As example, here all files of a web application called timeapp.war:
| File | Description |
|---|---|
| /index.html | Default page |
| /images/clock.png | An Image (clock) |
| /images/logo.png | An Image (clock) |
| /WEB-INF/web.xml | Deployment descriptor |
| /WEB-INF/classes/com/jarfiller/example/TimeServlet.class | The servlet class |
| /WEB-INF/classes/com/jarfiller/example/Helper.class | Some other class |
| /WEB-INF/lib/joda-time.jar | A library for the servlet |
The context root is the web application's path on the web server. All paths that you configure in web.xml are relative to the context root. The context root needs to be set in the web container (more).
Let's assume you have a web container running on localhost port 8080, and you set the context root to 'myapp'. Then all static files and all url patterns are relative to the URL "http://localhost:8080/myapp/".
If you don't want your application to reside in a directory, you must set your context root to '/'.
All files in a WAR file (except /WEB-INF/* and /META-INF/*) will automatically be served by the web server as static files, located at the application's base URL (more).
Content Type / MIME Type Mapping
The server determines the content type (MIME type) of static files from their extension. The specification does not require the container to know any extensions, unless you define content type mappings in your web.xml deployment descriptor:
<mime-mapping> <extension>html</extension> <mime-type>text/html</mime-type> </mime-mapping> <mime-mapping> <extension>xhtml</extension> <mime-type>application/xhtml+xml</mime-type> </mime-mapping>
In practice, common file types such as HTML and PNG are known to containers though, and you don't have to define them (hardly anyone does).
Welcome Files
You can define welcome files, which are the names of files which will be shown when a user requests a directory (more). Without them, the server shows a 404 Not Found error. This is a welcome file definition for web.xml:
<welcome-file-list> <!-- ordered by preference --> <welcome-file>index.jsp</welcome-file> <welcome-file>index.xhtml</welcome-file> <welcome-file>index.html</welcome-file> </welcome-file-list>
How to Create a Web Application with Eclipse
Eclipse offers great support for web applications:
- Create a 'Dynamic Web Project' for web applications.
- The 'Dynamic Web Module Version' is the Servlet API version. Select "2.5".
- All files in /WebContent will be copied into the WAR, in addition to all compiled classes. Use it for static files.
- Eclipse can run and debug your web application directly in a local Tomcat server and most other containers (more).
- Use 'Export..' with a 'Web/WAR file' destination to create a WAR.
How to Create a Web Application (WAR) with Ant
Use Ant's war task to create WAR files. You only need to specify the location of the WAR, the web.xml and your files:
<war destfile="build/timeapp.war" webxml="WebContent/WEB-INF/web.xml">
<fileset dir="WebContent/"/> <!-- Copy static files -->
<lib dir="lib/"/> <!-- Copy all libraries (*.jar) -->
<classes dir="build/classes/"/> <!-- Copy classes -->
</war>
How to Deploy a Web Application on Tomcat
Deployment of web applications in Tomcat is very easy:
- To deploy an application, copy the WAR into Tomcat's webapps directory. The application will start automatically.
- Alternatively, you can also copy web application directories (extracted WARs) into webapps.
- You can configure your application either by editing Tomcat's conf/context.xml file, or by putting a file /META-INF/context.xml into your web application. Read Tomcat's Context Configuration documentation.
- The context root is the application's WAR file name (without extension) if you copied a WAR, or the directory name for directories. If the WAR file is called ROOT.war (or you copy a directory called ROOT), it will be deployed with the context root "/".

