Chapter 7. Tracking Users with Sessions and Cookies

Today you'll learn about one of the most popular uses of JSP—tracking users with sessions and cookies. Tracking users is a perennial problem; when a user looks at your Web page, has that user been there before? Will you be remembering something about her? Will you remember her present purchases and be checking them out, displaying their total cost? Will you be customizing her Web page in ways that she's specified in the past? Today you'll see several ways of tracking users, including the following:

  • Hidden text—. Using hidden controls in a Web page is the easiest way of associating some information with the user that's not directly accessible to him. However, the hidden text can be seen if the user looks at the HTML for the Web page directly.

  • Cookies—. This is probably the most common way of tracking users on the Internet. You can store information in a user's computer using cookies, and retrieve it when you need it. You can also specify how long the cookie should exist before being deleted by the browser.

  • Sessions—. Sessions are something the server offers us to support user tracking, and they're great, although they can take up a lot of resources on the server. Sessions let you preserve data between accesses to a Web page by the same user.

  • Applications—. Applications are much like sessions, as you'll see, but they're more general—you can share data between all the JSP pages in a site using applications. In other words, unlike sessions, applications can be used to track multiple users at the same time.

  • Sessions, applications, and JavaBeans—. You can also set JavaBeans so they'll be included in a session or application. Normally, the data in a JavaBean is reset each time the user accesses a page and creates an object from that bean, but you can include the bean in a session or application so its data is preserved between accesses by the same user.

The first step is to use HTML hidden controls.

Using Hidden Controls

Using HTML hidden controls is an easy way to store data in a Web page. For example, in this JSP page, the code will let the user set the text to store in a hidden control in a text field:

<HTML> 
  <HEAD>
    <TITLE>Reading Hidden Controls</TITLE>
  </HEAD>

    <BODY>
        <H1>Reading Hidden Controls</H1>
        <%
            String text = "";
            if(request.getParameter("TEXT1") != null) {
                out.println("The hidden text is:" + request.getParameter("TEXT1"));
                text = request.getParameter("TEXT1");
            }
        %>
        .
        .
        .

The code stores the text the user types in the hidden control, as you can see in Listing 7.1.

Example 7.1. Reading Hidden Controls (ch07_01.jsp)

<HTML>
  <HEAD>
    <TITLE>Reading Hidden Controls</TITLE>
  </HEAD>

    <BODY>
        <H1>Reading Hidden Controls</H1>
        <%
            String text = "";
            if(request.getParameter("TEXT1") != null) {
                out.println("The hidden text is:" + request.getParameter("TEXT1"));
                text = request.getParameter("TEXT1");
            }
        %>
        <FORM ACTION="ch07_01.jsp" METHOD="POST">
            <INPUT TYPE="TEXT" NAME="TEXT1">
            <INPUT TYPE="HIDDEN" NAME="HIDDEN"
                VALUE="<%= text%>">
            <INPUT TYPE="SUBMIT" VALUE="Set Hidden Text">
        </FORM>
    </BODY>
</HTML>

You can see this page in Figure 7.1, where the user has entered some text and is about to click the Set Hidden Text button.

Setting hidden text.

Figure 7.1. Setting hidden text.

When the user clicks the button, the JSP code stores the text she's entered in a hidden control and displays that text, as you see in Figure 7.2.

Getting hidden text.

Figure 7.2. Getting hidden text.

The user can also take a look at the data in the hidden field directly—all she has to do is to view the HTML source of the page you see in Figure 7.2 (using the View, Source menu item in Internet Explorer, or the View, Page Source menu item in Netscape Navigator). Here's what that HTML source looks like—note the hidden control's text:

<HTML> 
  <HEAD>
    <TITLE>Reading Hidden Controls</TITLE>
  </HEAD>

    <BODY>
        <H1>Reading Hidden Controls</H1>
        The hidden text is:Hello there!

        <FORM ACTION="hidden.jsp" METHOD="POST">
            <INPUT TYPE="TEXT" NAME="TEXT1">
            <INPUT TYPE="HIDDEN" NAME="HIDDEN"
                VALUE="Hello there!">
            <INPUT TYPE="SUBMIT" VALUE="Set Hidden Text">
        </FORM>
    </BODY>
</HTML>

Hidden controls are fine as far as they go, but there are a number of obvious problems here—you can't store data in a secure way, and you can't store data between sessions. However, you can get around those problems with cookies.

You might not be surprised to learn that there's a class you use to work with cookies in JSP—the cookie class.

The Cookie Class

