Chapter 2. Servlet Development and Deployment

In this chapter, we will discuss how to develop and deploy Java servlets. Some of the topics covered are:

  • An explanation of what servlets are

  • Developing, configuring, packaging and deploying our first servlet

  • HTML form processing

  • Forwarding HTTP requests

  • Redirecting HTTP responses

  • Persisting data across HTTP requests

What is a Servlet? A servlet is a Java class that is used to extend the capabilities of servers that host applications. Servlets can respond to requests and generate responses. The base class for all servlets is javax.servlet.GenericServlet, this class defines a generic, protocol-independent servlet.

By far, the most common type of servlet is an HTTP servlet; this type of servlet is used in handling HTTP requests and generating HTTP responses. An HTTP servlet is a class that extends the javax.servlet.http.HttpServlet class, which is a subclass of javax.servlet.GenericServlet.

A servlet must implement one or more methods to respond to specific HTTP requests. These methods are overridden from the parent HttpServlet class. As can be seen in the following table, these methods are named so that knowing which one to use is intuitive.

HTTP Request

HttpServlet Method

GET

doGet(HttpServletRequest request, HttpServletResponse response)

POST

doPost(HttpServletRequest request, HttpServletResponse response)

PUT

doPut(HttpServletRequest request, HttpServletResponse response)

DELETE

doDelete(HttpServletRequest request, HttpServletResponse response)

Each of these methods take the same two parameters, namely an instance of a class implementing the javax.servlet.http.HttpServletRequest interface and an instance of a class implementing the javax.servlet.http.HttpServletResponse. These interfaces will be covered in detail, later in this chapter.

Note

Application developers never call the above methods directly; they are called automatically by the application server whenever it receives the corresponding HTTP request.

Of the four methods listed above, doGet() and doPost() are, by far, the most commonly used.

An HTTP GET request is generated whenever a user types the servlet's URL in the browser, when a user clicks on a link pointing to the servlet's URL, or when a user submits an HTML form using the GET method that has an action pointing to the servlet's URL. In any of these cases, the code inside the servlet's doGet() method gets executed.

An HTTP POST request is typically generated when a user submits an HTML form using the POST method and an action pointing to the servlet's URL. In this case, the servlet's code inside the doPost() method gets executed.

Writing Our First Servlet

In chapter 1, we deployed a simple application that printed a message on the browser window. That application basically consisted of a single servlet. In this section, we will see how that servlet was developed, configured, and packaged.

The code for the servlet is as follows:

package net.ensode.glassfishbook.simpleapp;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class SimpleServlet extends HttpServlet
{
protected void doGet(HttpServletRequest request, HttpServletResponse response)
{
try
{
response.setContentType("text/html");
PrintWriter printWriter = response.getWriter();
printWriter.println("<h2>");
printWriter
.println("If you are reading this, your application server is good to go!");
printWriter.println("</h2>");
}
catch (IOException ioException)
{
ioException.printStackTrace();
}
}
}

As this servlet is meant to execute when a user enters its URL in the browser window, we need to override the doGet() method from the parent HttpServlet class. As we explained, this method takes two parameters: an instance of a class implementing the javax.servlet.http.HttpServletRequest interface, and an instance of a class implementing the javax.servlet.http.HttpServletResponse interface.

Even though HttpServletRequest and HttpServletResponse are interfaces, application developers don't typically write classes implementing them. When control goes to a servlet from an HTTP request, the application server (GlassFish, in our case) provides objects implementing these interfaces.

The first thing our doGet() method does is to set the content type for the HttpServletResponse object to "text/html". If we forget to do this, the default content type used is "text/plain", which means that the HTML tags used a couple of lines down will be displayed on the browser, as opposed to them being interpreted as HTML tags.

Then we obtain an instance of java.io.PrintWriter by calling the HttpServletResponse.getWriter() method. We can then send text output to the browser by calling the PrintWriter.print() and PrintWriter.println() methods (the previous example uses println() exclusively). As we set the content type to "text/html", any HTML tags are interpreted properly by the browser.

Compiling the Servlet

To compile the servlet, the Java library included with GlassFish must be in the CLASSPATH. This library is called javaee.jar, it can be found under [glassfish installation directory]/glassfish/lib.

