Chapter 2
IN THIS CHAPTER
Looking at servlets
Downloading, installing, and configuring Tomcat
Creating simple servlets
Working with forms to get data from the user
Servlets are among the most popular ways to develop web applications today. Many of the best-known websites are powered by servlets, including Gmail, Amazon, LinkedIn, and eBay. In this chapter, I give you just the basics: what a servlet is, how to set up your computer so that you can code and test servlets, and how to create a simple servlet. The next two chapters build on this topic, presenting additional web programming techniques.
Before you can understand what a servlet is and how it works, you need to understand the basics of how web servers work. Web servers use a networking protocol called HTTP to send web pages to users. (HTTP stands for Hypertext Transfer Protocol, but that won’t be on the test.) With HTTP, a client computer uses a uniform resource locator, or URL, to request a document that’s located on the server computer. HTTP uses a request/response model, which means that client computers (web users) send request messages to HTTP servers, which in turn send response messages back to the clients.
A basic HTTP interaction works something like this:
Using a web-browser program running on a client computer, you specify the URL of a file that you want to access.
In some cases, you actually type the URL of the address, but most of the time you click a link that specifies the URL.
Your web browser sends an HTTP request message to the server computer indicated by the URL.
The request includes the name of the file that you want to retrieve.
The most important thing to note about normal web interactions is that they’re static. By static, I mean that the content of the file sent to the user is always the same. If the user requests the same file 20 times in a row, the same page displays 20 times.
By contrast, a servlet provides a way for the content to be dynamic. A servlet is simply a Java program that extends the javax.servlet.Servlet
class. The Servlet
class enables the program to run on a web server in response to a user request, and output from the servlet is sent back to the web user as an HTML page.
When you use servlets, Steps 1, 2, and 4 of the preceding procedure are the same; the fateful third step is what sets servlets apart. If the URL specified by the user refers to a servlet rather than a file, Step 3 goes more like this:
In other words, instead of sending the contents of a file, the server sends the output generated by the servlet program. Typically, the servlet program generates some HTML that’s displayed by the browser.
Servlets are designed to get their work done quickly and then end. Each time a servlet runs, it processes one request from a browser, generates one page that’s sent back to the browser, and then ends. The next time that user or any other user requests the same servlet, the servlet runs again.
Unfortunately, you can’t run servlet programs on any old computer. First, you have to install a special program called a servlet engine to turn your computer into a server that’s capable of running servlets. The best-known servlet engine is Apache Tomcat, which is available free from the Apache Software Foundation at http://tomcat.apache.org
. For this chapter, I used Tomcat version 8.
Tomcat can also work as a basic web server. In actual production environments, Tomcat is usually used in combination with a specialized web server, such as Apache’s HTTP Server.
Installing Tomcat isn’t rocket science, but it’s not as easy as making toast, either. Here are the steps you can follow to set up Tomcat 8:
Download the Tomcat Zip file from the Apache website (http://tomcat.apache.org
).
Although Apache also offers an executable setup file for installing Tomcat, I suggest that you download the Zip file instead.
Extract the contents of the Zip file by right-clicking the file and choosing Extract All; then specify c:
as the location to extract the files to.
I know you don’t want to clutter your root directory with a bunch of files, but the Tomcat Zip file contains a single folder named apache-tomcat-8_0_0
(the version number may vary), so only this one folder is created. After all the files are extracted, give this folder a new name that’s a little easier to type. I suggest c: omcat
.
Create an environment variable named JAVA_HOME
that points to the location of your Java Development Kit (JDK).
To create an environment variable, open Control Panel, double-click the System icon, and then click Advanced System Settings⇒ Environment Variables⇒ New, and create a variable named JAVA_HOME
. The value of this variable needs to be the complete path to your JDK installation folder, such as c:Program FilesJavajdk-9
.
A common mistake is to set this variable to the bin
directory or to the directory for the Java Runtime Environment (JRE), not the JDK. If Tomcat doesn’t start up later, double-check the JAVA_HOME
directory.
Copy the servlet-api.jar
file to the jrelibext
folder in your JDK root.
If your JDK is installed in c:Program FilesJavajdk-9
, copy this file to c:Program FilesJavajdk-9jrelibext
. You find the servlet-api.jar
file in c: omcatlib
, assuming that you extracted the Tomcat files to c: omcat
.
If you skip this step or copy the servlet-api.jar
file to the wrong place, you can’t compile your servlet programs. If you get compiler messages complaining that the javax.servlet
package doesn’t exist, double-check this step to make sure you performed it right.
After you install and configure Tomcat, you can start it by opening a command window, changing to the c: omcatin
directory, and typing startup. A batch file runs, starting Tomcat. When Tomcat starts, it opens a second command window that displays various status messages. Figure 2-1 shows the status window in action.
INFO: Server startup in 1186 ms
<Connector port="8080"… />
Change the port number from 8080 to some other number, such as 18080. Later, when you display servlets in a browser window, you have to specify this number as the HTTP port number instead of 8080.
You don’t need to shut down Tomcat after you start it unless you make a change in one of its configuration files. If you do, you can shut down Tomcat by running the shutdown
batch file from the c: omcatin
directory. Then you can run the startup
batch file to get Tomcat going again.
To find out whether you installed Tomcat correctly, you can try running the test servlets that are automatically installed when you install Tomcat. Open a web-browser window, and type this address:
http://localhost:8080
(If you changed the port number by editing the server.xml
file, as I discuss in the preceding section, use the port number you specified instead of 8080.)
The page shown in Figure 2-2 appears. If it doesn’t, refer to the section “Installing and configuring Tomcat,” earlier in this chapter, and double-check each step to make sure you did it correctly.
Okay, enough of the configuration stuff; now you can start writing some code. The following sections go over the basics of creating a simple HelloWorld
–type servlet.
Most servlets need access to at least three packages: javax.servlet
, javax.servlet.http
, and java.io
. As a result, you usually start with these import
statements:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
Depending on what other processing your servlet does, you may need additional import
statements.
To create a servlet, you write a class that extends the HttpServlet
class. Table 2-1 lists six methods you can override in your servlet class.
TABLE 2-1 The HttpServlet Class
Method |
When Called |
Signature |
|
|
|
|
|
|
|
|
|
|
|
|
|
First time servlet is run |
|
destroy() |
Servlet is destroyed |
|
Most servlets override at least the doGet
method. This method is called by the servlet engine when a user requests the servlet by typing its address in the browser’s address bar or by clicking a link that leads to the servlet.
Two parameters are passed to the doGet
method:
HttpServletRequest
object representing the incoming request from the user. You use the request
parameter primarily to retrieve data entered by the user in form fields. You find out how to do that later in this chapter, in the section “Getting Input from the User.”HttpServletResponse
object representing the response that is sent back to the user. You use the response
parameter to compose the output that is sent back to the user. You find out how to do that in the next section.One of the main jobs of most servlets is writing HTML output that’s sent back to the user’s browser. To do that, you first call the getWriter
method of the HttpServletResponse
class, which returns a PrintWriter
object that’s connected to the response object. Thus, you can use the familiar print
and println
methods to write HTML text.
Here’s a doGet
method for a simple HelloWorld
servlet:
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
PrintWriter out = response.getWriter();
out.println("Hello, World!");
}
Here the PrintWriter
object returned by response.getWriter()
is used to send a simple text string back to the browser. If you run this servlet, the browser displays the text Hello, World!
In most cases, you don’t want to send simple text back to the browser. Instead, you want to send formatted HTML. To do that, you must first tell the response object that the output is in HTML format. You can do that by calling the setContentType
method, passing the string "text/html"
as the parameter. Then you can use the PrintWriter
object to send HTML.
Listing 2-1 shows a basic HelloWorld
servlet that sends an HTML response.
LISTING 2-1 The HelloWorld Servlet
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
public class HelloWorld extends HttpServlet
{
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>HelloWorld</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Hello, World!</h1>");
out.println("</body>");
out.println("</html>");
}
}
Here the following HTML is sent to the browser (I added indentation to show the HTML’s structure):
<html>
<head>
<title>HelloWorld</title>
</head>
<body>
<h1>Hello, World!</h1>
</body>
</html>
When run, the HelloWorld
servlet produces the page shown in Figure 2-3.
For your reference, Table 2-2 summarizes all the HTML tags that I use in this book.
TABLE 2-2 Just Enough HTML to Get By
HTML tag |
Description |
|
Marks the start and end of an HTML document. |
|
Marks the start and end of the head section of an HTML document. |
|
Marks a title element. The text between the start and end tags is shown in the title bar of the browser window. |
|
Marks the start and end of the body section of an HTML document. The content of the document is provided between these tags. |
< |
Formats the text between these tags as a level-1 heading. |
< |
Formats the text between these tags as a level-2 heading. |
< |
Formats the text between these tags as a level-3 heading. |
|
Marks the start of a form. The |
|
Marks the end of a form. |
|
Creates an input field. Specify |
|
Represents a nonbreaking space. |
So exactly how do you run a servlet? First, you must compile the .java
file to create a .class
file; then you must move the .class
file into a directory from which Tomcat can run the servlet. For testing purposes, you can move the servlet’s class file to c: omcatwebappsExamplesWEB-INFclasses
and then type an address like this one in your browser’s address bar:
<http://localhost:8080/servlet/HelloWorld
You may also want to override the doPost
method, which is called if the user requests your servlet from a form. In many cases, you’ll just call doGet
from the doPost
method, so that both get and post requests are processed in the same way.
As you know, the doGet
method is called whenever the user enters the address of your servlet in the address bar or clicks a link that leads to your servlet. But many — if not most — servlets are associated with HTML forms, which provide fields in which the user can enter data. The normal way to send form data from the browser to the server is with an HTTP POST
request, not a GET
request.
If you want a servlet to respond to POST
requests, you can override the doPost
method instead of, or in addition to, the doGet
method. Other than the method name, doPost
has the same signature as doGet
. In fact, it’s not uncommon to see servlets in which the doPost
method simply calls doGet
, so that both POST
and GET
requests are processed identically. To do that, code the doPost
method like this:
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
doGet(request, response);
}
The HelloWorld
servlet, shown in Listing 2-1 earlier in this chapter, isn’t very interesting because it always sends the same text. Essentially, it’s a static servlet — which pretty much defeats the purpose of using servlets in the first place. You could just as easily have provided a static HTML page.
Listing 2-2 shows the code for a more dynamic HelloWorld
servlet. This version randomly displays one of six greetings. It uses the random
method of the Math
class to pick a random number from 1 to 6 and then uses this number to decide which greeting to display. It also overrides the doPost
method as well as the doGet
method, so posts and gets are handled identically.
LISTING 2-2 The HelloServlet Servlet
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
public class HelloServlet extends HttpServlet
{
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String msg = getGreeting();
out.println("<html>");
out.println("<head>");
out.println(
"<title>HelloWorld Servlet</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>");
out.println(msg);
out.println("</h1>");
out.println("</body>");
out.println("</html>");
}
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
doGet(request, response);
}
private String getGreeting()
{
String msg = "";
int rand = (int)(Math.random() * (6)) + 1;
switch (rand)
{
case 1:
return "Hello, World!";
case 2:
return "Greetings!";
case 3:
return "Felicitations!";
case 4:
return "Yo, Dude!";
case 5:
return "Whasssuuuup?";
case 6:
return "Hark!";
}
return null;
}
}
If a servlet is called by an HTTP GET
or POST
request that came from a form, you can call the getParameter
method of the request
object to get the values entered by the user in each form field. Here’s an example:
String name = request.getParameter("name"
Here the value entered in the form input field named name
is retrieved and assigned to the String
variable name
.
As you can see, retrieving data entered by the user in a servlet is easy. The hard part is creating a form in which the user can enter the data. To do that, you create the form by using a separate HTML file. Listing 2-3 shows an HTML file named InputServlet.html
that displays the form shown in Figure 2-4.
LISTING 2-3 The InputServlet.html File
<html>
<head>
<title>Input Servlet</title>
</head>
<body>
<form action="/servlet/InputServlet"
method="post">
Enter your name:
<input type="text" name="Name">
<br><br>
<input type="submit" value="Submit">
</form>
</body>
</html>
The action
attribute in the form
tag of this form specifies that /servlet/InputServlet
is called when the form is submitted, and the method
attribute indicates that the form is submitted via a POST
rather than a GET
request.
The form itself consists of an input text field named name
and a Submit button. It’s nothing fancy — just enough to get some text from the user and send it to a servlet.
Listing 2-4 shows a servlet that can retrieve the data from the form shown in Listing 2-3.
LISTING 2-4 The InputServlet Servlet
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class InputServlet extends HttpServlet
{
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
String name = request.getParameter("Name");
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Input Servlet</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>");
out.println("Hello " + name);
out.println("</h1>");
out.println("</body>");
out.println("</html>");
}
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
doGet(request, response);
}
}
As you can see, this servlet really isn’t much different from the first HelloWorld
servlet in Listing 2-1. The biggest difference is that it retrieves the value entered by the user in the name
field and uses it in the HTML that’s sent to the response PrintWriter
object. If the user enters Calvin Coolidge
in the name
input field, for example, the following HTML is generated:
<html>
<head>
<title>HelloWorld</title>
</head>
<body>
<h1>Hello Calvin Coolidge</h1>
</body>
</html>
Thus the message Hello Calvin Coolidge
is displayed on the page.
Although real-life servlets do a lot more than just parrot back information entered by the user, most of them follow this surprisingly simple structure — with a few variations, of course. Real-world servlets validate input data and display error messages if the user enters incorrect data or omits important data, and most real-world servlets retrieve or update data in files or databases. Even so, the basic structure is pretty much the same.
When you develop servlets, you often want to access other classes that you’ve created, such as input/output (I/O) classes that retrieve data from files or databases, utility or helper classes that provide common functions such as data validation, and perhaps even classes that represent business objects such as customers or products. To do that, all you have to do is save the class files in the classes
directory of the servlet’s home directory — which, for the purposes of this chapter, is c: omcatwebappsROOTWEB-INFclasses
.
To illustrate a servlet that uses several classes, Figure 2-5 shows the output from a servlet that lists movies read from a text file. This servlet uses three classes:
Movie
: A class that represents an individual movie.MovieIO
: A class that has a static public method named getMovies
. This method returns an ArrayList
object that contains all the movies read from the file.ListFiles
: The main servlet class. It calls the MovieIO.getMovies
class to get an ArrayList
of movies and then displays the movies on the page.The code for the Movie
class is shown in Listing 2-5. As you can see, this class doesn’t have much: It defines three public fields (title
, year
, and price
) and a constructor that lets you create a new Movie
object and initialize the three fields. Note that this servlet doesn’t use the price
field.
LISTING 2-5 The Movie Class
public class Movie
{
public String title;
public int year;
public double price;
public Movie(String title, int year,
double price)
{
this.title = title;
this.year = year;
this.price = price;
}
}
Listing 2-6 shows the MovieIO
class. This class uses the file I/O features that are presented in Book 8, Chapter 2 to read data from a text file. The text file uses tabs to separate the fields and contains these lines:
It's a Wonderful Life→1946→14.95
The Great Race→1965→12.95
Young Frankenstein→1974→16.95
The Return of the Pink Panther→1975→11.95
Star Wars→1977→17.95
The Princess Bride→1987→16.95
Glory→1989→14.95
Apollo 13→1995→19.95
The Game→1997→14.95
The Lord of the Rings: The Fellowship of the Ring→2001→19.95
Here the arrows represent tab characters in the file. I’m not going to go over the details of this class here, except to point out that getMovies
is the only public method in the class, and it’s static, so you don’t have to create an instance of the MovieIO
class to use it. For details on how this class works, turn to Book 8, Chapter 2.
LISTING 2-6 The MovieIO Class
import java.io.*;
import java.util.*;
public class MovieIO
{
public static ArrayList<Movie> getMovies()
{
ArrayList<Movie> movies =
new ArrayList<Movie>();
BufferedReader in =
getReader("c:\data\movies.txt");
Movie movie = readMovie(in);
while (movie != null)
{
movies.add(movie);
movie = readMovie(in);
}
return movies;
}
private static BufferedReader getReader(
String name)
{
BufferedReader in = null;
try
{
File file = new File(name);
in = new BufferedReader(
new FileReader(file) );
}
catch (FileNotFoundException e)
{
System.out.println(
"The file doesn't exist.");
System.exit(0);
}
return in;
}
private static Movie readMovie(BufferedReader in)
{
String title;
int year;
double price;
String line = "";
String[] data;
try
{
line = in.readLine();
}
catch (IOException e)
{
System.out.println("I/O Error");
System.exit(0);
}
if (line == null)
return null;
else
{
data = line.split(" ");
title = data[0];
year = Integer.parseInt(data[1]);
price = Double.parseDouble(data[2]);
return new Movie(title, year, price);
}
}
}
Listing 2-7 shows the code for the ListMovie
servlet class.
LISTING 2-7 The ListMovie Servlet Class
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
public class ListMovies extends HttpServlet
{
public void doGet(HttpServletRequest request, →8
HttpServletResponse response)
throws IOException, ServletException
{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String msg = getMovieList();
out.println("<html>");
out.println("<head>");
out.println(
"<title>List Movies Servlet</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Some of My Favorites</h1>");
out.println("<h3>");
out.println(msg);
out.println("</h3>");
out.println("</body>");
out.println("</html>");
}
public void doPost(HttpServletRequest request, →28
HttpServletResponse response)
throws IOException, ServletException
{
doGet(request, response);
}
private String getMovieList() →35
{
String msg = "";
ArrayList<Movie> movies = MovieIO.getMovies();
for (Movie m : movies)
{
msg += m.year + ": ";
msg += m.title + "<br>";
}
return msg;
}
}
The following paragraphs describe what its methods do:
doGet
method calls the getMovieList
method to get a string that contains a list of all the movies, separated by break (<br>
) tags. Then it uses a series of out.println
statements to write HTML that displays this list.doPost
method simply calls the doGet
method. That way, the servlet works whether it is invoked by a GET
or a POST
request.getMovieList
method calls the MovieIO.getMovies
method to get an ArrayList
that contains all the movies read from the file. Then it uses an enhanced for
loop to retrieve each Movie
object. Each movie’s year and title is added to the msg
string, separated by <br>
tags.