Cookies—. you either love them or hate them. They're small text strings you store on a user's computer. In the early days of cookies, people were very suspicious of them, but the truth is that they're simply text and can't cause problems (unless there are security problems in the user's browser that have not yet been exploited by hackers).

Tip

Although cookies are widely regarded as safe, many users are still wary of them, and have instructed their browsers not to accept them. If you can't set a cookie in the client browser you're working with, you might try another method of storing data, such as hidden controls. Technically, a browser is expected to support 20 cookies for each Web server; about 300 cookies total—and might limit the size of each cookie to 4KB of text.

A cookie's value can identify a user, so they are commonly used for session management. Cookies have a name and a value, and you can use methods of the Cookie class (the full name, including the Java package, is javax.servlet.http.Cookie) to get access to that data. You can also include comments in cookies and set their maximum possible ages.

Your JSP code sends cookies to the browser by using the HttpServletResponse.addCookie method. This method stores data in the HTTP response headers it sends to the browser, including the cookies you're creating.

The browser returns cookies to you by storing data in HTTP request headers. You can get cookie data using the HttpServletRequest.getCookies method, as you'll see in the upcoming examples.

You'll see how this all works in detail in today's work. You can see the methods of Cookie objects (that is, the javax.servlet.http.Cookie class) in Table 7.1.

Table 7.1. javax.servlet.http.Cookie Methods

Method

Does This

Cookie(java.lang.String name, java.lang.String value)

Creates a cookie with a given name and value.

java.lang.Object clone()

Returns a copy of the cookie.

java.lang.String getComment()

Returns the cookie's comment, or null if the cookie has no comment.

java.lang.String getDomain()

Returns the domain name for the cookie.

int getMaxAge()

Returns the maximum age of the cookie, in seconds. A value of -1 indicates the cookie will exist until browser shutdown.

java.lang.String getName()

Returns the name of the cookie.

java.lang.String getPath()

Returns the path on the server so that the browser returns the cookie.

boolean getSecure()

Returns true if the browser is sending cookies only over a secure protocol.

java.lang.String getValue()

Returns the value of the cookie.

int getVersion()

Returns the version of the protocol for the cookie.

void setComment(java.lang.String comment)

Sets a comment that describes a cookie's purpose.

void setDomain(java.lang.String domain)

Specifies the domain for the cookie.

void setMaxAge(int expiry)

Sets the maximum age of the cookie in seconds.

void setPath(java.lang.String uri)

Sets the path for the cookie (that is, the path by which the browser will send the cookie).

void setSecure(boolean flag)

Indicates to the browser if cookies should only be sent using a secure protocol (such as HTTPS).

void setValue(java.lang.String value)

Assigns a new value to a cookie after the cookie is created.

void setVersion(int version)

Sets the version of the cookie protocol for the cookie.

So how do you create a cookie? You use the addCookie method of the HttpServletResponse class, and that class is coming up next.

The HttpServletResponse Interface

The HttpServletResponse Interface

So where does that leave you? Fortunately, the server has done all the work you'll need here—one of the built-in objects available to you in your JSP code is the response object (see “The JSP Programming Environment” in Day 2, “Handling Data and Operators”), and this is a pre-built object based on the javax.servlet.http.HttpServletResponse interface.

Just as you use the request object to see what data the user has sent to you, you can use the response object to send data back to the user. In this case, you'll use this object to send cookies back to the browser, which will store them. You can see the fields of the javax.servlet.http.HttpServletResponse interface in Table 7.2, and the methods of this interface in Table 7.3. Because the response object is built on this interface, it shares all the methods of the interface, and you'll see how to put them to work in the next topic, creating your own cookies with the addCookie method. You use the various field values in Table 7.2 if you want to send a status report back to the browser, as with the sendError or setStatus methods (which we won't do here).

Note

The convention for fields is that if its name is in capital letters, it's a read-only constant whose value doesn't change.

Table 7.2. HttpServletResponse Fields

Method

Does This

int SC_ACCEPTED

Indicates that a request was accepted for processing, but was not completed.

int SC_BAD_GATEWAY

Indicates that the HTTP server received an invalid response from a server it consulted when acting as a proxy or gateway.

int SC_BAD_REQUEST

Indicates the request sent by the client was incorrect.

int SC_CONFLICT

Indicates that the request cannot be completed because of a conflict with the current state of the resource.

int SC_CONTINUE

Indicates the client can continue.

int SC_CREATED

Indicates the request succeeded and created a new resource on the server.

int SC_EXPECTATION_FAILED

Indicates that the server cannot meet the request in the Expect request header.

int SC_FORBIDDEN

Indicates the server cannot complete the request.

int SC_GATEWAY_TIMEOUT

Indicates that the server did not receive a response from a gateway or proxy server in time.

int SC_GONE

Indicates that the resource is no longer available.

int SC_HTTP_VERSION_NOT_SUPPORTED

Indicates that the server does not support the HTTP protocol version used in the request.

int SC_INTERNAL_SERVER_ERROR

Indicates an error inside the HTTP server.

int SC_LENGTH_REQUIRED

Indicates that the request cannot be handled without a specified content length.

int SC_METHOD_NOT_ALLOWED

Indicates that the method specified in the Request-Line is not allowed.

int SC_MOVED_PERMANENTLY

Indicates that the resource has moved to a new location.

int SC_MOVED_TEMPORARILY

Indicates that the resource has temporarily moved to another location.

int SC_MULTIPLE_CHOICES

Indicates that the resource corresponds to any one of a set.

int SC_NO_CONTENT

Indicates that the request was successful but there was no new content to return.

int SC_NON_AUTHORITATIVE_INFORMATION

Indicates that the meta information sent by the browser did not come from the server.

int SC_NOT_ACCEPTABLE

Indicates that the resource identified by the request was not acceptable.

int SC_NOT_FOUND

Indicates that the requested resource was not available.

int SC_NOT_IMPLEMENTED

Indicates the HTTP server does not support the request.

int SC_NOT_MODIFIED

Indicates that a GET operation found that the resource was available and not modified.

int SC_OK

Indicates the request succeeded.

int SC_PARTIAL_CONTENT

Indicates that the server has fulfilled the partial GET request.

int SC_PAYMENT_REQUIRED

Reserved for future use.

int SC_PRECONDITION_FAILED

Indicates that the precondition given in a request header field failed.

int SC_PROXY_AUTHENTICATION_REQUIRED

Indicates that the client must authenticate itself with the proxy.

int SC_REQUEST_ENTITY_TOO_LARGE

Indicates that the request entity is larger than the server can process.

int SC_REQUEST_TIMEOUT

Indicates that the request timed out.

int SC_REQUEST_URI_TOO_LONG

Indicates that the Request-URI field is too long.

int SC_REQUESTED_RANGE_NOT_SATISFIABLE

Indicates that the server cannot serve the requested data range.

int SC_RESET_CONTENT

Indicates that the agent will reset the display of the document.

int SC_SEE_OTHER

Indicates that the response to the request can be found under a different URI.

int SC_SERVICE_UNAVAILABLE

Indicates that the HTTP server is overloaded.

int SC_SWITCHING_PROTOCOLS

Indicates the server is switching protocols.

int SC_TEMPORARY_REDIRECT

Indicates that the requested resource is temporarily at a different URI.

int SC_UNAUTHORIZED

Indicates that the request needs HTTP authentication.

int SC_UNSUPPORTED_MEDIA_TYPE

Indicates that the request is in a format not supported by the requested resource.

int SC_USE_PROXY

Indicates that the requested resource must be accessed through the proxy.

Table 7.3. HttpServletResponse Methods

Method

Does This

void addCookie(Cookie cookie)

Adds the given cookie to the response.

void addDateHeader(java.lang.String name, long date)

Adds a response header with the given name and date.

void addHeader(java.lang.String name, java.lang.String value)

Adds a response header with the given name and value.

void addIntHeader(java.lang.String name, int value)

Adds a response header with the given name and integer value.

boolean containsHeader (java.lang.String name)

Returns a Boolean value indicating if a response header has been set.

java.lang.String encodeRedirectUrl (java.lang.String url)

Deprecated. As of servlet specification version 2.1, use encodeRedirectURL (String url) instead.

java.lang.String encodeRedirectURL (java.lang.String url)

Encodes the specified URL for use in the sendRedirect method.

java.lang.String encodeUrl (java.lang.String url)

Deprecated. As of servlet specification version 2.1, use encodeURL(String url) instead.

java.lang.String encodeURL (java.lang.String url)

Encodes the specified URL by including the session ID in it.

void sendError(int sc)

Sends an error response to the client using the given status field value.

void sendError(int sc, java.lang.String msg)

Sends an error response to the client using the given field value and text.

void sendRedirect (java.lang.String location)

Sends a temporary redirect response to the browser using the given URL.

void setDateHeader(java.lang.String name, long date)

Sets a response header with the given name and date.

void setHeader(java.lang.String name, java.lang.String value)

Sets a response header with the given name and value.

void setIntHeader(java.lang.String name, int value)

Sets a response header with the given nameand integer value.

void setStatus(int sc)

Sets the status code for this response.

void setStatus (int sc, java.lang.String sm)

Deprecated. As of servlet specification version 2.1, use setStatus(int) to send an error with a description.

Creating a Cookie

This next example will put all this new technology to work. Here, the code will create a cookie and place some text in it, and another page will read the cookie and display that text. To create the cookie, you use the Cookie class's constructor, passing it the name of the cookie (which will be message here) and the text in the cookie (which will just be “Hello!” in this case). You can also set the length of time the cookie will exist on the user's computer with the setMaxAge method, which you pass a value in seconds to—to make the cookie last for a day, you can pass a value of 24 * 60 * 60 this way:

<HTML> 
    <HEAD>
        <TITLE>Setting a Cookie</TITLE>
    </HEAD>

    <BODY>
        <H1>Setting a Cookie</H1>

        <%
        Cookie cookie1 = new Cookie("message", "Hello!");
        cookie1.setMaxAge(24 * 60 * 60);
        %>
        .
        .
        .

That creates the cookie, but doesn't install it in the browser—to do that, you use the response object's addCookie method this way:

<HTML> 
    <HEAD>
        <TITLE>Setting a Cookie</TITLE>
    </HEAD>

    <BODY>
        <H1>Setting a Cookie</H1>

        <%
        Cookie cookie1 = new Cookie("message", "Hello!");
        cookie1.setMaxAge(24 * 60 * 60);
        response.addCookie(cookie1);
        %>
        .
        .
        .

That installs the cookie in the browser. You can also include a link to the page that will read the cookie, as you see in Listing 7.2.

Example 7.2. Setting a Cookie (ch07_02.jsp)

<HTML>
    <HEAD>
        <TITLE>Setting a Cookie</TITLE>
    </HEAD>

    <BODY>
        <H1>Setting a Cookie</H1>

        <%
        Cookie cookie1 = new Cookie("message", "Hello!");
        cookie1.setMaxAge(24 * 60 * 60);
        response.addCookie(cookie1);
        %>

        <A HREF="ch07_03.jsp"/>Read the cookie</A>
    </BODY>
</HTML>

You can see this page in Figure 7.3, where it's already set its cookie in the browser. The next step is to read that cookie's information back in.

Setting a cookie.

Figure 7.3. Setting a cookie.

Reading a Cookie

To store a cookie in the user's computer, you use the request object's getCookies method. This method returns an array of Cookie objects (or null if there are no cookies) So how do you read the cookie named message? You start with the getCookies method, creating an array of Cookie objects:

<HTML> 
    <HEAD>
        <TITLE>Reading a Cookie</TITLE>
    </HEAD>

    <BODY>
        <H1>Reading a Cookie</H1>

        <%
        Cookie[] cookies = request.getCookies();
        .
        .
        .

Tip

Are you passed all the cookies on the computer? No, you're only passed the cookies that came from the same domain as the page you're using the getCookies method in.

This returns an array of cookies, which you can loop over to find the message cookie. Here's what that loop might look like:

<HTML> 
    <HEAD>
        <TITLE>Reading a Cookie</TITLE>
    </HEAD>

    <BODY>
        <H1>Reading a Cookie</H1>

        <%
        Cookie[] cookies = request.getCookies();

        for(int loopIndex = 0; loopIndex < cookies.length; loopIndex++) {
            .
            .
            .
        }
        .
        .
        .

Inside the body of the loop, you can get the name of each cookie with the Cookie class's getName method, and its value with the getValue method. If the code finds the message cookie, it displays that cookie's value. You can see what that looks like in Listing 7.3.

Example 7.3. Reading a Cookie (ch07_03.jsp)

<HTML>
    <HEAD>
        <TITLE>Reading a Cookie</TITLE>
    </HEAD>

    <BODY>
        <H1>Reading a Cookie</H1>

        <%
        Cookie[] cookies = request.getCookies();

        for(int loopIndex = 0; loopIndex < cookies.length; loopIndex++) {
            if (cookies[loopIndex].getName().equals("message")) {
               out.println("The cookie says " + cookies[loopIndex].getValue());
            }
        }
        %>
    </BODY>
</HTML>

Now this page is able to read the cookie set in ch07_02.jsp. You can see what the results are in Figure 7.4, where the code was able to recover and display the cookie's text.

Reading a cookie.

Figure 7.4. Reading a cookie.

Now you're setting and reading cookies using JSP!

Setting and Reading a Cookie in the Same Page

The previous example set a cookie in one page and read it in another, but sometimes you might want to set and read a cookie in the same page. For example, if your home page allows the user to customize some aspects of the page, such as its background color, you can store that information in a cookie. The next time the user opens your home page, your code can read that cookie and display the correct background color.

Here's an example to show how this works—in this case, the code will set a cookie named color to cyan, and the next time you load the same page, the JSP code will use that cookie to change the background color of the page to cyan. When the page loads, it will check for the cookie named color, and if it's found, use its value to set the background color of the Web page. However, if that cookie isn't found, the code will set a Boolean variable named foundCookie to false, which means it will have to create the cookie:

<HTML> 
    <HEAD>
        <TITLE>Setting and Reading Cookies</TITLE>
    </HEAD>

    <BODY
        <%
        Cookie[] cookies = request.getCookies();
        boolean foundCookie = false;

        for(int loopIndex = 0; loopIndex < cookies.length; loopIndex++) {
            Cookie cookie1 = cookies[loopIndex];
            if (cookie1.getName().equals("color")) {
                out.println("bgcolor = " + cookie1.getValue());
                foundCookie = true;
            }
        }
        .
        .
        .

If foundCookie is false the code will set the color cookie. You can test if foundCookie is false with an if statement and the JSP not operator. ! (discussed in Day 2), which flips the Boolean sense of its argument like this

if(!foundCookie) 

where the body of the if statement is executed if the color cookie wasn't found. In that case, the code creates the cookie and stores it as you see in Listing 7.4.

Example 7.4. Setting and Reading Cookies in the Same Page (ch07_04.jsp)

<HTML>
    <HEAD>
        <TITLE>Setting and Reading Cookies</TITLE>
    </HEAD>

    <BODY
        <%
        Cookie[] cookies = request.getCookies();
        boolean foundCookie = false;

        for(int loopIndex = 0; loopIndex < cookies.length; loopIndex++) {
            Cookie cookie1 = cookies[loopIndex];
            if (cookie1.getName().equals("color")) {
                out.println("bgcolor = " + cookie1.getValue());
                foundCookie = true;
            }
        }

        if (!foundCookie) {
            Cookie cookie1 = new Cookie("color", "cyan");
            cookie1.setMaxAge(24*60*60);
            response.addCookie(cookie1);
        }
        %>
        >
        <H1>Setting and Reading Cookies</H1>
        This page will set its background color using a cookie.
    </BODY>
</HTML>

When you load this page the first time, it sets the color cookie, and the page background will be white. When you load the page from then on, until the cookie expires, the page reads that cookie and uses it to turn the page background cyan, as you see in Figure 7.5.

Setting and reading a cookie using the same page.

Figure 7.5. Setting and reading a cookie using the same page.

That gives you a good foundation on how to use cookies. You've seen how to set cookies and read them back in, using separate pages or the same page. You've seen how to specify how long the cookie should exist, what its name should be, and what its value should be. As you can see, cookies are great for tracking individual users—after all, you're storing data on the user's computer; how much more tracking do you need?

It turns out that you might indeed need more tracking—you might want to preserve the data in various variables in your code between user accesses to the page. Cookies can store data as text on the user's computer for you, but what if you want to store your data in objects—and have those objects retain their value between page loadings? For something such as that, you can use sessions.

Using Sessions

Using Sessions

This is very different from writing a standard program, where you're interacting with the user while the program is running, so you can store data in variables and count on it not being reset to its default values the next time you look at that data. Using sessions, you actually can do the same thing in JSP—you can interact with the user as though you have a session going.

What does that mean? During the time a session is active, you can store data in the session, and it'll be preserved on the server in between times the user accesses your page. You can set your variables in one page access, and they'll hold the same data the next time you see the page, as long as the session hasn't timed out (see “Setting Session Timeouts” later today). The default time Tomcat allows between page accesses in a session is 30 minutes.

Using Sessions

Note

You should realize that it might not be possible for Tomcat to set up a session with the browser. Tomcat usually uses cookies to store session information, but the browser may have cookies turned off, for example (in that case, Tomcat tries to encode the needed information in URLs, but sometimes that is not successful). If Tomcat is not able to create a session with the browser, the isNew method will keep returning true every time the page is accessed, and the session ID will be different for each page access. You can also use the isRequestedSessionIdFromURL and isRequestedSessionIdFromCookie methods to see how Tomcat is storing session information—see Table 4.2.

Those are just a few of the methods of the javax.servlet.http.HttpSession interface—you can see them in Table 7.4.

Table 7.4. javax.servlet.http.HttpSession Methods

Method

Does This

void addCookie(Cookie cookie)

Adds the specified cookie to the response object.

java.lang.Object getAttribute (java.lang.String name)

Returns the object of the given name in this session.

java.util.Enumeration getAttributeNames()

Returns a Java Enumeration of String objects containing the names of all the objects in this session.

long getCreationTime()

Returns the time when this session was created (measured in milliseconds since midnight January 1, 1970 GMT).

java.lang.String getId()

Returns a string containing the identifier for this session.

long getLastAccessedTime()

Returns the last time the client sent a request in with this session, as the number of milliseconds since midnight January 1, 1970 GMT.

int getMaxInactiveInterval()

Returns the maximum time, in seconds, which the server will keep this session open between client accesses.

ServletContext getServletContext()

Returns the ServletContext to which this session belongs.

HttpSessionContext getSessionContext()

As of servlet specification version 2.1, this method is deprecated.

java.lang.Object getValue(java.lang.String name)

Deprecated. As of servlet specification version 2.2, this method is replaced by getAttribute(java.lang.String).

java.lang.String[] getValueNames()

Deprecated. As of servlet specification version 2.2, this method is replaced by getAttributeNames().

void invalidate()

Invalidates this session.

boolean isNew()

Returns true if the client does not yet know about the session.

void putValue(java.lang.String name, java.lang.Object value)

Deprecated. As of servlet specification version 2.2, this method is replaced by setAttribute(java.lang.String, java.lang.Object).

void removeAttribute(java.lang.String name)

Removes the object with the specified name from this session.

void removeValue(java.lang.String name)

As of servlet specification version 2.2, this method is replaced by removeAttribute(java.lang.String).

void setAttribute(java.lang.String name, java.lang.Object value)

Connects an object to this session, using the given name.

void setMaxInactiveInterval(int interval)

Specifies the time, in seconds, between client requests before the server will invalidate this session.

Creating a Session

This is all best seen in an example. This next example will show how to store the number of times the user has accessed the page in the current session, as well as how to get the session ID, when the session was created, and the last time the page was accessed in the current session. This example starts with the page directive first discussed in Day 1, “Getting Started!,” with the directive's session attribute set to true:

<%@page import = "java.util.*" session="true"%> 

This makes sure that opening this page starts a new session if such a session doesn't already exist. Technically speaking, this page directive is not necessary, because the default for the session attribute is true, but it's included here just for completeness (you can omit it in your own session-based code).

This example will keep track of the number of times the user has viewed the current page in a session attribute named counter. The first thing to do is see if this attribute has already been set in a former page access in this session, which you can do with the getAttribute method.

Here's something to note—you can't store the basic data types such as int in session attributes—you can only store Java objects, which are based on the java.lang.Object class (all Java objects are based on the same class). String objects are fine to store as attributes—but what about integer values such as our counter value? Java has a class to match all the basic data types—Integer for int values, Double for double values, and so on. You can create an object using these classes by passing a string (like 3) to the class's constructor, or by passing a value of the corresponding data type to the class's constructor (for example: Integer integerObject = new Integer(3) or Double doubleObject = new Double(3.14)). You can recover the data in the corresponding basic data form with the intValue method of the Integer class, doubleValue method of the Double class, and so on.

The counter variable will be stored as an Integer object, so here's how you can read its value from the session object using the getAttribute method:

<%@page import = "java.util.*" session="true"%> 
<HTML>
    <HEAD>
        <TITLE>Using Sessions</TITLE>
    </HEAD>

    <BODY>
        <%
        Integer counter =
            (Integer)session.getAttribute("counter");
        .
        .
        .

If counter has not been set before, getAttribute will return a value of null. That means you can create the counter value, or increment it if it already exists, and store the new value in the session object like the following:

<%@page import = "java.util.*" session="true"%> 
<HTML>
    <HEAD>
        <TITLE>Using Sessions</TITLE>
    </HEAD>
<BODY>
    <%
    Integer counter =
        (Integer)session.getAttribute("counter");
    if (counter == null) {
        counter = new Integer(1);
    } else {
        counter = new Integer(counter.intValue() + 1);
    }

    session.setAttribute("counter", counter);
    .
    .
    .

That way you can store and retrieve data in the session object. You can also get the current session ID with the getID method. You get the time the session was created with the getCreationTime method, and you get the time the session was last accessed with the getLastAccessedTime method. You can see all this at work in Listing 7.5.

Example 7.5. Creating and Using a Session (ch07_05.jsp)

<%@page import = "java.util.*" session="true"%>
<HTML>
    <HEAD>
        <TITLE>Using Sessions to Track Users</TITLE>
    </HEAD>

    <BODY>
        <%
        Integer counter =
            (Integer)session.getAttribute("counter");
        if (counter == null) {
            counter = new Integer(1);
        } else {
            counter = new Integer(counter.intValue() + 1);
        }

        session.setAttribute("counter", counter);
        %>
        <H1>Using Sessions to Track Users</H1>
        Session ID: <%=session.getId()%>
        <BR>
        Session creation time: <%=new Date(session.getCreationTime())%>
        <BR>
        Last accessed time: <%=new Date(session.getLastAccessedTime())%>
        <BR>
        Number of times you've been here: <%=counter%>
    </BODY>
</HTML>

You can see the results in Figure 7.6, where the user has opened this page and reloaded it a number of times.

Creating and using a session.

Figure 7.6. Creating and using a session.

Using sessions such as this is great for storing and recovering data—it provides you with an environment much like a standard program, where you interact with the user without having to worry about having your data reset.

Setting Session Timeouts

You can use methods of the session object to set the maximum time between page accesses before the server ends the session:

  • getMaxInactiveInterval()—. Returns the maximum time interval, in seconds, for which the server will keep this session open between accesses.

  • setMaxInactiveInterval(int interval)—. Specifies the time, in seconds, between user requests before the servlet container will invalidate this session.

If you set the lifetime of a session to -1, the session will never expire.

The default timeout between user accesses for sessions in Tomcat is 30 minutes. You can change this in Tomcat's web.xml file (stored as jakarta-tomcat-4.0.3confweb.xml). All you have to do is change the time stored in the <session-timeout> element:

<!-- ==================== Default Session Configuration ================= --> 

<!-- You can set the default session timeout (in minutes) for all newly   -->
<!-- created sessions by modifying the value below.                       -->

<session-config>
  <session-timeout>30</session-timeout>
</session-config>

Besides sessions, you can also use applications.

Using Applications

A session enables you to track one user at a time—an application enables you to track all JSPs in the same site, no matter how many users are using them. To access the current application, you can use the built-in JSP application object. Like the session object, the application object is based on the javax.servlet.http.HttpSession interface. In the previous example, you saw how to create a session attribute named counter, which stores the number of times the user has visited the page in the current session. In the same way, you can create an application attribute named applicationCounter that holds the total number of times anyone in the same application has viewed a JSP page:

Integer applicationCounter = (Integer)application.getAttribute("applicationCounter"); 
if (applicationCounter == null) {
    applicationCounter = new Integer(1);
} else {
    applicationCounter = new Integer(applicationCounter.intValue() + 1);
}

application.setAttribute("applicationCounter", applicationCounter);

You can see this at work in Listing 7.6, where the code supports a counter for the number of visits in the current session, and in the current application.

Example 7.6. Using the Application Object (ch07_06.jsp)

<HTML>
    <HEAD>
        <TITLE>Using the Application Object</TITLE>
    </HEAD>

    <BODY>
        <H1>Using the Application Object</H1>
        <%
        Integer counter = (Integer)session.getAttribute("counter");
        String heading = null;
        if (counter == null) {
            counter = new Integer(1);
        } else {
            counter = new Integer(counter.intValue() + 1);
        }

        session.setAttribute("counter", counter);

        Integer applicationCounter = (Integer)application.getAttribute("applicationCounter");
        if (applicationCounter == null) {
            applicationCounter = new Integer(1);
        } else {
            applicationCounter = new Integer(applicationCounter.intValue() + 1);
        }

        application.setAttribute("applicationCounter", applicationCounter);
        %>

        You have visited this page <%=counter%> times.
        <BR>
        This page has been visited by all users <%=applicationCounter%> times.
    </BODY>
</HTML>

In this example, the session counter keeps track of the number of times a user has visited the page, and the application counter keeps track of the number of times all users have accessed the page. This isn't particularly easy to see on the same computer, because Tomcat will count you as the same user. However, you can get around that if you happen to have different browsers. For example, you can open it in Internet Explorer and reload a few times, as you see in Figure 7.7. If you then open it in another browser, such as Netscape Navigator, you'll see that the application counter is indeed keeping track of users across sessions, as shown in Figure 7.8.

Using the application object.

Figure 7.7. Using the application object.

Another user using the application object.

Figure 7.8. Another user using the application object.

Using Sessions, Applications, and JavaBeans

Using Sessions, Applications, and JavaBeans

The bean you see in Listing 7.7 maintains a property named counter that JSP code can increment—we'll see that using page scope, counter is reset to 1 each time the page loads, but using session scope, counter will increment to 2, 3, 4, and so on as you reload the page, because the bean is stored in the session's data.

Example 7.7. A Bean That Maintains a Usage Counter (ch07_07.jsp)

package beans;

public class ch07_07
{

    private int counter = 0;

    public void setCounter(int value)
    {
        this.counter = value;
    }

    public int getCounter()
    {
        return this.counter;
    }

    public ch07_07()
    {
    }
}

You can see a JSP page that uses this bean with page scope in Listing 7.8.

Example 7.8. Using Page Scope for Beans (ch07_08.jsp)

<HTML>
    <HEAD>
        <TITLE>Using Beans and Page Scope</TITLE>
    </HEAD>

    <BODY>
        <H1>Using Beans and Page Scope</H1>

        <jsp:useBean id="bean1" class="beans.ch07_07" scope="page" />
        <%
        bean1.setCounter(bean1.getCounter() + 1);
        %>
        The counter value is: <jsp:getProperty name="bean1" property="counter" />
    </BODY>
</HTML>

And you can see that Web page at work in Figure 7.9—no matter how many times you reload this page, the counter will remain set to 1, because the bean has page scope, so it's created anew each time you load the page.

Using a bean with page scope.

Figure 7.9. Using a bean with page scope.

However, if you give the bean session scope, as in Listing 7.9, it's stored with the rest of the session, which means the counter value will be preserved between page accesses.

Example 7.9. Using Session Scope for Beans (ch07_09.jsp)

<HTML>
    <HEAD>
        <TITLE>Using Beans and Session Scope</TITLE>
    </HEAD>

    <BODY>
        <H1>Using Beans and Session Scope</H1>

        <jsp:useBean id="bean1" class="beans.ch07_07" scope="session" />

        <%
        bean1.setCounter(bean1.getCounter() + 1);
        %>
        The counter value is: <jsp:getProperty name="bean1" property="counter" />
    </BODY>
</HTML>

You can see the results of giving the bean session scope in Figure 7.10.

Using a bean with session scope.

Figure 7.10. Using a bean with session scope.

Summary

Today you learned how to track users with cookies and sessions in JSP. Everything started by using HTML hidden controls to store data in the Web page sent to the browser and then sent back to the server. Although storing data in hidden controls works, it's not very secure, and the data stored in those controls is visible if the user views the page's HTML source.

You learned that you can use cookies to store text data on a person's computer, using Cookie objects and the response object's addCookie method. You can retrieve those objects with the request object's getCookies method.

To support a session, you use the session object. As you've seen, you can get the session's ID, creation time, last accessed time, and more using session methods. Sessions let you establish a workable connection with the user's browser, letting you store data between page accesses.

You can also use application objects to store data; an application is broader than a session, because sessions deal with a single user, but an application includes all the users using JSP pages on your site.

Finally, you learned that you can store beans in sessions and applications if you set the scope attribute <jsp:useBean> to the appropriate values.

Q&A

Q1:

Are there any drawbacks to using sessions?

A1:

Yes, they put a considerable strain on the resources of the server if there are many sessions running at the same time. They can also be broken unexpectedly if the user's connection fails. All in all, in professional JSP applications, you must be prepared for cases when using a session with the user doesn't work.

Q2:

Can I store other data in cookies besides the cookie's name, maximum age, and value?

A2:

Yes, you can also use the Cookie object's setComment and getComment methods to store a comment—a String object—in the cookie. This comment can explain the purpose of the cookie, for example.

Workshop

This workshop tests whether you understand all the concepts you learned today. It's a good idea to master today's concepts by honing your knowledge here before starting tomorrow's material. You can find the answers to the quiz questions in Appendix A.

Quiz

1:

What are the names of the Cookie object methods you use to find a cookie's name and value?

2:

What is the default timeout for a session in the Tomcat server?

3:

How do you know if Tomcat can't establish a session with the user's browser?

4:

What possible scopes can you use with JavaBeans in JSP?

5:

What is the default setting for the page directive's session attribute?

Exercises

1:

Create a sample home page that accepts a person's name and birthday using text fields (use text fields for the name, birth month, and birth day) and stores that information using a cookie that lasts a year. Then use the Date and Calendar classes you saw in Day 6, “Creating JSP Components: JavaBeans,” to display a greeting to the person on his birthday.

2:

Try repeating the JavaBean example in the topic “Using Sessions, Applications, and JavaBeans,” but this time, give the bean application scope to create a Web page counter that uses the counter in the bean to indicate the total number of times the page has been accessed by anyone, and then test it out. Also, use the application object's setMaxInactiveInterval method to set the application timeout to a second or two and watch what happens to the counter as the application times run out over repeated page reloads.

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

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