To compile from the command line using the javac compiler, a command like the following must be issued (all in one line):

javac -cp /opt/glassfish/lib/javaee.jar:. net/ensode/glassfishbook/simpleapp/SimpleServlet.java

Of course, these days very few developers compile code with the "raw" javac compiler; instead, either a graphical IDE or a command line build tool like Apache ANT or Apache Maven is used. Consult your IDE or build tool documentation for information on how to add the javaee.jar library to its CLASSPATH.

Note

Maven

Apache Maven is a build tool similar to ANT. However, Maven offers a number of advantages over ANT including automatic download of dependencies and standard commands for compilation and packaging of applications. Maven was the build tool used to compile and package most of the examples in this book, therefore it is recommended to have Maven installed in order to easily build the examples.

When using Maven, the code can be compiled and packaged by issuing the following command at the project's root directory (simpleapp in this case): mvn package.

Maven can be downloaded from http://maven.apache.org/.

Configuring the Servlet

Before we can deploy our servlet, we need to configure it. All Java EE web applications are configured via an XML deployment descriptor named web.xml. The web.xml deployment descriptor for our servlet is as follows:

<?xml version="1.0" encoding="UTF-8"?>
"<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5"
xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=" http://java.sun.com/xml/ns/ javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">"
<servlet>
<servlet-name>SimpleServlet</servlet-name>
<servlet-class>
net.ensode.glassfishbook.simpleapp.SimpleServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SimpleServlet</servlet-name>
<url-pattern>/simpleservlet</url-pattern>
</servlet-mapping>
</web-app>

The first few lines are boilerplate XML stating the XML version and encoding, plus the schema used for the XML file and other information. It is safe to just copy and paste these lines and reuse them across applications. The<servlet> and<servlet-mapping> XML tags above are used to actually configure our servlet.

The<servlet> tag contains two nested tags.<servlet-name> defines a logical name for the servlet, and<servlet-class> indicates the Java class defining the servlet.

The<servlet-mapping> tag also contains two nested tags:<servlet-name>, which must match the value set inside the<servlet> tag and<url-pattern>, which sets the URL pattern for which the servlet will execute.

<url-pattern> can be specified in one of two ways, by using a path prefix (which is what the example above does), or by specifying an extension suffix.

Path prefix values for<url-pattern> indicate that any URL paths starting with the given path will be serviced by the corresponding servlet. Path prefix values must start with a forward slash.

Note

Java EE web applications run from within a context root. The context root is the first string in the URL that is not the server name or IP address, nor the port. For example, in the URL http://localhost:8080/simpleapp/simpleservlet, the string simpleapp is the context root. The value for<url-pattern> is relative to the application's context root.

Extension suffix values for<url-pattern> indicate that any URLs ending in the given suffix will be serviced by the corresponding servlet. In the above example, we chose to use a path prefix. Had we chosen to use an extension suffix, the<servlet-mapping> tag would have looked something like this:

<servlet-mapping>
<servlet>SimpleServlet</servlet>
<url-pattern>*.foo</url-pattern>
</servlet-mapping>

This would direct any URLs ending with the string .foo to our servlet.

The reason the<servlet-name> tag is specified twice (once inside the<servlet> tag and again inside the<servlet-mapping> tag) is because a Java EE 5 web application can have more than one servlet, each of which must have a<servlet> tag in the application's web.xml. The<servlet> tag for each must have a corresponding<servlet-mapping> tag, and the<servlet-name> nested tag is used to indicate which<servlet> tag corresponds to which<servlet-mapping> tag.

Note

A Java EE 5 web.xml file can contain many additional XML tags. However, these additional tags are not needed for this simple example. Additional tags will be discussed in future examples when they are needed.

Before we can execute our servlet, we need to package it as part of a web application in a WAR (Web ARchive) file.

Packaging the Web Application

All Java EE 5 web applications must be packaged in a WAR (Web ARchive) file before they can be deployed. A WAR file is nothing but a compressed file containing our code and configuration. WAR files can be created by any utility that can create files in ZIP format (for example, WinZip, 7-Zip, etc.). Also, many Java IDEs and build tools such as ANT and Maven automate WAR file creation.

