Session Management Part 1S2C Home « Session Management Part 1
In the last lesson we saw how our HTML form was sent back to the server after entry because we didn't put a path in the action attribute. We learnt that omitting the action attribute or leaving it as an empty string sends the submitted form to the same URL used for the request. This could give the impression that our client was in some sort of conversational state with the server. This isn't true of course as the language of the web, which as we have learned is HTTP, is stateless and so there is no way for the HTTP protocol to remember from which client the request was made and inform the server.
What many non-trivial applications require is a way for a web application to recognize requests made by new or returning visitors so we can process client requests appropriately. By using session management we can provide ways to let the server and more importantly the container know, which clients made a particular request through some sort of session tracking mechanism.
In the first of three lessons on conversational state we look at two ways to get around the statelessness of HTTP and the pros and cons of the session management techniques used to do this. First we will look at URL rewriting and then look at the use of hidden fields to achieve conversational state within our applications. Both of these methods of session management are mainly suitable for applications with small page counts as the work involved increases with each new page we add to an application.
URL RewritingTop
The first session management technique we will look at is URL rewriting which involves appending one or more tokens as a query string to a URL, beginning with a ?
and delimited by
&
. This is normally in the form of one or more key/value pairs and the following code shows an example of a URL where a resource called nameform
will be looked up on the
server and firstname
and lastname
keys have been sent with values of john
and smith
.
http://jsptutor.co.uk/nameform?firstname=john&lastname=smith
Before we write a servlet to demonstrate URL rewriting, let's take a look at the advantages and disadvantages of using this session management technique.
Advantages
URL rewriting is not dependant upon storing information on the client's computer as for instance using cookies is, which is a session management technique we will look at in the next lesson.
URL rewriting can be used in combination with cookies, as a fallback for session tracking, if cookies are disabled by the user.
Disadvantages
The length of the URL sent by some of the older browsers is limited in size, so this may be an issue if you send a lot of information across in the URL.
Any information that is passed across in the URL is visible, which might not be the ideal situation if sensitive information such as passwords need to be passed across to the server.
All links need to pass across the URL rewriting information to the server which can be a hit to performance as well as development and maintenance overheads; so the more links we need to pass across the greater the hit and workload.
The container creates a HttpSession
object on initial entry to a website, so if you need to keep track of a user's session id then then this will only work for URL rewriting with dynamic pages, not normal HTML static pages.
If the space character or the special characters listed below form part of the query string of a URL they have to be encoded first, unless they are being used as delimiters.
; , / ? : @ & = + $ #
URL Rewriting ExampleTop
Within the _ServletsInt
folder create a new folder for the web application we will create in this lesson and call it numbers
.
Within the numbers
folder create separate folders to hold our DD, source files and our compiled byte code and called dd
, src
and classes
. Within the
src
folder create a subfolder called controller
.
So after creating these folders your directory structure should look something like the following screenshot:
Coding NumbersServlet
Top
We are now ready to code up a servlet that uses URL rewriting as its session management technique. On initial entry to the NumbersServlet
class below the doGet()
will be
invoked and as this is the first time in, the numType
parameter will be null
and so the displayHomePage()
method will run. After this the URL will get rewritten
dependant upon the odds or evens option chosen by the user and the displayNumbers()
method will be invoked and display the users number choice. After this the URL will get rewritten
dependant upon user choices and the appropriate details displayed.
Cut and paste the following code into your text editor and save it in the c:\_ServletsInt\numbers\src\controller directory as NumbersServlet.java
.
package controller;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class NumbersServlet extends HttpServlet {
private static final long serialVersionUID = 871964L;
private String[] oddNumbers = {"1", "3", "5", "7", "9", "11", "13", "15", "17", "19"};
private String[] evenNumbers = {"2", "4", "6", "8", "10", "12", "14", "16", "18", "20"};
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// Check to see if we passed a number type across in URL and display appropriate page
String numType = req.getParameter("numType");
if (numType != null && (numType.equals("odds") || numType.equals("evens"))) {
// display odd or even numbers
displayNumbers(req, resp, numType);
} else {
// display home
displayHomePage(req, resp);
}
}
public void displayHomePage(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// Create a response
resp.setContentType("text/html");
PrintWriter writer = resp.getWriter();
writer.print("<html><head><title>Odd or Even Numbers Selection</title></head>" +
"<body><h1>Select odd or even:</h1>" +
"<a href='?numType=odds'>odds</a><br>" +
"<a href='?numType=evens'>evens</a>" +
"</body></html>");
}
public void displayNumbers(HttpServletRequest req, HttpServletResponse resp, String numType)
throws ServletException, IOException {
int pageNum = 1;
String pageReq = req.getParameter("pageNum");
if (pageReq != null) {
// Retrieve and convert page number to int type
try {
pageNum = Integer.parseInt(pageReq);
} catch(NumberFormatException ex) {
}
// Stop ArrayIndexOutOfBoundsException
in for
loop if user overtypes URL page number
if (pageNum > 2) {
pageNum = 1;
}
}
String[] dispNumbers = new String[10];
if (numType.equals("odds")) {
dispNumbers = oddNumbers;
} else {
dispNumbers = evenNumbers;
}
// Create a response
resp.setContentType("text/html");
PrintWriter writer = resp.getWriter();
writer.print("<html><head><title>Display Numbers</title></head>" +
"<body><h1>Display Numbers:</h1>" +
"<a href='oddsandevens'>Select Numbers</a><br>" +
"<strong>Page " + pageNum + "</strong><br>");
int startIdx = pageNum * 5 - 5;
// Cycle through selected array and send to HTML
for (int i = startIdx; i < startIdx + 5; i++) {
writer.println(dispNumbers[i] + "<br>");
}
writer.println("<a href='?numType=" + numType + "&pageNum=1'>Page 1</a>");
writer.print(" <a href='?numType=" + numType + "&pageNum=2'>Page 2</a>");
writer.print("</body></html>");
}
}
Compiling NumbersServlet
Top
Open your command line editor:
Change to directory c:\_ServletsInt\numbers\src\controller
Compile NumbersServlet.java
using the java compiler with the -cp
and -d
options as below, making sure you change apache-tomcat-6.0.37
to wherever you downloaded Tomcat to.
javac -cp c:\apache-tomcat-6.0.37\lib\servlet-api.jar -d ..\..\classes NumbersServlet.java
The following screenshot shows that we get a clean compile and also the NumbersServlet
class now compiled into the classes\controller
directory.
Coding The DDTop
There are no DD entries for this application that we haven't seen before.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" version="2.5">
<servlet>
<servlet-name>numbers</servlet-name>
<servlet-class>controller.NumbersServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>numbers</servlet-name>
<url-pattern>/oddsandevens</url-pattern>
</servlet-mapping>
</web-app>
Save the web.xml
file in the DD
folder.
Tomcat DeploymentTop
Go to your Tomcat installation which in my case is:
C:\apache-tomcat-6.0.37\webapps\
Within the webapps
folder create a folder for our web application called numbers
Within the numbers
folder create the WEB-INF
folder.
Copy the web.xml
file and the classes
directory and contents from our development environment into the WEB-INF
folder.
After creating these folders and copying the files from development your Tomcat directory structure within the webapps\numbers
folder should look something like the following screenshot:
Testing Our ServletTop
Open a command prompt and change the directory to the location of our Tomcat bin directory and then type in startup
(Windows 7) or startup.sh
(Linux/Unix/OSX).
Press Enter and the Tomcat server should open up in a new window.
You can also start up Tomcat by double-clicking the startup
batch file within your Tomcat /bin
folder.
With Tomcat up and running type the following into your web browser address bar and press enter:
http://localhost:8080/numbers/oddsandevens
The web browser should be directed to the NumbersServlet
servlet class within Tomcat and execute it. On initial entry to the NumbersServlet the doGet()
will be invoked and as
this is the first time in the numType
parameter will be null
and so the displayHomePage()
method will run and produce a screen that looks like the following:
After this the URL will get rewritten dependant upon the odds or evens option chosen by the user and the displayNumbers()
method will be invoked and display the users number choice. The
following screenshot shows the screen after the odds
hyperlink has been clicked
This last screenshot shows the screen after the Page 2
hyperlink has been pressed.
Hidden FieldsTop
The second session management technique we will look at is hidden fields which involves putting hidden fields into a HTML form rather than appending values to the URL as we did with URL rewriting. The hidden fields get passed over to the server along with the defaults and other values entered on the HTML form and can then be used to track the session.
Before we write a servlet to demonstrate using hidden fields for session tracking, let's take a look at the advantages and disadvantages of using this session management technique.
Advantages
Because the information is passed across in the HTML form and not the URL, you can pass across far more information to the server than with the URL rewriting technique.
The hidden fields can contain special characters that don't have to be encoded unlike URL rewriting.
All information that is passed across to the server in the HTML form is not visible, so sensitive information such as passwords can be passed across, within the HTML form, to the server.
Hidden fields are not dependant upon storing information on the client's computer as for instance using cookies is, which is a session management technique we will look at in the next lesson.
Disadvantages
All pages within the application need to pass the hidden fields to the server which can be a hit to performance as well as development and maintenance overheads; so the more pages we need to pass the hidden fields to, the greater the hit and workload
Hidden Fields ExampleTop
Within the _ServletsInt
folder create a new folder for the web application we will create in this lesson and call it bookstore
Within the bookstore
folder create separate folders to hold our DD, source files and our compiled byte code and called dd
, src
and classes
. Within the
src
folder create two subfolders called controller
and model
.
So after creating these folders your directory structure should look something like the following screenshot:
Coding The Book
ClassTop
The Book
Class models a book title and some details and uses the JavaBeans standard of get<someProperty>
and set<someProperty>
. For a refresher
on JavaBeans you can find information in the Java section at Encapsulation - Getters & Setters.
Cut and paste the following code into your text editor and save it in the c:\_ServletsInt\bookstore\src\model directory as Book.java
.
package model;
public class Book {
private int num;
private String title;
private String rating;
// Getters and setters
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getRating() {
return rating;
}
public void setRating(String rating) {
this.rating = rating;
}
}
Compiling The Book
ClassTop
Open your command line editor:
Change to directory c:\_ServletsInt\bookstore\src\model
Compile Book.java
using the java compiler with the -cp
and -d
options as below, making sure you change apache-tomcat-6.0.37
to wherever you downloaded Tomcat to.
javac -cp c:\apache-tomcat-6.0.37\lib\servlet-api.jar -d ..\..\classes Book.java
The following screenshot shows that we get a clean compile and also the Book
class now compiled into the classes\model
directory.
Coding BookStoreServlet
Top
Ok with our model, the Book
class coded and compiled we are now ready to code up a servlet that uses hidden fields as its session management technique. On deployment the init()
routine will run and create 3 books objects for later use. After initialisation, when the BookStoreServlet
class below is run the doGet()
will be invoked and we use the
HttpServletRequest
method encodeURI()
to get the URI and then use the String
method endsWith()
, to detemine whether to invoke the displayBookList()
method, or the displayEditBookForm()
method.
When the form is submitted we use action='updateBook' attribute along with method='post' attribute so that the /updateBook
mapping in the DD below will send us to the doPost()
method where we can action the HTML form.
Cut and paste the following code into your text editor and save it in the c:\_ServletsInt\bookstore\src\controller directory as BookStoreServlet.java
.
package controller;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.ArrayList;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import model.Book;
public class BookStoreServlet extends HttpServlet {
private static final long serialVersionUID = 871964L;
private List<Book> books = new ArrayList<Book>();
@Override
public void init() throws ServletException {
// Create some Book records for later use
Book book1 = new Book();
book1.setNum(1);
book1.setTitle("Wuthering Heights");
book1.setRating("Classic");
books.add(book1);
Book book2 = new Book();
book2.setNum(2);
book2.setTitle("The Railway Children");
book2.setRating("Good");
books.add(book2);
Book book3 = new Book();
book3.setNum(3);
book3.setTitle("Treasure Island");
book3.setRating("Great");
books.add(book3);
}
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// Get request URL so we can decide which method to invoke
String uri = req.getRequestURI();
if (uri.endsWith("/book")) {
// display book list
displayBookList(resp);
} else if (uri.endsWith("/editBook")) {
// display editable book form
displayEditBookForm(req, resp);
}
}
@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
int bookNum = 0;
// Update a Book object
String num = req.getParameter("num");
if (num != null) {
// Retrieve and convert book number to int type
try {
bookNum = Integer.parseInt(num);
Book book = getBook(bookNum);
if (book != null) {
book.setTitle(req.getParameter("title"));
book.setRating(req.getParameter("rating"));
}
} catch(NumberFormatException ex) {
}
}
displayBookList(resp);
}
public void displayBookList(HttpServletResponse resp) throws IOException {
// Create a response
resp.setContentType("text/html");
PrintWriter writer = resp.getWriter();
writer.println("<html><head><title>Books</title></head>" +
"<body><h1>Books In Stock:</h1><ul>");
for (Book book : books) {
writer.println("<li>" + book.getTitle() + "(" + book.getRating() + ") (" +
"<a href='editBook?num=" + book.getNum() + "'>Edit Book</a>)</li>");
}
writer.println("</ul></body></html>");
}
public void displayEditBookForm(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
// Create a response
resp.setContentType("text/html");
PrintWriter writer = resp.getWriter();
int bookNum = 0;
// Retrieve and convert book number to int type
try {
bookNum = Integer.parseInt(req.getParameter("num"));
} catch(NumberFormatException ex) {
}
Book book = getBook(bookNum);
if (book != null) {
// We found the book so lets output to a table with hidden field
writer.println("<html><head><title>Edit Book</title></head>" +
"<body><h1>Edit Book:</h1><form action='updateBook' method='post'>" +
"<fieldset style='background-color:silver;border:1px solid black;" +
"padding:5px;text-align:left;width:220px;'>" +
"<legend>Edit Book Details</legend>");
writer.println("<input type=hidden name='num' value='" + bookNum + "'/>");
writer.println("<table><tr><td>Title:</td><td><input name='title' value='" +
book.getTitle() + "'/></td></tr>");
writer.println("<tr><td>Rating:</td><td><input name='rating' value='" +
book.getRating() + "'/></td></tr>");
writer.println("<tr><td><input type='submit' value='Update Book'/></td><td></td></tr>");
writer.println("<tr><td><a href='book'>Book List</a></td><td></td></tr>");
writer.println("</table></form></body></html>");
} else {
writer.println("Sorry, the requested book was not found.");
}
}
public Book getBook(int bookNum) {
// Retrieve a book using number
for (Book book : books) {
if (book.getNum() == bookNum) {
return book;
}
}
return null;
}
}
Compiling BookStoreServlet
Top
Open your command line editor:
Change to directory c:\_ServletsInt\bookstore\src\controller
Compile BookStoreServlet.java
using the java compiler with the -cp
and -d
options as below, making sure you change apache-tomcat-6.0.37
to wherever you downloaded Tomcat to.
javac -cp c:\apache-tomcat-6.0.37\lib\servlet-api.jar;..\..\classes -d ..\..\classes BookStoreServlet.java
The following screenshot shows that we get a clean compile and also the BookStoreServlet
class now compiled into the classes\controller
directory.
Coding The DDTop
There are no DD entries for this application that we haven't seen before but there is a slight difference in this DD than in those we have seen before. Notice how within the <servlet-mapping>
top-level element that there are three <url-pattern> sub-level elements which all map to the
BookStoreServlet
servlet. This is why we do the check within the doGet()
method using the HttpServletRequest
method encodeURI()
. This method will get
the URI and we then use the String
method endsWith()
to detemine whether to invoke the displayBookList()
method, or the displayEditBookForm()
method.
When the form is submitted we use action='updateBook' attribute along with method='post' attribute so that the /updateBook
mapping will send us to the doPost()
method where we can action the HTML form.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" version="2.5">
<servlet>
<servlet-name>bookStore</servlet-name>
<servlet-class>controller.BookStoreServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>bookStore</servlet-name>
<url-pattern>/book</url-pattern>
<url-pattern>/editBook</url-pattern>
<url-pattern>/updateBook</url-pattern>
</servlet-mapping>
</web-app>
Save the web.xml
file in the DD
folder.
Tomcat DeploymentTop
Go to your Tomcat installation which in my case is:
C:\apache-tomcat-6.0.37\webapps\
Within the webapps
folder create a folder for our web application called bookstore
Within the bookstore
folder create the WEB-INF
folder.
Copy the web.xml
file and the classes
directories and contents from our development environment into the WEB-INF
folder.
After creating these folders and copying the files from development your Tomcat directory structure within the webapps\bookstore
folder should look something like the following screenshot:
Testing Our ServletTop
Open a command prompt and change the directory to the location of our Tomcat bin directory and then type in startup
(Windows 7) or startup.sh
(Linux/Unix/OSX).
Press Enter and the Tomcat server should open up in a new window.
You can also start up Tomcat by double-clicking the startup
batch file within your Tomcat /bin
folder.
With Tomcat up and running type the following into your web browser address bar and press enter:
http://localhost:8080/bookstore/book
The web browser should be directed to the BookStoreServlet
servlet class within Tomcat and execute it. On initial entry to BookStoreServlet the doGet()
will be invoked and we
use the HttpServletRequest
method encodeURI()
to get the URI and then use the String
method endsWith()
, to detemine whether to invoke the
displayBookList()
method, or the displayEditBookForm()
method. Because of what we entered on the address line the displayBookList()
method will run and produce a screen that looks like the following:
The following screenshot shows the screen after we clicked on the hyperlink for The Railway Children.
This last screenshot shows the screen after we changed the rating to Classic and hit the Update Book
button.
The changes we made appear in the book list and you can make further changes to make sure things get updated. Of course we are not persisting anything to a database as we would in the real world so if
you redeploy the application then all changes will be lost and the list recreated via the init()
method. Another point is there is no synchronisation for updating book details as there would
need to be if this were a real application.
Lesson 2 Complete
In this lesson we looked at two session management techniques, URL rewriting and hidden fields, that can be used when the application doesn't contain lots of pages.
What's Next?
In the next lesson we look at the use of cookies as a session management technique.