Java Servlets - Servlet Tutorial
Java Servlets - Servlet Tutorial
Before a servlet's doGet/doPost method can be called, several things need to have been done:
The servlet must have been compiled in the usual way (using the javac compiler), in an environment where the HttpServlet class and all its
support classes are available on the class path. All these classes are found in the Tomcat servlet.jar file, which we have installed in
/usr/share/java/servlet.jar on all DoC machines. Adding this to your classpath will enable you to compile servlets.
For a servlet to work, it needs a Tomcat context directory to live in. Let's assume that we've already set up a personal tomcat context
directory called example-context for all our examples to go inside. That is, as in both the Personal Tomcat and JSP Tutorial pages, assume
that we've already done the following:
mktomcat6 ~/example-context
cd ~/example-context
Thus, you are already sitting in ~/example-context with nothing else on the directory stack (type dirs).
The servlet class (and any associated support classes) must have been installed into the WEB-INF/classes subdirectory of the context directory,
or jarred up into a .jar file and placed into the WEB-INF/lib subdirectory of the context.
Finally, the context needs to have been configured to map a particular URL onto the particular servlet class. This mapping is contained in a
special file (WEB-INF/web.xml) in the context directory, which this tutorial will tell you more about.
Starting in the ~/example-context directory, push temporarily into the src subdirectory: pushd src.
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
accesses++;
out.print("Number of times this servlet has been accessed:" + accesses);
}
}
This is almost the simplest servlet possible. It has a very simple doGet method, which simply sets up the output for displaying an HTML page
and counts the number of times it has been accessed. It does this with a global variable, which persists as long as the servlet is loaded. This
will be destroyed when the server is restarted.
Now create a Makefile as follows (if you've just been following the JSP tutorial, you'll need to merge the following into the existing Java Bean
Makefile, that's beyond the scope of this tutorial):
CONTEXT = ../webapps/ROOT
CLSDIR = $(CONTEXT)/WEB-INF/classes
CLASSES = Simple.class
all: $(CLASSES)
clean:
/bin/rm -f $(CLASSES) */*.class
install: $(CLASSES)
install -m600 $(CLASSES) $(CLSDIR)
Simple.class: Simple.java
javac Simple.java
Now compile and install everything via make install, fixing any Java or Makefile errors as you go. Then popd to get back into the context top-
level dir.
Now, before we start Tomcat, we have to decide how to map our Simple Servlet into the URL space - there are two choices:
1. You can set it up so that any servlet we install (called CLASSNAME) maps into URL space as:
http://localhost:59999/servlet/CLASSNAME
This is probably the best option for servlet development and experimentation, as it works for any servlet without requiring you to edit the
web.xml file each time you add a servlet.
2. Alternatively, you can choose a specific URL which should map to a chosen servlet. For example, we might want the Simple servlet to
appear as URL:
http://localhost:59999/s
Note that this allows you to completely separate the servlet class name structure from the URL structure of your web application - this
extra level of abstraction is very useful, especially for a more complex web application.
Whichever option you prefer, both involve customizing the WEB-INF/web.xml file, so let's start by pushd web-apps/ROOT (where the web content
and WEB-INF directory lives):
1. The "map each installed servlet CLASSNAME to http://localhost:59999/servlet/CLASSNAME" option uses the Tomcat generic invoker
servlet. This useful servlet (meta-servlet? proxy-servlet? whatever) needs to be configured to manage the "/servlet/*" part of URL
space, and when invoked with a URL like /servlet/XYZ, searches for the XYZ.class, loads it, and then forwards the request to XYZ.
To enable the Invoker servlet, you must add the following code to the middle of WEB-INF/web.xml file:
2. For the second option, where Simple appears as http://localhost:59999/s edit web.xml and add the following:
<!-- The Simple servlet, as URL /s -->
<servlet>
<servlet-name>simple</servlet-name>
<servlet-class>Simple</servlet-class>
<load-on-startup>5</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>simple</servlet-name>
<url-pattern>/s</url-pattern>
</servlet-mapping>
Having customized the web.xml file in whichever way you prefer, pushd, tomcat6 start, point a web browser at the appopriate URL (either
..../servlet/Simple or /s) and you should see the web page generated by the Simple servlet's doGet() method, if we reload the page a few
times you'll see the static counter increment, don't forget to tomcat6 stop afterwards and pushd back into the web app root.
Note that you can add both the above sections to web.xml, and if you do so, the same servlet is accessible via both URLs, but is instantiated
twice, once at each location, so the counter is not shared between both URLs. That is, every time you reload:
http://localhost:59999/s
We recommend always adding the invoker servlet stanza to the web.xml, so that you don't need to edit the web.xml every time you want to
test a new servlet. Indeed, we may even add it to the default web.xml that is created by mktomcat6 in the near future.
See our separate JDBC with DoC Supported Databases document for a single worked example (Films and directors) shown in multiple different
forms - including a pair of Servlet versions, one connecting to Postgres and the other to Microsoft SQL Server. Specifically, here's the source code
of Servlet_Postgres.java and Servlet_MSSQL.java.
Let's try to get them both working in Personal Tomcat, it's simple. Proceed as follows:
As Java source code is involved, check you're back in the example-context top-level directory via dirs and (if necessary) swap dirs with pushd,
then, use pushd src to enter the source directory temporarily (just like you'd do for a java bean).
Take a copy of both of the above files into the src directory, either by wget http://www.doc.ic.ac.uk/csg/java/jdbc/Servlet_Postgres.java and
wget http://www.doc.ic.ac.uk/csg/java/jdbc/Servlet_MSSQL.java, or (more neatly) by using your DoC-specific knowledge of where the CSG web
pages live in Unix filesystem terms, so we can copy both files straight in by:
cp /vol/www/csg/java/jdbc/Servlet*.java .
CONTEXT = ../webapps/ROOT
LIBDIR = $(CONTEXT)/WEB-INF/lib
CLSDIR = $(CONTEXT)/WEB-INF/classes
JARS = servlets.jar
CLASSES = Simple.class Servlet_Postgres.class Servlet_MSSQL.class
clean:
/bin/rm -f $(JARS) $(CLASSES) $(CLSDIR)/* $(LIBDIR)/*
servlets.jar: $(CLASSES)
jar cf servlets.jar $(CLASSES)
Simple.class: Simple.java
javac Simple.java
Servlet_Postgres.class: Servlet_Postgres.java
javac Servlet_Postgres.java
Servlet_MSSQL.class: Servlet_MSSQL.java
javac Servlet_MSSQL.java
Note that this time we're jarring all the servlet classes up, for installing into WEB-INF/lib.
Now compile and install everything via make install, fixing any Java or Makefile errors as you go. Then popd to get back into the context top-
level dir.
Now, if you've followed our advice and added the invoker servlet stanza into web.xml, then - as soon as you tomcat6 start - your new servlets
will be accessible via
http://localhost:59999/servlet/Servlet_Postgres
and
http://localhost:59999/servlet/Servlet_MSSQL
If not, then you'll need to swap dirs again via pushd, and modify the WEB-INF/web.xml file - you could choose specific URLs for the Postgres and
MSSQL versions of the servlet, but why not now take our advice and add the invoker servlet stanza into web.xml! Then swap dirs again (back