A WAR file must contain the following directories (in addition to its root directory)

WEB-INF

WEB-INF/classes

WEB-INF/lib

The root directory contains JSPs (covered in the next chapter), HTML files, JavaScript files, and CSS files.

WEB-INF contains deployment descriptors such as web.xml.

WEB-INF/classes contains the compiled code (.class files) and may optionally contain property files. Just as with any Java classes, the directory structure must match the package structure, therefore this directory typically contains several subdirectories corresponding to the classes contained in it.

WEB-INF/lib contains JAR files containing any library dependencies our code might have.

The root directory, WEB-INF, and WEB-INF/classes directories can have sub directories. Any resources on a subdirectory of the root directory (other than WEB-INF) can be accessed by prepending the subdirectory name to its file name. For example, if there was a subdirectory called css containing a CSS file called style.css, this CSS file could be accessed in JSPs and HTML files in the root directory by the following line:

<link rel="stylesheet" type="text/css" media="screen" href="css/style.css" />

Notice the css prefix to the file name, corresponding to the directory where the CSS file resides.

To create our WAR file "from scratch", create the above directory structure in any directory in your system, then follow the following steps:

  1. Copy the web.xml file to WEB-INF.

  2. Create the following directory structure under WEB-INF/classes: net/ensode/glassfishbook/simpleapp.

  3. Copy SimpleServlet.class to the simpleapp directory from step 2.

  4. From the command line, issue the following command from the directory right above WEB-INF: jar cvf simpleapp.war.

You should now have a WAR file ready for deployment.

Note

When using Maven to build the code, the WAR file is automatically generated when issuing the mvn package command. The WAR file can be found under the target directory, it is named simpleapp.war.

Before we can execute our application, it needs to be deployed.

Deploying the Web Application

As we discussed in Chapter 1, there are several ways of deploying an application. The easiest and most straightforward way to deploy any Java EE application is to copy the deployment file (WAR file in this case) to the [glassfish installation directory]/glassfish/domains/domain1/autodeploy directory.

After copying the WAR file to the autodeploy directory, the system log should show a message similar to the following:

