epubjs
Version:
Render ePub documents in the browser, across many devices
417 lines (408 loc) • 106 kB
HTML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Java Web Applications</title><link rel="stylesheet" href="core.css" type="text/css"/><meta name="generator" content="DocBook XSL Stylesheets V1.74.0"/></head><body><div class="sect1" title="Java Web Applications"><div class="titlepage"><div><div><h1 class="title"><a id="learnjava3-CHP-15-SECT-2"/>Java Web Applications</h1></div></div></div><p>So far we’ve used the term <span class="emphasis"><em>web application</em></span>
generically, referring to any kind of browser-based application that is
located on a web server. Now we are going to be more precise with that
term. In the context of the Java Servlet API, a web application is a
collection of servlets and Java web services that support Java classes,
content such as HTML or JSP pages and images, and configuration
information. For deployment (installation on a web server), a web
application is bundled into a WAR file. We’ll discuss WAR files in detail
later, but suffice it to say that they are really just JAR archives that
contain all the application files along with some deployment information.
The important thing is that the standardization of WAR files means not
only that the Java code is portable, but also that the process of
deploying the application to a server is standardized.</p><p>Most WAR archives have at their core a <span class="emphasis"><em>web.xml</em></span>
file. This is an XML configuration file that describes which servlets are
to be deployed, their names and URL paths, their initialization
parameters, and a host of other information, including security and
authentication requirements. In recent years, however, the
<span class="emphasis"><em>web.xml</em></span> file has become optional for many
applications due to the introduction of Java annotations that take the
place of the XML configuration. In most cases, you can now deploy your
servlets and Java web services simply by annotating the classes with the
necessary information and packaging them into the WAR file, or using a
combination of the two. We’ll discuss this in detail later in the
chapter.</p><p>Web applications, or web apps, also have a well-defined runtime
environment. Each web app has its own “root” path on the web server,
meaning that all the URLs addressing its servlets and files start with a
common unique prefix (e.g.,
<span class="emphasis"><em>http://www.oreilly.com/someapplication/</em></span>). The web
app’s servlets are also isolated from those of other web applications. Web
apps cannot directly access each other’s files (although they may be
allowed to do so through the web server, of course). Each web app also has
its own <span class="emphasis"><em>servlet context</em></span>. We’ll discuss the servlet
context in more detail, but in brief, it is a common area for servlets
within an application to share information and get resources from the
environment. The high degree of isolation between web applications is
intended to support the dynamic deployment and updating of applications
required by modern business systems and to address security and
reliability concerns. Web apps are intended to be coarse-grained,
relatively complete applications—not to be tightly coupled with other web
apps. Although there’s no reason you can’t make web apps cooperate at a
high level, for sharing logic across applications you might want to
consider web services, which we’ll discuss later in this chapter.</p><div class="sect2" title="The Servlet Lifecycle"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-15-SECT-2.1"/>The Servlet Lifecycle</h2></div></div></div><p><a id="idx10859" class="indexterm"/> <a id="idx10889" class="indexterm"/>Let’s jump now to the Servlet API and get started building
servlets. We’ll fill in the gaps later when we discuss various parts of
the APIs and WAR file structure in more detail. The Servlet API is very
simple (reminiscent of the old Applet API). The base <a id="I_indexterm15_id776576" class="indexterm"/><code class="literal">Servlet</code> class has three
lifecycle methods—<a id="I_indexterm15_id776587" class="indexterm"/><code class="literal">init()</code>, <a id="I_indexterm15_id776599" class="indexterm"/><a id="I_indexterm15_id776605" class="indexterm"/><code class="literal">service()</code>, and <code class="literal">destroy()</code>—along with some methods for getting
configuration parameters and servlet resources. However, these methods
are not often used directly by developers. Generally developers will
implement the <a id="idx10847" class="indexterm"/><code class="literal">doGet()</code> and <a id="I_indexterm15_id776637" class="indexterm"/><code class="literal">doPost()</code> methods of the
<a id="I_indexterm15_id776648" class="indexterm"/><code class="literal">HttpServlet</code> subclass
and access shared resources through the servlet context, as we’ll
discuss shortly.</p><p>Generally, only one instance of each deployed servlet class is
instantiated per container. More precisely, it is one instance per
servlet entry in the <span class="emphasis"><em>web.xml</em></span> file, but we’ll talk
more about servlet deployment later. In the past, there was an exception
to that rule when using the special <code class="literal">SingleThreadModel</code> type of servlet. As of
Servlet API 2.4, single-threaded servlets have been deprecated.</p><p>By default, servlets are expected to handle requests in a
multithreaded way; that is, the servlet’s service methods may be invoked
by many threads at the same time. This means that you should not store
per-request or per-client data in instance variables of your servlet
object. (Of course, you can store general data related to the servlet’s
operation, as long as it does not change on a per-request basis.)
Per-client state information can be stored in a client
<span class="emphasis"><em>session</em></span> object on the server or in a client-side
cookie, which persists across client requests. We’ll talk about client
state later as well.</p><p>The <code class="literal">service()</code> method of a
servlet accepts two parameters: a servlet “request” object and a servlet
“response” object. These provide tools for reading the client request
and generating output; we’ll talk about them (or rather their <code class="literal">HttpServlet</code> versions) in detail in the
examples.<a id="I_indexterm15_id776708" class="indexterm"/><a id="I_indexterm15_id776715" class="indexterm"/></p></div><div class="sect2" title="Servlets"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-15-SECT-2.2"/>Servlets</h2></div></div></div><p>The package of primary interest to us here is <a id="I_indexterm15_id776730" class="indexterm"/><code class="literal">javax.servlet.http</code>,
which contains APIs specific to servlets that handle HTTP requests for
web servers. In theory, you can write servlets for other protocols, but
nobody really does that and we are going to discuss servlets as if all
servlets were HTTP-related.</p><p>The primary tool provided by the <code class="literal">javax.servlet.http</code> package is the <a id="I_indexterm15_id776752" class="indexterm"/><code class="literal">HttpServlet</code> base class.
This is an abstract servlet that provides some basic implementation
details related to handling an HTTP request. In particular, it overrides
the generic servlet <code class="literal">service()</code> request
and breaks it out into several HTTP-related methods, including <code class="literal">doGet()</code>, <a id="I_indexterm15_id776776" class="indexterm"/><code class="literal">doPost()</code>, <a id="I_indexterm15_id776786" class="indexterm"/><code class="literal">doPut()</code>, and <code class="literal">doDelete()</code>. The default <a id="I_indexterm15_id776802" class="indexterm"/><code class="literal">service()</code> method
examines the request to determine what kind it is and dispatches it to
one of these methods, so you can override one or more of them to
implement the specific protocol behavior you need.</p><p><code class="literal">doGet()</code> and <code class="literal">doPost()</code> correspond to the standard HTTP
<a id="I_indexterm15_id776826" class="indexterm"/><code class="literal">GET</code> and <a id="I_indexterm15_id776836" class="indexterm"/><code class="literal">POST</code> operations.
<code class="literal">GET</code> is the standard request for
retrieving a file or document at a specified URL. <code class="literal">POST</code> is the method by which a client sends an
arbitrary amount of data to the server. HTML forms utilize <code class="literal">POST</code> to send data as do most web
services.</p><p>To round these out, <code class="literal">HttpServlet</code>
provides the <code class="literal">doPut()</code> and <code class="literal">doDelete()</code> methods. These methods correspond
to a less widely used part of the HTTP protocol, which is meant to
provide a way to upload and remove files or file-like entities. <code class="literal">doPut()</code> is supposed to be like <code class="literal">POST</code> but with slightly different semantics (a
<code class="literal">PUT</code> is supposed to logically replace
the item identified by the URL, whereas <code class="literal">POST</code> presents data to it); <a id="I_indexterm15_id776908" class="indexterm"/><code class="literal">doDelete()</code> would be its
opposite.</p><p><code class="literal">HttpServlet</code> also implements
three other HTTP-related methods for you: <a id="I_indexterm15_id776926" class="indexterm"/><code class="literal">doHead()</code>, <a id="I_indexterm15_id776936" class="indexterm"/><code class="literal">doTrace()</code>, and
<a id="I_indexterm15_id776947" class="indexterm"/><code class="literal">doOptions()</code>. You don’t
normally need to override these methods. <code class="literal">doHead()</code> implements the HTTP <code class="literal">HEAD</code> request, which asks for the headers of a
<code class="literal">GET</code> request without the body.
<code class="literal">HttpServlet</code> implements this by
default in the trivial way, by performing the <code class="literal">GET</code> method and then sending only the headers.
You may wish to override <code class="literal">doHead()</code>
with a more efficient implementation if you can provide one as an
optimization. <code class="literal">doTrace()</code> and <code class="literal">doOptions()</code> implement other features of HTTP
that allow for debugging and simple client/server capabilities
negotiation. You shouldn’t normally need to override these.</p><p>Along with <code class="literal">HttpServlet</code>,
<code class="literal">javax.servlet.http</code> also includes
subclasses of the objects <a id="I_indexterm15_id777020" class="indexterm"/><code class="literal">ServletRequest</code> and
<a id="I_indexterm15_id777031" class="indexterm"/><code class="literal">ServletResponse</code>,
<a id="I_indexterm15_id777042" class="indexterm"/><code class="literal">HttpServletRequest</code> and
<a id="I_indexterm15_id777053" class="indexterm"/><code class="literal">HttpServletResponse</code>.
These subclasses provide, respectively, the input and output streams
needed to read and write client data. They also provide the APIs for
getting or setting HTTP header information and, as we’ll see, client
session information. Rather than document these dryly, we’ll show them
in the context of some examples. As usual, we’ll start with the simplest
possible example.</p></div><div class="sect2" title="The HelloClient Servlet"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-15-SECT-2.3"/>The HelloClient Servlet</h2></div></div></div><p><a id="idx10888" class="indexterm"/>Here’s our servlet version of “Hello, World,” <code class="literal">HelloClient</code>:</p><a id="I_15_tt915"/><pre class="programlisting"><code class="nd">@WebServlet</code><code class="o">(</code><code class="n">urlPatterns</code><code class="o">={</code><code class="s">"/hello"</code><code class="o">})</code>
<code class="kd">public</code> <code class="kd">class</code> <code class="nc">HelloClient</code> <code class="kd">extends</code> <code class="n">HttpServlet</code>
<code class="o">{</code>
<code class="kd">public</code> <code class="kt">void</code> <code class="nf">doGet</code><code class="o">(</code><code class="n">HttpServletRequest</code> <code class="n">request</code><code class="o">,</code> <code class="n">HttpServletResponse</code> <code class="n">response</code><code class="o">)</code>
<code class="kd">throws</code> <code class="n">ServletException</code><code class="o">,</code> <code class="n">IOException</code>
<code class="o">{</code>
<code class="n">response</code><code class="o">.</code><code class="na">setContentType</code><code class="o">(</code><code class="s">"text/html"</code><code class="o">);</code> <code class="c1">// must come first</code>
<code class="n">PrintWriter</code> <code class="n">out</code> <code class="o">=</code> <code class="n">response</code><code class="o">.</code><code class="na">getWriter</code><code class="o">();</code>
<code class="n">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code>
<code class="s">"<html><head><title>Hello Client!</title></head><body>"</code>
<code class="o">+</code> <code class="s">"<h1>Hello Client!</h1>"</code>
<code class="o">+</code> <code class="s">"</body></html>"</code> <code class="o">);</code>
<code class="o">}</code>
<code class="o">}</code></pre><p>If you want to try this servlet right away, skip ahead to <a class="xref" href="ch15s03.html" title="WAR Files and Deployment">WAR Files and Deployment</a>, where we walk through the process
of deploying this servlet. Because we’ve included the <a id="I_indexterm15_id777122" class="indexterm"/><code class="literal">WebServlet</code> annotation
in our class, this servlet does not need a <em class="filename">web.xml</em> file for deployment. All you have to
do is bundle the class file into a particular folder within a WAR
archive (a fancy ZIP file) and drop it into a directory monitored by the
Tomcat server. For now, we’re going to focus on just the servlet example
code itself, which is pretty simple in this case.</p><p>Let’s have a look at the example. <code class="literal">HelloClient</code> extends the base <code class="literal">HttpServlet</code> class and overrides the <code class="literal">doGet()</code> method to handle simple requests. In
this case, we want to respond to any <code class="literal">GET</code> request by sending back a one-line HTML
document that says “Hello Client!” First, we tell the container what
kind of response we are going to generate, using the <a id="I_indexterm15_id777175" class="indexterm"/><code class="literal">setContentType()</code> method
of the <code class="literal">HttpServletResponse</code> object. We
specify the MIME type “text/html” for our HTML response. Then, we get
the output stream using the <code class="literal">getWriter()</code> method and print the message to
it. It is not necessary for us to explicitly close the stream. We’ll
talk more about managing the output stream throughout this
chapter.</p><div class="sect3" title="ServletExceptions"><div class="titlepage"><div><div><h3 class="title"><a id="learnjava3-CHP-15-SECT-2.3.1"/>ServletExceptions</h3></div></div></div><p><a id="I_indexterm15_id777210" class="indexterm"/> <a id="I_indexterm15_id777219" class="indexterm"/>The <a id="I_indexterm15_id777230" class="indexterm"/><code class="literal">doGet()</code> method of our example servlet
declares that it can throw a <a id="I_indexterm15_id777243" class="indexterm"/><code class="literal">ServletException</code>. All
of the service methods of the Servlet API may throw a <code class="literal">ServletException</code> to indicate that a request
has failed. A <code class="literal">ServletException</code> can
be constructed with a string message and an optional <code class="literal">Throwable</code> parameter that can carry any
corresponding exception representing the root cause of the
problem:</p><a id="I_15_tt916"/><pre class="programlisting"> <code class="k">throw</code> <code class="k">new</code> <code class="nf">ServletException</code><code class="o">(</code><code class="s">"utter failure"</code><code class="o">,</code> <code class="n">someException</code> <code class="o">);</code></pre><p>By default, the web server determines exactly what is shown to
the user whenever a <code class="literal">ServletException</code> is thrown; often there
is a “development mode” where the exception and its stack trace are
displayed. Using the <em class="filename">web.xml</em>
file, you can designate custom error pages. (See the section <a class="xref" href="ch15s03.html#learnjava3-CHP-15-SECT-3.4" title="Error and Index Pages">Error and Index Pages</a> for details.)</p><p>Alternatively, a servlet may throw an <a id="I_indexterm15_id777307" class="indexterm"/><code class="literal">UnavailableException</code>,
a subclass of <code class="literal">ServletException</code>, to
indicate that it cannot handle requests. This exception can be thrown
to indicate that the condition is permanent or that it should last for
a specified period of seconds.</p></div><div class="sect3" title="Content type"><div class="titlepage"><div><div><h3 class="title"><a id="learnjava3-CHP-15-SECT-2.3.2"/>Content type</h3></div></div></div><p><a id="I_indexterm15_id777333" class="indexterm"/> <a id="I_indexterm15_id777339" class="indexterm"/> <a id="I_indexterm15_id777348" class="indexterm"/>Before fetching the output stream and writing to it, we
must specify the kind of output we are sending by calling the <code class="literal">response</code> parameter’s <a id="I_indexterm15_id777365" class="indexterm"/><code class="literal">setContentType()</code>
method. In this case, we set the content type to <code class="literal">text/html</code>, which is the proper MIME type for
an HTML document. In general, though, it’s possible for a servlet to
generate any kind of data, including audio, video, or some other kind
of text or binary document. If we were writing a generic <code class="literal">FileServlet</code> to serve files like a regular
web server, we might inspect the filename extension and determine the
MIME type from that or from direct inspection of the data. (This is a
good use for the <code class="literal">java.nio.file.Files
probeConentType()</code> method!) For writing binary data, you can
use the <a id="I_indexterm15_id777400" class="indexterm"/><code class="literal">getOutputStream()</code>
method to get an <a id="I_indexterm15_id777411" class="indexterm"/><code class="literal">OutputStream</code> as
opposed to a <code class="literal">Writer</code>.</p><p>The content type is used in the <code class="literal">Content-Type:</code> header of the server’s HTTP
response, which tells the client what to expect even before it starts
reading the result. This allows your web browser to prompt you with
the “Save File” dialog when you click on a ZIP archive or executable
program. When the content-type string is used in its full form to
specify the character encoding (for example, <code class="literal">text/html; charset=ISO-8859-1</code>), the
information is also used by the servlet engine to set the character
encoding of the <code class="literal">PrintWriter</code> output
stream. As a result, you should always call the <code class="literal">setContentType()</code> method before fetching the
writer with the <code class="literal">getWriter()</code> method.
The character encoding can also be set separately via the servlet
response <code class="literal">setCharacterEncoding()</code>
method.<a id="I_indexterm15_id777471" class="indexterm"/></p></div></div><div class="sect2" title="The Servlet Response"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-15-SECT-2.4"/>The Servlet Response</h2></div></div></div><p><a id="idx10861" class="indexterm"/> <a id="idx10891" class="indexterm"/>In addition to providing the output stream for writing
content to the client, the <a id="I_indexterm15_id777513" class="indexterm"/><code class="literal">HttpServletResponse</code>
object provides methods for controlling other aspects of the HTTP
response, including headers, error result codes, redirects, and servlet
container buffering.</p><p>HTTP headers are metadata name/value pairs sent with the response.
You can add headers (standard or custom) to the response with the
<a id="I_indexterm15_id777529" class="indexterm"/><code class="literal">setHeader()</code> and
<a id="I_indexterm15_id777540" class="indexterm"/><code class="literal">addHeader()</code> methods
(headers may have multiple values). There are also convenience methods
for setting headers with integer and date values:</p><a id="I_15_tt917"/><pre class="programlisting"> <code class="n">response</code><code class="o">.</code><code class="na">setIntHeader</code><code class="o">(</code><code class="s">"MagicNumber"</code><code class="o">,</code> <code class="mi">42</code><code class="o">);</code>
<code class="n">response</code><code class="o">.</code><code class="na">setDateHeader</code><code class="o">(</code><code class="s">"CurrentTime"</code><code class="o">,</code> <code class="n">System</code><code class="o">.</code><code class="na">currentTimeMillis</code><code class="o">()</code> <code class="o">);</code></pre><p>When you write data to the client, the servlet container
automatically sets the HTTP response code to a value of 200, which means
OK. Using the <a id="I_indexterm15_id777565" class="indexterm"/><code class="literal">sendError()</code> method, you
can generate other HTTP response codes. <code class="literal">HttpServletResponse</code> contains predefined
constants for all of the standard codes. Here are a few common
ones:</p><a id="I_15_tt918"/><pre class="programlisting"> <code class="n">HttpServletResponse</code><code class="o">.</code><code class="na">SC_OK</code>
<code class="n">HttpServletResponse</code><code class="o">.</code><code class="na">SC_BAD_REQUEST</code>
<code class="n">HttpServletResponse</code><code class="o">.</code><code class="na">SC_FORBIDDEN</code>
<code class="n">HttpServletResponse</code><code class="o">.</code><code class="na">SC_NOT_FOUND</code>
<code class="n">HttpServletResponse</code><code class="o">.</code><code class="na">SC_INTERNAL_SERVER_ERROR</code>
<code class="n">HttpServletResponse</code><code class="o">.</code><code class="na">SC_NOT_IMPLEMENTED</code>
<code class="n">HttpServletResponse</code><code class="o">.</code><code class="na">SC_SERVICE_UNAVAILABLE</code></pre><p>When you generate an error with <code class="literal">sendError()</code>, the response is over and you
can’t write any actual content to the client. You can specify a short
error message, however, which may be shown to the client. (See the
section <a class="xref" href="ch15s04.html#learnjava3-CHP-15-SECT-4.1" title="A Simple Filter">A Simple Filter</a>.)</p><p>An HTTP redirect is a special kind of response that tells the
client web browser to go to a different URL. Normally this happens
quickly and without any interaction from the user. You can send a
redirect with the <a id="I_indexterm15_id777613" class="indexterm"/><code class="literal">sendRedirect()</code>
method:</p><a id="I_15_tt919"/><pre class="programlisting"> <code class="n">response</code><code class="o">.</code><code class="na">sendRedirect</code><code class="o">(</code><code class="s">"http://www.oreilly.com/"</code><code class="o">);</code></pre><p>While we’re talking about the response, we should say a few words
about buffering. Most responses are buffered internally by the servlet
container until the servlet service method has exited or a preset
maximum size has been reached. This allows the container to set the HTTP
content-length header automatically, telling the client how much data to
expect. You can control the size of this buffer with the <a id="I_indexterm15_id777640" class="indexterm"/><code class="literal">setBufferSize()</code> method,
specifying a size in bytes. You can even clear it and start over if no
data has been written to the client. To clear the buffer, use <code class="literal">isCommitted()</code> to test whether any data has
been set, then use <a id="I_indexterm15_id777658" class="indexterm"/><code class="literal">resetBuffer()</code> to dump
the data if none has been sent. If you are sending a lot of data, you may wish to set the content
length explicitly with the <a id="I_indexterm15_id777674" class="indexterm"/><code class="literal">setContent</code><code class="literal">Length()</code>
method.<a id="I_indexterm15_id777692" class="indexterm"/></p></div><div class="sect2" title="Servlet Parameters"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-15-SECT-2.5"/>Servlet Parameters</h2></div></div></div><p><a id="idx10860" class="indexterm"/> <a id="idx10890" class="indexterm"/>Our first example showed how to accept a basic request. Of
course, to do anything really useful, we’ll need to get some information
from the client. Fortunately, the servlet engine handles this for us,
interpreting both <code class="literal">GET</code> and <code class="literal">POST</code> form-encoded data from the client and
providing it to us through the simple <code class="literal">getParameter()</code> method of the servlet
request.</p><div class="sect3" title="GET, POST, and “extra path”"><div class="titlepage"><div><div><h3 class="title"><a id="learnjava3-CHP-15-SECT-2.5.1"/>GET, POST, and “extra path”</h3></div></div></div><p><a id="I_indexterm15_id777762" class="indexterm"/> <a id="I_indexterm15_id777768" class="indexterm"/> <a id="I_indexterm15_id777775" class="indexterm"/>There are two common ways to pass information from your
web browser to a servlet or CGI program. The most general is to “post”
it, meaning that your client encodes the information and sends it as a
stream to the program, which decodes it. Posting can be used to upload
large amounts of form data or other data, including files. The other
way to pass information is to somehow encode the information in the
URL of your client’s request. The primary way to do this is to use
<code class="literal">GET</code>-style encoding of parameters in
the URL string. In this case, the web browser encodes the parameters
and appends them to the end of the URL string. The server decodes them
and passes them to the application.</p><p>As we described in <a class="xref" href="ch14.html" title="Chapter 14. Programming for the Web">Chapter 14</a>,
<code class="literal">GET</code>-style encoding takes the
parameters and appends them to the URL in a name/value fashion, with
the first parameter preceded by a question mark (?) and the rest
separated by ampersands (&). The entire string is expected to be
<span class="emphasis"><em>URL-encoded</em></span>: any special characters (such as
spaces, ?, and & in the string) are specially encoded.</p><p>Another way to pass data in the URL is called <span class="emphasis"><em>extra
path</em></span>. This simply means that when the server has located
your servlet or CGI program as the target of a URL, it takes any
remaining path components of the URL string and hands them over as an
extra part of the URL. For example, consider these URLs:</p><a id="I_15_tt920"/><pre class="programlisting"> <code class="nl">http:</code><code class="c1">//www.myserver.example/servlets/MyServlet</code>
<code class="nl">http:</code><code class="c1">//www.myserver.example/servlets/MyServlet/foo/bar</code></pre><p>Suppose the server maps the first URL to the servlet called
<code class="literal">MyServlet</code>. When given the second
URL, the server also invokes <code class="literal">MyServlet</code>, but considers <code class="literal">/foo/bar</code> to be “extra path” that can be
retrieved through the servlet request <code class="literal">getExtraPath()</code> method. This technique is
useful for making more human-readable and meaningful URL pathnames,
especially for document-centric content.</p><p>Both <code class="literal">GET</code> and <code class="literal">POST</code> encoding can be used with HTML forms on
the client by specifying <code class="literal">get</code> or
<code class="literal">post</code> in the <code class="literal">action</code> attribute of the form tag. The
browser handles the encoding; on the server side, the servlet engine
handles the decoding.</p><p>The content type used by a client to post form data to a servlet
is: “application/x-www-form-urlencoded.” The Servlet API automatically
parses this kind of data and makes it available through the <a id="I_indexterm15_id777897" class="indexterm"/><code class="literal">getParameter()</code>
method. However, if you do not call the <code class="literal">getParameter()</code> method, the data remains
available, unparsed, in the input stream and can be read by the
servlet directly.</p></div><div class="sect3" title="GET or POST: Which one to use?"><div class="titlepage"><div><div><h3 class="title"><a id="learnjava3-CHP-15-SECT-2.5.2"/>GET or POST: Which one to use?</h3></div></div></div><p>To users, the primary difference between <code class="literal">GET</code> and <code class="literal">POST</code> is that they can see the <code class="literal">GET</code> information in the encoded URL shown in
their web browser. This can be useful because the user can cut and
paste that URL (the result of a search, for example) and mail it to a
friend or bookmark it for future reference. <code class="literal">POST</code> information is not visible to the user
and ceases to exist after it’s sent to the server. This behavior goes
along with the protocol’s intent that <code class="literal">GET</code> and <code class="literal">POST</code> are to have different semantics. By
definition, the result of a <code class="literal">GET</code>
operation is not supposed to have any side effects; that is, it’s not
supposed to cause the server to perform any persistent operations
(such as making a purchase in a shopping cart). In theory, that’s the
job of <code class="literal">POST</code>. That’s why your web
browser warns you about reposting form data again if you hit reload on
a page that was the result of a form posting.</p><p>The extra path style would be useful for a servlet that
retrieves files or handles a range of URLs in a human-readable way.
Extra path information is often useful for URLs that the user must see
or remember, because it looks like any other path.<a id="I_indexterm15_id777982" class="indexterm"/><a id="I_indexterm15_id777989" class="indexterm"/></p></div></div><div class="sect2" title="The ShowParameters Servlet"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-15-SECT-2.6"/>The ShowParameters Servlet</h2></div></div></div><p><a id="idx10869" class="indexterm"/> <a id="idx10871" class="indexterm"/> <a id="idx10895" class="indexterm"/>Our first example didn’t do much. This next example prints
the values of any parameters that were received. We’ll start by handling
<code class="literal">GET</code> requests and then make some
trivial modifications to handle <code class="literal">POST</code>
as well. Here’s the code:</p><a id="I_15_tt921"/><pre class="programlisting"><code class="kn">import</code> <code class="nn">java.io.*</code><code class="o">;</code>
<code class="kn">import</code> <code class="nn">javax.servlet.http.*</code><code class="o">;</code>
<code class="kn">import</code> <code class="nn">java.util.*</code><code class="o">;</code>
<code class="kd">public</code> <code class="kd">class</code> <code class="nc">ShowParameters</code> <code class="kd">extends</code> <code class="n">HttpServlet</code>
<code class="o">{</code>
<code class="kd">public</code> <code class="kt">void</code> <code class="nf">doGet</code><code class="o">(</code><code class="n">HttpServletRequest</code> <code class="n">request</code><code class="o">,</code> <code class="n">HttpServletResponse</code> <code class="n">response</code><code class="o">)</code>
<code class="kd">throws</code> <code class="n">IOException</code>
<code class="o">{</code>
<code class="n">showRequestParameters</code><code class="o">(</code> <code class="n">request</code><code class="o">,</code> <code class="n">response</code> <code class="o">);</code>
<code class="o">}</code>
<code class="kt">void</code> <code class="nf">showRequestParameters</code><code class="o">(</code><code class="n">HttpServletRequest</code> <code class="n">request</code><code class="o">,</code>
<code class="n">HttpServletResponse</code> <code class="n">response</code><code class="o">)</code>
<code class="kd">throws</code> <code class="n">IOException</code>
<code class="o">{</code>
<code class="n">response</code><code class="o">.</code><code class="na">setContentType</code><code class="o">(</code><code class="s">"text/html"</code><code class="o">);</code>
<code class="n">PrintWriter</code> <code class="n">out</code> <code class="o">=</code> <code class="n">response</code><code class="o">.</code><code class="na">getWriter</code><code class="o">();</code>
<code class="n">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code>
<code class="s">"<html><head><title>Show Parameters</title></head><body>"</code>
<code class="o">+</code> <code class="s">"<h1>Parameters</h1><ul>"</code><code class="o">);</code>
<code class="n">Map</code><code class="o"><</code><code class="n">String</code><code class="o">,</code> <code class="n">String</code><code class="o">[]></code> <code class="n">params</code> <code class="o">=</code> <code class="n">request</code><code class="o">.</code><code class="na">getParameterMap</code><code class="o">();</code>
<code class="k">for</code> <code class="o">(</code> <code class="n">String</code> <code class="n">name</code> <code class="o">:</code> <code class="n">params</code><code class="o">.</code><code class="na">keySet</code><code class="o">()</code> <code class="o">)</code>
<code class="o">{</code>
<code class="n">String</code> <code class="o">[]</code> <code class="n">values</code> <code class="o">=</code> <code class="n">params</code><code class="o">.</code><code class="na">get</code><code class="o">(</code> <code class="n">name</code> <code class="o">);</code>
<code class="n">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code><code class="s">"<li>"</code><code class="o">+</code> <code class="n">name</code> <code class="o">+</code><code class="s">" = "</code><code class="o">+</code> <code class="n">Arrays</code><code class="o">.</code><code class="na">asList</code><code class="o">(</code><code class="n">values</code><code class="o">)</code> <code class="o">);</code>
<code class="o">}</code>
<code class="n">out</code><code class="o">.</code><code class="na">close</code><code class="o">(</code> <code class="o">);</code>
<code class="o">}</code>
<code class="o">}</code></pre><p>As in the first example, we override the <a id="I_indexterm15_id778076" class="indexterm"/><code class="literal">doGet()</code> method. We
delegate the request to a helper method that we’ve created, called
<code class="literal">showRequestParameters()</code>, a method
that enumerates the parameters using the request object’s <a id="I_indexterm15_id778095" class="indexterm"/><code class="literal">getParameterMap()</code>
method, which returns a map of parameter name to values, and prints the
names and values. Note that a parameter may have multiple values if it
is repeated in the request from the client, hence the map contains
<code class="literal">String []</code>. To make thing pretty, we
listed each parameter in HTML with <code class="literal"><li></code> tag.</p><p>As it stands, our servlet would respond to any URL that contains a
<code class="literal">GET</code> request. Let’s round it out by
adding our own form to the output and also accommodating <code class="literal">POST</code> method requests. To accept posts, we
override the <a id="I_indexterm15_id778136" class="indexterm"/><code class="literal">doPost()</code> method. The
implementation of <code class="literal">doPost()</code> could
simply call our <code class="literal">showRequestParameters()</code> method, but we can
make it simpler still. The API lets us treat <code class="literal">GET</code> and <code class="literal">POST</code> requests interchangeably because the
servlet engine handles the decoding of request parameters. So we simply
delegate the <code class="literal">doPost()</code> operation to
<code class="literal">doGet()</code>.</p><p>Add the following method to the example:</p><a id="I_15_tt922"/><pre class="programlisting"> <code class="kd">public</code> <code class="kt">void</code> <code class="nf">doPost</code><code class="o">(</code> <code class="n">HttpServletRequest</code> <code class="n">request</code><code class="o">,</code> <code class="n">HttpServletResponse</code> <code class="n">response</code><code class="o">)</code>
<code class="kd">throws</code> <code class="n">ServletException</code><code class="o">,</code> <code class="n">IOException</code>
<code class="o">{</code>
<code class="n">doGet</code><code class="o">(</code> <code class="n">request</code><code class="o">,</code> <code class="n">response</code> <code class="o">);</code>
<code class="o">}</code></pre><p>Now, let’s add an HTML form to the output. The form lets the user
fill in some parameters and submit them to the servlet. Add this line to
the <a id="I_indexterm15_id778198" class="indexterm"/><code class="literal">showRequestParameters()</code>
method before the call to <code class="literal">out.close()</code>:</p><a id="I_15_tt923"/><pre class="programlisting"> <code class="n">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code><code class="s">"</ul><p><form method=\"POST\" action=\""</code>
<code class="o">+</code> <code class="n">request</code><code class="o">.</code><code class="na">getRequestURI</code><code class="o">()</code> <code class="o">+</code> <code class="s">"\">"</code>
<code class="o">+</code> <code class="s">"Field 1 <input name=\"Field 1\" size=20><br>"</code>
<code class="o">+</code> <code class="s">"Field 2 <input name=\"Field 2\" size=20><br>"</code>
<code class="o">+</code> <code class="s">"<br><input type=\"submit\" value=\"Submit\"></form>"</code>
<code class="o">);</code></pre><p>The form’s <code class="literal">action</code> attribute is
the URL of our servlet so that our servlet will get the data back. We
use the <a id="I_indexterm15_id778235" class="indexterm"/><code class="literal">getRequestURI()</code> method
to get the location of our servlet. For the <code class="literal">method</code> attribute, we’ve specified a <code class="literal">POST</code> operation, but you can try changing the
operation to <code class="literal">GET</code> to see both
styles.</p><p>So far, we haven’t done anything terribly exciting. In the next
example, we’ll add some power by introducing a user session to store
client data between requests. But before we go on, we should mention a
useful standard servlet, <code class="literal">SnoopServlet</code>, that is akin to our previous
example.<a id="I_indexterm15_id778276" class="indexterm"/><a id="I_indexterm15_id778283" class="indexterm"/><a id="I_indexterm15_id778290" class="indexterm"/></p></div><div class="sect2" title="User Session Management"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-15-SECT-2.7"/>User Session Management</h2></div></div></div><p><a id="I_indexterm15_id778304" class="indexterm"/> <a id="I_indexterm15_id778311" class="indexterm"/>One of the nicest features of the Servlet API is its
simple mechanism for managing a user session. By a session, we mean that
the servlet can maintain information over multiple pages and through
multiple transactions as navigated by the user; this is also called
maintaining state. Providing continuity through a series of web pages is
important in many kinds of applications, such as handling a login
process or tracking purchases in a shopping cart. In a sense, session
data takes the place of instance data in your servlet object. It lets
you store data between invocations of your service methods.</p><p>Session tracking is supported by the servlet container; you
normally don’t have to worry about the details of how it’s accomplished.
It’s done in one of two ways: using client-side cookies or URL
rewriting. <span class="emphasis"><em>Client-side cookies</em></span> are a standard HTTP
mechanism for getting the client web browser to cooperate in storing
state information for you. A cookie is basically just a name/value
attribute that is issued by the server, stored on the client, and
returned by the client whenever it is accessing a certain group of URLs
on a specified server. Cookies can track a single session or multiple
user visits.</p><p><a id="I_indexterm15_id778340" class="indexterm"/> <span class="emphasis"><em>URL rewriting</em></span> appends
session-tracking information to the URL, using <code class="literal">GET</code>-style encoding or extra path information.
The term <span class="emphasis"><em>rewriting</em></span> applies because the server
rewrites the URL before it is seen by the client and absorbs the extra
information before it is passed back to the servlet. In order to support
URL rewriting, a servlet must take the extra step to encode any URLs it
generates in content (e.g., HTML links that may return to the page)
using a special method of the <code class="literal">HttpServletResponse</code> object. We’ll describe
this later. You need to allow for URL rewriting by the server if you
want your application to work with browsers that do not support cookies
or have them disabled. Many sites simply choose not to work without
cookies.</p><p>To the servlet programmer, state information is made available
through an <a id="I_indexterm15_id778375" class="indexterm"/><code class="literal">HttpSession</code> object,
which acts like a hashtable for storing any objects you would like to
carry through the session. The objects stay on the server side; a
special identifier is sent to the client through a cookie or URL
rewriting. On the way back, the identifier is mapped to a session, and
the session is associated with the servlet again.</p></div><div class="sect2" title="The ShowSession Servlet"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-15-SECT-2.8"/>The ShowSession Servlet</h2></div></div></div><p><a id="idx10870" class="indexterm"/> <a id="idx10896" class="indexterm"/>Here’s a simple servlet that shows how to store some
string information to track a session:</p><a id="I_15_tt924"/><pre class="programlisting"> <code class="kn">import</code> <code class="nn">java.io.*</code><code class="o">;</code>
<code class="kn">import</code> <code class="nn">javax.servlet.ServletException</code><code class="o">;</code>
<code class="kn">import</code> <code class="nn">javax.servlet.http.*</code><code class="o">;</code>
<code class="kn">import</code> <code class="nn">java.util.Enumeration</code><code class="o">;</code>
<code class="kd">public</code> <code class="kd">class</code> <code class="nc">ShowSession</code> <code class="kd">extends</code> <code class="n">HttpServlet</code> <code class="o">{</code>
<code class="kd">public</code> <code class="kt">void</code> <code class="nf">doPost</code><code class="o">(</code>
<code class="n">HttpServletRequest</code> <code class="n">request</code><code class="o">,</code> <code class="n">HttpServletResponse</code> <code class="n">response</code><code class="o">)</code>
<code class="kd">throws</code> <code class="n">ServletException</code><code class="o">,</code> <code class="n">IOException</code>
<code class="o">{</code>
<code class="n">doGet</code><code class="o">(</code> <code class="n">request</code><code class="o">,</code> <code class="n">response</code> <code class="o">);</code>
<code class="o">}</code>
<code class="kd">public</code> <code class="kt">void</code> <code class="nf">doGet</code><code class="o">(</code>
<code class="n">HttpServletRequest</code> <code class="n">request</code><code class="o">,</code> <code class="n">HttpServletResponse</code> <code class="n">response</code><code class="o">)</code>
<code class="kd">throws</code> <code class="n">ServletException</code><code class="o">,</code> <code class="n">IOException</code>
<code class="o">{</code>
<code class="n">HttpSession</code> <code class="n">session</code> <code class="o">=</code> <code class="n">request</code><code class="o">.</code><code class="na">getSession</code><code class="o">();</code>
<code class="kt">boolean</code> <code class="n">clear</code> <code class="o">=</code> <code class="n">request</code><code class="o">.</code><code class="na">getParameter</code><code class="o">(</code><code class="s">"clear"</code><code class="o">)</code> <code class="o">!=</code> <code class="kc">null</code><code class="o">;</code>
<code class="k">if</code> <code class="o">(</code> <code class="n">clear</code> <code class="o">)</code>
<code class="n">session</code><code class="o">.</code><code class="na">invalidate</code><code class="o">();</code>
<code class="k">else</code> <code class="o">{</code>
<code class="n">String</code> <code class="n">name</code> <code class="o">=</code> <code class="n">request</code><code class="o">.</code><code class="na">getParameter</code><code class="o">(</code><code class="s">"Name"</code><code class="o">);</code>
<code class="n">String</code> <code class="n">value</code> <code class="o">=</code> <code class="n">request</code><code class="o">.</code><code class="na">getParameter</code><code class="o">(</code><code class="s">"Value"</code><code class="o">);</code>
<code class="k">if</code> <code class="o">(</code> <code class="n">name</code> <code class="o">!=</code> <code class="kc">null</code> <code class="o">&&</code> <code class="n">value</code> <code class="o">!=</code> <code class="kc">null</code> <code class="o">)</code>
<code class="n">session</code><code class="o">.</code><code class="na">setAttribute</code><code class="o">(</code> <code class="n">name</code><code class="o">,</code> <code class="n">value</code> <code class="o">);</code>
<code class="o">}</code>
<code class="n">response</code><code class="o">.</code><code class="na">setContentType</code><code class="o">(</code><code class="s">"text/html"</code><code class="o">);</code>
<code class="n">PrintWriter</code> <code class="n">out</code> <code class="o">=</code> <code class="n">response</code><code class="o">.</code><code class="na">getWriter</code><code class="o">();</code>
<code class="n">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code>
<code class="s">"<html><head><title>Show Session</title></head><