[#|2007-02-17T11:36:22.906-0500|INFO|sun-appserver9.1|javax.enterprise.system.tools.deployment|_ThreadID=12;_ThreadName=Timer-4;|deployed with moduleid = simpleapp|#]
[#|2007-02-17T11:36:23.424-0500|INFO|sun-appserver9.1|javax.enterprise.system.tools.deployment|_ThreadID=12;_ThreadName=Timer-4;|[AutoDeploy] Successfully autodeployed : /opt/glassfish/domains/domain1/autodeploy/simpleapp.war.|#]

Note

The system log can be found under [glassfish installation directory]/glassfish/domains/domain1/logs/server.log.

The last line should contain the string "Successfully autodeployed" indicating that our WAR file was deployed successfully.

Testing the Web Application

To verify that the servlet has been properly deployed, we need to point our browser to http://localhost:8080/simpleapp/simpleservlet; after doing so, we should see a page like the one shown in the following screenshot.

Testing the Web Application

Unsurprisingly, this is the same message as we saw when deploying the application in Chapter 1, as this is the same application as we deployed then.

Earlier in this chapter, we mentioned that URL paths for a Java EE 5 application are relative to their context root. The default context root for a WAR file is the name of the WAR file itself (minus the .war extension). As can be seen in the screenshot above, the context root for our application is simpleapp, which happens to match the name of the WAR file. This default can be changed by adding an additional configuration file to the WEB-INF directory of the WAR file. The name of this file must be sun-web.xml. An example sun-web.xml that will change the context root of our application from the default simpleapp to simple would look like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sun-web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Application Server 8.1 Servlet 2.4//EN" "http://www.sun.com/software/appserver/dtds/sun-web-app_2_4-1.dtd">
<sun-web-app>
<context-root>/simple</context-root>
</sun-web-app>

As can be seen in the above example, the context root for the application must be in the<context-root> tag of the sun-web.xml configuration file. After redeploying the simpleapp.war, directing the browser to http://localhost:8080/simple/simpleservlet will execute our servlet.

Note

The sun-web.xml file can contain a number of additional tags to configure several aspects of the application. Additional tags will be discussed in the relevant sections of this book.

Processing HTML Forms

Servlets are rarely accessed by typing their URL directly in the browser. The most common use for servlets is to process data entered by users in an HTML form. In this section, we illustrate this process.

Before digging into the servlet code and HTML markup, let's take a look at the web.xml file for this new application.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" 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">
<servlet>
<servlet-name>FormHandlerServlet</servlet-name>
<servlet-class>
net.ensode.glassfishbook.formhandling.FormHandlerServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FormHandlerServlet</servlet-name>
<url-pattern>/formhandlerservlet</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>dataentry.html</welcome-file>
</welcome-file-list></web-app>

The above web.xml file is very similar to the one we saw in the previous section; however, it contains an XML tag we haven't seen before, namely the<welcome-file> tag. The<welcome-file> tag determines what file to direct to when a user types a URL ending in the application's context root (for this example, the URL would be http://localhost:8080/formhandling, as we are naming our WAR file formhandling.war and not specifying a custom context root). We will name the HTML file containing the form dataentry.html; this will cause GlassFish to render it in the browser when the user types our application's URL and does not specify a file name.

Note

If no<welcome-file> is specified in the application's web.xml file, GlassFish will look for a file named index.html and use it as the welcome file. If it can't find it, it will look for a file named index.jsp and use it as a welcome file. If it can't find it either one, it will display a directory listing.

The HTML file containing the form for our application looks like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Data Entry Page</title>
</head>
<body>
<form method="post" action="formhandlerservlet"><table cellpadding="0" cellspacing="0" border="0">
<tr>
<td>Please enter some text:</td>
<td>
<input type="text" name="enteredValue" /></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="Submit"></td>
</tr>
</table>
</form>
</body>
</html>

Notice how the value for the form's action attribute matches the value of the servlet's<url-pattern> in the application's web.xml (minus the initial slash). As the value of the form's method attribute is "post", our servlet's doPost() method will be executed when the form is submitted.

Now let's take a look at our servlet's code:

package net.ensode.glassfishbook.formhandling;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class FormHandlerServlet extends HttpServlet
{
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
{
String enteredValue;
enteredValue = request.getParameter("enteredValue");
response.setContentType("text/html");
PrintWriter printWriter;
try
{
printWriter = response.getWriter();
printWriter.println("<p>");
printWriter.print("You entered: ");
printWriter.print(enteredValue);
printWriter.print("</p>");
}
catch (IOException e)
{
e.printStackTrace();
}
}
}

As can be seen in the above example, we obtain a reference to the value the user typed by calling the request.getParameter() method. This method takes a single String object as its sole parameter; the value of this string must match the name of the input field in the HTML file. In this case, the HTML file has a text field named "enteredValue":

<input type="text" name="enteredValue" />

Therefore the servlet has a corresponding line:

enteredValue = request.getParameter("enteredValue");

to obtain the text entered by the user and store it in the string variable named enteredValue (the name of the variable does not need to match the input field name, but naming it that way is good practice to make it easy to remember what value the variable is holding).

After packaging the preceding three files in a WAR file called formhandling.war, then deploying the WAR file, we can see the rendered dataentry.html file by entering the following URL in the browser: http://localhost:8080/formhandling.

Processing HTML Forms

After we enter "some text" in the text field and submit the form (either by hitting "enter" or clicking on the Submit button), we should see the output of the servlet.

Processing HTML Forms

The HttpServletRequest.getParameter() method can be used to obtain the value of any HTML input field that can only return one value (text boxes, text areas, single selects, radio buttons, hidden fields, etc.). The procedure to obtain any of these fields values is identical, in other words, the servlet doesn't care if the user typed in the value in a text field, selected it from a set of radio buttons, etc. As long as the input field's name matches the value passed to the getParameter() method, this code will work.

Note

When dealing with radio buttons, all related radio buttons must have the same name. Calling the HttpServletRequest.getParameter() method and passing the name of the radio buttons will return the value of the selected radio button.

Some HTML input fields like checkboxes and multiple select boxes allow the user to select more than one value. For these fields, instead of using the HttpServletRequest.getParameter() method, the HttpServletRequest.getParameterValues() method is used. This method also takes a string containing the input field's name as its only parameter, and returns an array of strings containing all the values that were selected by the user.

Let's add a second HTML file and a second servlet to our application to illustrate this case. The relevant sections of this HTML are shown below.

<form method="post" action="multiplevaluefieldhandlerservlet"><p>Please enter one or more options.</p>
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td><input name="options" type="checkbox" value="option1" />
Option 1</td>
</tr>
<tr>
<td><input name="options" type="checkbox" value="option2" />
Option 2</td>
</tr>
<tr>
<td><input name="options" type="checkbox" value="option3" />
Option 3</td>
</tr>
<tr>
<td><input type="submit" value="Submit" /></td>
<td></td>
</tr>
</table>
</form>

The new HTML file contains a simple form having three checkboxes and a submit button. Notice how every checkbox has the same value for its name attribute. As we mentioned before, any checkboxes that are clicked by the user will be sent to the servlet.

Let's now take a look at the servlet that will handle the above HTML form.

package net.ensode.glassfishbook.formhandling;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MultipleValueFieldHandlerServlet extends HttpServlet
{
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
{
String[] selectedOptions = request.getParameterValues("options");
response.setContentType("text/html");
try
{
PrintWriter printWriter = response.getWriter();
printWriter.println("<p>");
printWriter.print("The following options were selected:");
printWriter.println("<br/>");
if (selectedOptions != null)
{
for (String option : selectedOptions)
{
printWriter.print(option);
printWriter.println("<br/>");
}
}
else
{
printWriter.println("None");
}
printWriter.println("</p>");
}
catch (IOException e)
{
e.printStackTrace();
}
}
}

The above code calls the request.getParameterValues() method and assigns its return value to the selectedOptions variable. Farther down the doPost() method, the code traverses the selectedOptions array and prints the selected values in the browser.

Note

This code uses the enhanced for loop introduced in JDK 1.5. Refer to http://java.sun.com/j2se/1.5.0/docs/guide/language/foreach.html for more information.

If no checkboxes are clicked, the request.getParameterValues() method will return null; therefore it is a good idea to check for null before attempting to traverse through this method's return values.

Before this new servlet can be deployed, the following lines need to be added to the application's web.xml file:

<servlet>
<servlet-name>MultipleValueFieldHandlerServlet</servlet-name>
<servlet-class>
net.ensode.glassfishbook.formhandling.MultipleValueFieldHandlerServlet
</servlet-class>
</servlet>

and:

<servlet-mapping>
<servlet-name>MultipleValueFieldHandlerServlet</servlet-name>
<url-pattern>/multiplevaluefieldhandlerservlet</url-pattern>
</servlet-mapping>

to assign a logical name and URL to the new servlet.

After re-creating the formhandling.war file by adding the compiled servlet and the HTML file and redeploying it, we can see the changes in action by typing the following URL in the browser window: http://localhost:8080/formhandling/multiplevaluedataentry.html.

Processing HTML Forms

After submitting the form, control goes to our servlet, and the browser window should look something like this:

Processing HTML Forms

Of course, the actual message seen in the browser window will depend on what checkboxes the user clicked on.

Request Forwarding and Response Redirection

In many cases, one servlet processes form data, then transfers control to another servlet or JSP to do some more processing or display a confirmation message on the screen. There are two ways of doing this: either the request can be forwarded or the response can be redirected to another servlet or page.

Request Forwarding

Notice how the text displayed in the previous sections' example matches the value of the value attribute of the checkboxes that were clicked, and not the labels displayed on the previous page. This might confuse the users. Let's modify the servlet to change these values so that they match the labels, then forward the request to another servlet that will display the confirmation message on the browser.

The new version of MultipleValueFieldHandlerServlet is shown next.

package net.ensode.glassfishbook.formhandling;
import java.io.IOException;
import java.util.ArrayList;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MultipleValueFieldHandlerServlet extends HttpServlet
{
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
{
String[] selectedOptions = request.getParameterValues("options");
ArrayList<String> selectedOptionLabels = null;
if (selectedOptions != null)
{
selectedOptionLabels = new
ArrayList<String>(selectedOptions.length);
for (String selectedOption : selectedOptions)
{
if (selectedOption.equals("option1"))
{
selectedOptionLabels.add("Option 1");
}
else if (selectedOption.equals("option2"))
{
selectedOptionLabels.add("Option 2");
}
else if (selectedOption.equals("option3"))
{
selectedOptionLabels.add("Option 3");
}
}
}
request.setAttribute("checkedLabels", selectedOptionLabels);
try
{
request.getRequestDispatcher("confirmationservlet").
forward(request, response);
}
catch (ServletException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}

This version of the servlet iterates through the selected options and adds the corresponding label to an ArrayList of Strings. This ArrayList is then attached to the request object by calling the request.setAttribute() method. This method is used to attach any object to the request so that any other code we forward the request to can have access to it later.

Note

This code uses generics, a feature introduced to the Java language in JDK 1.5, see http://java.sun.com/j2se/1.5.0/docs/guide/language/generics.html for details.

After attaching the ArrayList to the request, we then forward the request to the new servlet in the following line of code:

request.getRequestDispatcher("confirmationservlet").forward(
request, response);

The String argument to this method must match the value of the<url-pattern> tag of the servlet in the application's web.xml file.

At this point, control goes to our new servlet. The code for this new servlet is shown below:

package net.ensode.glassfishbook.requestforward;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ConfirmationServlet extends HttpServlet
{
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
{
try
{
PrintWriter printWriter;
List<String> checkedLabels = (List<String>) request
.getAttribute("checkedLabels");
response.setContentType("text/html");
printWriter = response.getWriter();
printWriter.println("<p>");
printWriter.print("The following options were selected:");
printWriter.println("<br/>");
if (checkedLabels != null)
{
for (String optionLabel : checkedLabels)
{
printWriter.print(optionLabel);
printWriter.println("<br/>");
}
}
else
{
printWriter.println("None");
}
printWriter.println("</p>");
}
catch (IOException ioException)
{
ioException.printStackTrace();
}
}
}

This code obtains the ArrayList that was attached to the request by the previous servlet. This is accomplished by calling the request.getAttribute() method; the parameter for this method must match the value used to attach the object to the request.

Once this servlet obtains the list of option labels, it traverses through it and displays them on the browser.

Request Forwarding

Forwarding a request as described above only works for other resources (servlets and JSP pages) in the same context as the code doing the forwarding. In simple terms, the servlet or JSP that we want to forward to must be packaged in the same WAR file as the code that is invoking the request.getRequestDispatcher().forward() method. If we need to direct the user to a page in another context (or even another server), we can do it by redirecting the response object.

Response Redirection

One disadvantage of forwarding a request as described in the previous section is that requests can only be forwarded to other servlets or JSPs in the same context. If we need to direct the user to a page on a different context (deployed in another WAR file in the same server or deployed in a different server) we need to use the HttpServletResponse.sendRedirect() method.

To illustrate response redirection, let's develop a simple web application that asks the user to select their favorite search engine, then directs the user to his/her search engine of choice. The HTML page for this application would look like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Response Redirection Demo</title>
</head>
<body>
<form method="post" action="responseredirectionservlet">
Please indicate your favorite search engine.
<table>
<tr>
<td><input type="radio" name="searchEngine"
value="http://www.google.com">Google</td>
</tr>
<tr>
<td><input type="radio" name="searchEngine"
value="http://www.msn.com">MSN</td>
</tr>
<tr>
<td><input type="radio" name="searchEngine"
value="http://www.yahoo.com">Yahoo!</td>
</tr><tr>
<td colspan="2"><input type="submit" value="Submit" /></td>
</tr>
</table>
</form>
</body>
</html>

The HTML form in this markup code contains three radio buttons; the value for each of them is the URL for the search engine corresponding to the user's selection. Notice how the value for the name attribute of each radio button is the same, namely "searchEngine". The servlet will obtain the value of the selected radio button by calling the request.getParameter() method and passing the string "searchEngine" as a parameter, as demonstrated in the code below:

package net.ensode.glassfishbook.responseredirection;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ResponseRedirectionServlet extends HttpServlet
{
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException
{
String url = request.getParameter("searchEngine");
if (url != null)
{
response.sendRedirect(url);
}
else
{
PrintWriter printWriter = response.getWriter();
printWriter.println("No search engine was selected.");
}
}
}

By calling request.getParameter("searchEngine"), this code assigns the URL of the selected search engine to the variable url. Then, (after checking for null, in case the user clicked on the submit button without selecting a search engine), it directs the user to the selected search engine by calling response.sendRedirect() and passing the url variable as a parameter.

The web.xml file for this application should be fairly straightforward and is not shown (it is part of this book's code download).

After packaging the code and deploying it, we can see it in action by typing the following URL in the browser: http://localhost:8080/responseredirection/.

Response Redirection

After clicking the submit button, the user is directed to their favorite search engine.

It should be noted that redirecting the response as just illustrated creates a new HTTP request to the page we are redirecting to; therefore any request parameters and attributes are lost.

Response Redirection

Persisting Application Data across Requests

In the previous section, we saw how it is possible to store an object in the request by invoking the HttpRequest.setAttribute() method and how later this object can be retrieved by invoking the HttpRequest.getAttribute() method. This approach only works if the request was forwarded to the servlet invoking the getAttribute() method. If this is not the case, the getAttribute() method will return null.

It is possible to persist an object across requests. In addition to attaching an object to the request object, an object can also be attached to the session object or to the servlet context. The difference between these two is that objects attached to the session will not be visible to different users, whereas objects attached to the servlet context are.

Attaching objects to the session and servlet context is very similar to attaching objects to the request. To attach an object to the session, the HttpServletRequest.getSession() method must be invoked. This method returns an instance of javax.servlet.http.HttpSession, we then call the HttpSession.setAttribute() method to attach the object to the session. The following code fragment illustrates the process:

protected void doPost(HttpServletRequest request, HttpServletResponse response)
{
.
.
.
Foo foo = new Foo(); //theoretical object
HttpSession session = request.getSession();
session.setAttribute("foo", foo);
.
.
.
}

We can then retrieve the object from the session by calling the HttpSession.getAttribute() method.

protected void doPost(HttpServletRequest request, HttpServletResponse response)
{
HttpSession session = request.getSession();
Foo foo = (Foo)session.getAttribute("foo");
}

Notice how the return value of session.getAttribute() needs to be cast to the appropriate type. This is necessary because the return value of this method is java.lang.Object.

The procedure to attach objects to and retrieve objects from the servlet context is very similar. The servlet needs to call the getServletContext() method (defined in the class called GenericServlet, which is the parent class of HttpServlet, which in turn is the parent class of our servlets). This method returns an instance of javax.servlet.ServletContext, which defines a setAttribute() and a getAttribute() method. These methods work in the same way as their HttpServletRequest and HttpSessionResponse counterparts.

The procedure to attach an object to the servlet context is illustrated in the following code snippet:

protected void doPost(HttpServletRequest request, HttpServletResponse response)
{
//The getServletContext() method is defined higher in
//the inheritance hierarchy.
ServletContext servletContext = getServletContext();
Foo foo = new Foo();
servletContext.setAttribute("foo", foo);
.
.
.
}

The above code attaches the foo object to the servlet context; this object will be available to any servlet in our application, and will be the same across sessions. It can be retrieved by calling the ServletContext.getAttribute() method, as is illustrated next.

protected void doPost(HttpServletRequest request, HttpServletResponse response)
{
ServletContext servletContext = getServletContext();
Foo foo = (Foo)servletContext.getAttribute("foo");
.
.
.
}

This code obtains the foo object from the request context; again a cast is needed because the ServletContext.getAttribute() method, like its counterparts, returns an instance of java.lang.Object.

Note

Objects attached to the servlet context are said to have a scope of application. Similarly, objects attached to the session are said to have a scope of session, and objects attached to the request are said to have a scope of request.

Summary

This chapter covered how to develop, configure, package, and deploy servlets. We also covered how to process HTML form information by accessing the HTTP request object. Additionally, we covered forwarding HTTP requests from one servlet to another, as well as redirecting the HTTP response to a different server. Lastly, we discussed how to persist objects in memory across requests by attaching them to the servlet context and the HTTP session.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.151.106