In this chapter
Web programmers often need to keep track of data between user requests. Given what you already know about JSP, servlets, and HTML forms, you already have the ability to keep track of data between requests. You can store user data in hidden form variables.
Although not the most elegant solution, form variables are used by many applications to store user data. The idea is that every time the user submits a form, it contains some hidden variables that contain information about the user. These variables might be a login ID and password or the user's name. The big hassle with this method is that all your forms must preserve these hidden variables and continue to pass them around.
The best way to illustrate this technique is with an example. Listing 5.1 shows a login form that calls a JSP to handle the login.
Example 5.1. Source Code for Login.html
<HTML> <BODY bgcolor="#ffffff"> <H1>Login</H1> Please log in <FORM action="Login.jsp" method="POST"> <TABLE> <TR><TD>User Name:<TD><INPUT type="text" name="username"> <TR><TD>Password:<TD><INPUT type="password" name="password"> </TABLE> <P> <INPUT type="submit" value="Login!"> </FORM> </BODY> </HTML>
The goal of this example is to preserve the username across multiple pages. Obviously the Login.jsp page will have the username because it's passed as a form variable from Login.html. Listing 5.2 shows Login.jsp. Notice that it inserts the username as a hidden form variable.
Example 5.2. Source Code for Login.jsp
<HTML> <BODY bgcolor="#ffffff"> <% // Get the login information String userName = request.getParameter("username"); String password = request.getParameter("password"); %> Welcome, <%=userName%>! <FORM action="/servlet/usingjsp.ColorServlet" method="POST"> <%-- Save the username in a hidden form variable --%> <INPUT type="hidden" name="username" value="<%=userName%>"> <P> Please enter your favorite color: <SELECT name="color"> <OPTION value="blue" SELECTED>Blue</OPTION> <OPTION value="red">Red</OPTION> <OPTION value="green">Green</OPTION> <OPTION value="yellow">Yellow</OPTION> <OPTION value="mauve">Mauve</OPTION> </SELECT> <P> <INPUT type="submit" value="Choose color!"> </FORM> </BODY> </HTML>
Figure 5.1 shows the output from Login.jsp.
Just so you don't think servlets have been cut out of the loop here, the third part of this example is a servlet that receives the hidden form variable along with the user's color choice. Listing 5.3 shows the servlet.
Example 5.3. Source Code for ColorServlet.java
package usingjsp; import javax.servlet.*; import java.io.*; public class ColorServlet extends GenericServlet { public void service(ServletRequest request, ServletResponse response) throws IOException { // Tell the Web server that the response is HTML response.setContentType("text/html"); // Get the PrintWriter for writing out the response PrintWriter out = response.getWriter(); // Fetch the username and color parameters String userName = request.getParameter("username"); String color = request.getParameter("color"); // Write the HTML back to the browser out.println("<HTML>"); out.println("<BODY bgcolor= "#ffffff">"); out.println("Well, I see that "+userName+ "'s favorite color is "+color+"."); out.println("</BODY>"); out.println("</HTML>"); } }
One of the reasons you don't see hidden variables used very often in commercial Web sites, especially e-commerce sites, is that they are inherently insecure. Suppose Login.jsp actually verified the username and password. You would assume that the username passed to ColorServlet
is valid. There is nothing to stop someone from inserting their own username and even a bizarre color by passing it in the URL for the servlet. Figure 5.2 shows an example of how the system can be tricked. Notice that the phony username and color are embedded into the URL.
Changing a username is bad enough, but imagine what could happen if someone did this with a bank account or credit card number! Certainly this technique needs some work. You could get clever and choose a variable name that is far less obvious than "username
". Suppose, for example, that you changed the name of the hidden variable to "xpq7564HHgk
". Surely no one would guess the variable name! Unfortunately, all someone needs to do is ask the browser to display the source for the page, as shown in Figure 5.3.
Figure 5.3. Because a user can view the source to a page, you can't safely hide anything in the page.
Another big concern with hidden form variables is that the user might accidentally bookmark the secure information. When you submit a form using an HTTP GET
method (setting method="get"
in your <form>
tag), the form variables all appear in the URL and will be part of a bookmark if the user bookmarks the page. Even hidden form variables show up in the URL. If you use hidden form variables, even storing a single value, make sure you use an HTTP POST
to keep the hidden information from being bookmarked.
Now, suppose you decide to store information on the server instead of trying to save all the data in hidden form variables. When a request comes in from a browser, how will you know what information goes with which client browser? To solve this problem, the browser must identify itself somehow.
You need to store one piece of data on the client: a key that uniquely identifies the browser and helps you remember where the user's data is stored. In other words, you get some data from the client, you store it in a hash table using some random key, and then send that key back to the browser in a hidden field. The next time the user fills out a form, the browser sends the server the hidden key field along with the other form variables. Your code on the server takes that key, looks in the hash table, and pulls out the user's data.
Storing data this way is much more secure than putting the data straight into hidden fields. Now if someone wants to break the system and tamper with the data, the best he can do is change the key. If the key value is large enough, it's unlikely that the hacker will be able to guess someone else's random key. He certainly won't be able to send you phony data, because the data stays on the server.
Listing 5.4 shows you a Java class that implements the key generation and data storage for keeping track of user data.
Example 5.4. Source Code for UserDataTable.java
package usingjsp; import java.util.*; public class UserDataTable { protected static Hashtable userData = new Hashtable(); protected static Random keyGenerator = new Random(); /** Creates a new table for a user's data and returns the key for * the user's data. */ public static String createUserData() { // Create a random key for the user's data String userKey = ""+keyGenerator.nextLong(); // Create a hash table for the user's data and store it userData.put(userKey, new Hashtable()); return userKey; } /** Returns the user data table for a particular user */ public static Hashtable getUserData(String userKey) { if (userKey == null) return null; return (Hashtable) userData.get(userKey); } /** Destroys the user data table for a particular user */ public static void clearUserData(String userKey) { if (userKey == null) return; userData.remove(userKey); } }
To make use of this new UserDataTable
class, you need to change the Login.jsp file to store the username in the user data table instead of a hidden frame. Listing 5.5 shows how Login.jsp can support this new storage method with very few changes.
Example 5.5. Source Code for Login2.jsp
<%@ page language="java" import="java.util.*,usingjsp.*" %> <HTML> <BODY bgcolor="#ffffff"> <% // Get the login information String userName = request.getParameter("username"); String password = request.getParameter("password"); String userKey = UserDataTable.createUserData(); Hashtable userData = UserDataTable.getUserData(userKey); userData.put("username", userName); %> Welcome, <%=userName%>! <FORM action="/servlet/usingjsp.ColorServlet2" method="POST"> <%-- Save the username in a hidden form variable --%> <INPUT type="hidden" name="userkey" value="<%=userKey%>"> <P> Please enter your favorite color: <SELECT name="color"> <OPTION value="blue" SELECTED>Blue</OPTION> <OPTION value="red">Red</OPTION> <OPTION value="green">Green</OPTION> <OPTION value="yellow">Yellow</OPTION> <OPTION value="mauve">Mauve</OPTION> </SELECT> <P> <INPUT type="submit" value="Choose color!"> </FORM> </BODY> </HTML>
The main difference between Login.jsp and Login2.jsp is that Login2.jsp creates a user data table and stores the key for that table in a hidden field. Notice that Login2.jsp does not send the username back to the browser in a hidden field. All you need now is to modify the ColorServlet
program to fetch the username from the user data table instead of from the hidden field. Listing 5.6 shows the modified ColorServlet
that uses the user data table.
Example 5.6. Source Code for ColorServlet2.java
package usingjsp; import javax.servlet.*; import java.io.*; import java.util.*; public class ColorServlet2 extends GenericServlet { public void service(ServletRequest request, ServletResponse response) throws IOException { // Tell the Web server that the response is HTML response.setContentType("text/html"); // Get the PrintWriter for writing out the response PrintWriter out = response.getWriter(); // Fetch the user key and color parameters String userKey = request.getParameter("userkey"); String color = request.getParameter("color"); Hashtable userData = UserDataTable.getUserData(userKey); // If the user data table isn't found, someone probably monkeyed with // the key value. if (userData == null) { out.println("<HTML><BODY>"); out.println("<H1>Sorry</H1>"); out.println("The system is experiencing problems."); out.println("</BODY></HTML>"); return; } // Now try to get the username from the table String userName = (String) userData.get("username"); // Write the HTML back to the browser out.println("<HTML>"); out.println("<BODY bgcolor= "#ffffff">"); out.println("Well, I see that "+userName+ "'s favorite color is "+color+"."); out.println("</BODY>"); out.println("</HTML>"); } }
This method of storing data makes one assumption that you can't overlook: The servlet and Java Server Page must be running within the same Java Virtual Machine (JVM). The key to preserving the data is that the UserDataTable
class uses static data. If the servlet runs in one JVM while the Java Server Page runs in another JVM, they will be using separate copies of the UserDataTable
class, and thus will not share any data. If you ever decide to use a technique like this, make sure that everything is running within the same JVM. Most servlet and JSP engines on the market today run within a single JVM.
The hidden form variable approach seems to work fairly well except for one thing: the hidden variable itself. First of all, putting the hidden variable in every form is a hassle. Second, it requires the browser to use forms only as a method of accessing server-side pages. If you use a hyperlink, there are no form variables to pass. You must either rewrite your hyperlinks to include something like "?userkey=9345837479" or find a better alternative. That alternative is the session
object.
One thing you need to realize when dealing with the Web is that there is no permanent connection between the browser and the Web server. If you have done database programming or socket programming, you are familiar with the concept of a session: an active connection between two participants.
The HTTP protocol used by the browser and the Web server is not session-oriented. When the browser needs a page from the Web server, it opens a connection, retrieves the page, and then closes the connection. Because there is no active connection, the Web server has no idea what is happening on the browser. The browser could crash or the entire client computer could be turned off, and the Web server would be oblivious.
That being said, servlets and Java Server Pages do have a notion of a session. Near the end of the discussion on hidden form variables, you saw a technique in which data is stored on the server, referenced by a single key that was stored on the client. Servlets and Java Server Pages use a very similar technique, which is implemented by the HttpSession
object.
The beauty of the HttpSession
object is that it does not rely on hidden form variables and works even if a servlet or JSP is accessed via a hyperlink. The reason HttpSession
is able to work without hidden form variables is that it uses something called a cookie to store the user's session key. A cookie contains a piece of data that the server sends to the browser and that the browser sends back to the server with each request. You will learn much more about cookies in Chapter 8, "More About Saving Data."
→ To learn more about cookies, see "Storing Data in a Cookie,".
The Java Server Pages API has several built-in objects. You have already seen two of them: request
and out.
The next important one is called session
, and it's an instance of HttpSession.
The three methods that you use the most in the session
object are getAttribute, setAttribute,
and removeAttribute.
The declarations for these methods are
public void setAttribute(String name, Object value) throws IllegalStateException public Object getAttribute(String name) throws IllegalStateException public void removeAttribute(String name, Object value) throws IllegalStateException
These methods act much like the get
and put
methods in the Hashtable
class. That is, setAttribute
associates a name with a value, and getAttribute
returns the value associated with a name or null
if there is no value associated. For example, to store some data in a session, you would do something like this:
session.setAttribute("someKey", "here is my data");
To retrieve the data back out of the session, you would do something like this:
String myData = (String) session.getAttribute("someKey");
The getAttribute,
setAttribute,
and removeAttribute
methods were added to the Servlet API in version 2.2. Prior to version 2.2, these methods were called getValue,
putValue,
and removeValue
(with the same parameters). Although getValue,
putValue,
and removeValue
are supported under version 2.2 of the Servlet API, they are deprecated. Only use them if your servlets must run under Servlet API version 2.1 or earlier.
IllegalStateException
is thrown when you try to get or set an attribute on an invalid session. A session becomes invalid either when you call its
invalidate
method or after the session has timed out. The servlet engine keeps track of how long it has been since a session has been accessed; after a certain period of inactivity, the session is marked as invalid. You can configure the amount of time it takes to time out a session, either on a per-session basis or for all sessions.
The Servlet API specifies a way for you to control the timeout period on a per-session basis. Most servlet engines also provide a way for you to specify a default timeout length, but they are not required to by the Servlet API.
Listing 5.7 shows the Login.jsp page modified to support the session
object instead of the UserDataTable
class. Notice that it no longer needs to use the hidden form variable.
Example 5.7. Source Code for Login3.jsp
<%@ page language="java" import="java.util.*,usingjsp.*" %> <HTML> <BODY bgcolor="#ffffff"> <% // Get the login information String userName = request.getParameter("username"); String password = request.getParameter("password"); // Store the username in the session session.setAttribute("username", userName); %> Welcome, <%=userName%>! <FORM action="/servlet/usingjsp.ColorServlet3" method="POST"> <P> Please enter your favorite color: <SELECT name="color"> <OPTION value="blue" SELECTED>Blue</OPTION> <OPTION value="red">Red</OPTION> <OPTION value="green">Green</OPTION> <OPTION value="yellow">Yellow</OPTION> <OPTION value="mauve">Mauve</OPTION> </SELECT> <P> <INPUT type="submit" value="Choose color!"> </FORM> </BODY> </HTML>
If you are having trouble storing or retrieving your session information, see "Storing and Retrieving Data," in the "Troubleshooting" section at the end of this chapter.
You have probably guessed this already, but the session
object you use in a servlet is identical to the one you use in a Java Server Page. The only difference is that it isn't already conveniently sitting around in a variable named session.
Instead, you must get the session
object from the request
object.
Java Server Pages also get the session
object from the request
object. The only reason you don't notice is that the JSP compiler automatically generates code to fetch the session
object and put it in a variable named session.
To get the session
object from the request
object, just call the getSession
method:
HttpSession session = request.getSession();
Inside a servlet, you use the same getAttribute
and setAttribute
methods to update session variables as you do in a Java Server Page. After all, the session
object is an instance of HttpSession
in both a servlet and a JSP.
Because the servlet engine needs to send a session cookie back to the browser, make sure you get the session
object before you start sending a response back to the browser. Otherwise, it might be too late for the servlet engine to send back the cookie, because the cookie must be sent back in the header portion of the response. In a JSP, the session
object is usually available immediately. You really only need to worry about this inside a servlet.
Listing 5.8 shows the modifications necessary to ColorServlet
to make it use HttpSession
instead of the UserDataClass.
Also notice that unlike the previous versions of ColorServlet,
this one is a subclass of HttpServlet
(the others were subclasses of GenericServlet
). The method signature on the service method is a little different now, too, because the request
and response
parameters are now instances of HttpServletRequest
and HttpServletResponse.
Example 5.8. Source Code for ColorServlet3.java
package usingjsp; import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import java.util.*; public class ColorServlet3 extends HttpServlet { public void service(HttpServletRequest request, HttpServletResponse response) throws IOException { // Tell the Web server that the response is HTML response.setContentType("text/html"); // Get the PrintWriter for writing out the response PrintWriter out = response.getWriter(); // Fetch the color parameter String color = request.getParameter("color"); // Get the username from the session HttpSession session = request.getSession(); String userName = (String) session.getAttribute("username"); // Write the HTML back to the browser out.println("<HTML>"); out.println("<BODY bgcolor= "#ffffff">"); out.println("Well, I see that "+userName+ "'s favorite color is "+color+"."); out.println("</BODY>"); out.println("</HTML>"); } }
Now that you see that servlets and Java Server Pages can support sessions, you can take a step back and look at how the sessions work. When the servlet engine creates a session, it sends a session identifier (also referred to as a session key earlier in this chapter) back to the browser in the form of a cookie. Again, the cookie is just a piece of information that the browser sends back to the server whenever it asks the server for a page.
Usually, for a session, the cookie disappears when the Web browser is shut down. As you will see in Chapter 8, a browser can save cookies to disk, so when the browser starts up again it still knows about the cookies it had when it shut down. Because sessions are typically short-lived, and because shutting the browser down is an action that warrants the termination of a session, the session cookie is usually not saved to disk. Remember, the server has no idea when the Web browser shuts down. Figure 5.4 illustrates the interaction between the browser and the servlet engine as it relates to cookies and sessions.
When the browser asks the server for a page, the server looks at the session cookie, and then finds the session corresponding to that session identifier. Occasionally, the servlet engine looks through its sessions and gets rid of those that haven't been accessed in a long time. If it didn't do this, eventually the servlet engine would be wasting a lot of memory holding onto sessions that could never be accessed again because the cookies associated with those sessions are long gone (people shut down their browsers eventually, and that kills the session cookies).
When you call the getSession
method to retrieve the current session, the request
object automatically creates a session if one doesn't already exist. In some JSP implementations, the session is created automatically even if you never use it. Most of the time, you don't really care when the session has been created. Other times, however, you need to explicitly reset the existing session and start over.
Suppose, for example, that you have implemented an online shopping site. A user logs on, visits a few pages, and selects several items to buy. You store these items in the user's session as they travel from page to page. Now, suppose the user decides that she doesn't want any of those items, and rather than go through the trouble of removing them from her shopping cart, she decides to just log in to your site again.
If a user comes back into your login page, you probably want to start her over with a clean slate. Although you could design a site that is smart enough to figure out what you were last doing and send you back to where you left off, most people assume that when they come in through the "front door," they are starting over.
Users might go back to the login screen and walk away from the computer, thinking their order is now gone. Imagine their surprise if another user could walk up to the computer, log back in, and have the previous user's order, complete with credit card number.
The getSession
method in the request
object enables you to control the creation of new sessions. When you ask for a session, you can ask that the request object not create a new session if one doesn't already exist. The following segment of code automatically invalidates the previous session and then creates a new one:
// Get the old session, but don't create a session if // one didn't already exist (passing true would allow // creation of a new one). HttpSession oldSess = request.getSession(false); // If there was an old session, invalidate it if (oldSess != null) { oldSess.invalidate(); } // Now create a fresh new session HttpSession session = request.getSession(true);
This code works for both JSP and servlets, except that for a JSP, you shouldn't re-declare a session. Instead, the last line should just read
session = request.getSession(true);
A session can be terminated in two ways: You force the termination by calling the invalidate
method on the session, or the servlet engine times the session out. Depending on the kind of data you store in the session, you might need to perform some kind of cleanup of the session data. For example, you might have a database connection stored in the session, or a connection to an RMI or CORBA service on another machine. Although Java's garbage collector eventually eliminates these resources, you shouldn't keep them open any longer than you need to.
A session
object has a callback mechanism to notify an object when it has been associated with a session and when it is no longer associated with a session. That is, when you call session.setAttribute("someName", someObject),
the session
object can notify the object that it is being associated with a session. When the session terminates, the session
object can notify the object that it is no longer associated with the session.
This notification is on an object-by-object basis. Although it might seem strange at first, the notification technique is actually very flexible. You can write objects that are session-aware and can perform their own cleanup. If you are using standard objects, such as a JDBC Connection
object, you can create a special session cleanup object that releases your database connection.
The HttpSessionBindingListener
interface defines notification methods that the session
object uses to notify objects when they are added to or removed from a session. There are two methods in the interface:
public void valueBound(HttpSessionBindingEvent event); public void valueUnbound(HttpSessionBindingEvent event);
As you might have guessed, valueBound
is called when an object is added to a session; valueUnbound
is called when the object is removed from a session. Listing 5.9 shows an example class that listens for valueBound
and valueUnbound
messages and counts the number of sessions that are bound to it.
Example 5.9. Source Code for BindListener.java
package usingjsp; import javax.servlet.http.*; /** Counts the number of sessions that are bound to this object. */ public class BindListener implements HttpSessionBindingListener { // The current session count protected int numSessions; public BindListener() { numSessions = 0; } // Every time this object is added to a session, // valueBound is called public synchronized void valueBound(HttpSessionBindingEvent event) { numSessions++; } // Every time this object is removed from a session, // valueUnbound is called public synchronized void valueUnbound(HttpSessionBindingEvent event) { numSessions--; } // Returns the current number of bound sessions public int getNumSessions() { return numSessions; } }
To test the BindListener
class, you need to observe what happens when you access it from multiple sessions and also see what happens when you invalidate a session containing a BindListener
object. You should expect to see the session count go up whenever the object is added to a session, and you should see the count go down when the object is removed from a session, or when the session it belongs to is invalidated.
Listing 5.10 shows a test harness JSP that exercises the BindListener
class. By selecting various hyperlinks, you can remove the BindListener
object from the session or invalidate the session.
Example 5.10. Source Code for BindTest.jsp
<%@ page language="java" import="usingjsp.BindListener" %> <HTML> <BODY bgcolor="#ffffff"> <%-- Set up a static BindListener shared by all instances of this JSP. There is probably only one instance, but just in case the server creates multiple instances, this page can handle it. --%> <%! protected static BindListener listener = new BindListener(); %> <% BindListener l = null; // Allow the browser to pass a "removeListener" parameter to remove // a listener from the session if (request.getParameter("removeListener") != null) { session.removeAttribute("listener"); } // Allow the browser to pass a "resetSession parameter to clear out // the session else if (request.getParameter("resetSession") != null) { // See if there is already a session HttpSession oldSession = request.getSession(false); // If there was already a session, invalidate if (oldSession != null) { l = (BindListener) oldSession.getAttribute("listener"); oldSession.invalidate(); // Tell the user that the session was reset and show that the // bind counts have been updated. Make sure that there was a // listener on the old session, too. if (l != null) { %> Your current session was reset. The listener now has <%=l.getNumSessions()%> active sessions.<P> <% } else { %> Your old session didn't have a listener.<P> <% } l = null; } } else { // See if the listener is already in the session l = (BindListener) session.getAttribute("listener"); // If not, add the global copy of the listener to the session if (l == null) { // Put the global listener variable into the session session.setAttribute("listener", listener); l = listener; } } %> <% if (l != null) { %> You have a listener bound to your session. <% } else { %> You do not have a listener bound to your session. <% } %> There are currently <%=listener.getNumSessions()%> sessions holding onto the bind listener. <P> <TABLE> <TR> <TD> <A href="BindTest.jsp">Refresh Form</A> <TD> <A href="BindTest.jsp?removeListener">Remove Listener</A> <TD> <A href="BindTest.jsp?resetSession">Reset Session</A> </TABLE> </BODY> </HTML>
Figure 5.5 shows several browser sessions running BindTest.jsp.
Normally, JSP and servlet sessions rely on the HTTP cookie mechanism to preserve the session identifier between requests. Cookies are really nice for doing things such as sessions and online ordering. Unfortunately, cookies have also been abused. Many Web sites store personal information in cookies, and many Web users don't like their personal information being sent to another Web server without their knowledge. To put it simply, cookie abuse has given cookies a bad name.
Many users now disable cookies within their browsers. You might think that with cookies disabled, the only way to keep track of session information would be the hidden field technique discussed at the beginning of this chapter. Fortunately, there is another solution.
If you knew the session ID, you could pass it as a parameter to all your servlets and Java Server Pages. The HttpSession
object contains a getId
method, so you could pass it around. Now all you need is a way to take a session ID and find the session with that ID. In version 2.1 of the Servlet API, there was a way to locate a session by ID (the getSession
method in the HttpSessionContext
object). Unfortunately, the HttpSessionContext
class has been deprecated for version 2.2 of the Servlet API, meaning the class might be removed from future versions of the Servlet API.
You don't need to go through the trouble of tracking the session ID, however. The Servlet API provides a way for you to insert a session ID into a URL. The idea is, for every URL in your Web application that refers to a servlet or a JSP, you insert the session ID as a parameter to that servlet or JSP. Because the session ID is normally stored in a cookie, you only need pass the session ID as a parameter when cookies are disabled.
Many Web sites that do session-oriented work require you to enable cookies. Although it's nice to be able to support sessions without cookies, users generally find them acceptable for applications such as online shopping. If you decide to require cookies, you might need to put a note on your Web site explaining the necessity of cookies.
The HttpServletResponse
object (the response
object in a JSP) contains two methods to help you pass the session ID around to different pages:
public String encodeURL(String url); public String encodeRedirectURL(String url);
If you need to do session tracking but the browser doesn't support cookies, encodeURL
and encodeRedirectURL
return a modified URL containing the session ID as a parameter for that URL. If the browser supports cookies, the URL is returned unmodified. Listing 5.11 shows a JSP that presents a form, handles the submission of the form, and puts the form results into a session. It calls encodeURL
and encodeRedirectURL
to make sure that sessions are supported even with cookies turned off.
Example 5.11. Source Code for RewriteDemo.jsp
<HTML> <BODY> <H1>URL Rewriting Demo</H1> <%-- See if the session already contains the name. If so, say "Hello" to the user --%> <% String name = (String) session.getAttribute("name"); if (name != null) { // This user already has a session, show the name and show the list of // items they have entered out.println("Hello, "+name+"!"); %> <A href="<%=response.encodeURL("RewriteDemo2.jsp")%>"> Click here to continue</A> <% } // If name is passed in as a parameter, it must be as a response to // the form input. Put it in the session and redirect it to the second // page. else if (request.getParameter("name") != null) { session.setAttribute("name", request.getParameter("name")); response.sendRedirect(response.encodeRedirectURL( "RewriteDemo2.jsp")); } else { %> <FORM ACTION="<%=response.encodeURL("RewriteDemo.jsp")%>"> Please enter your name: <INPUT type=text name="name"> <P> <INPUT type="submit" value="Login!"> </FORM> <% } %> </BODY> </HTML>
Figure 5.6 shows RewriteDemo2.jsp, which RewriteDemo.jsp redirects the user to. Notice that the address line contains an embedded session ID. The session ID appears because the browser in this situation has cookies turned off.
If you are having trouble with URL rewriting, see "URL Rewriting" in the "Troubleshooting" section at the end of this chapter.
To disable cookies in Internet Explorer, you must change the security level for your Internet zone. Internet explorer groups Web sites into four zones: Local Intranet, Internet, Trusted Sites, and Restricted Sites. To change the security settings for a zone, go to the IE menu and select Tools-Internet Options and then click the security tab. You should see a dialog box like the one shown in Figure 5.7.
You can change the setting on each zone to a different level (high, medium, medium-low, and low). The high setting disables cookies. If you are testing with the Web site on your own machine, you must change the setting for the Local Intranet zone. If you are testing with another machine, you will probably need to change the setting for the Internet zone. Just move the slider on the security dialog box up to high.
TO disable cookies in Netscape, click the Edit menu and select Preferences. Then, select Advanced in the dialog box. You should see a dialog box similar to the one shown in Figure 5.8. Click the Do Not Accept or Send Cookies button.
Figure 5.8. To change the cookie settings in Netscape, go to the Preferences dialog box and select Advanced.
If you are having trouble disabling or enabling cookies in your browser, see "Cookie Settings" in the "Troubleshooting" section at the end of this chapter.
Unfortunately, to make full use of URL rewriting, you must pass all your pages through the URL rewriting process. In other words, if you have a static HTML page with links to Java Server Pages or servlets that needs session information, you must turn these static HTML pages into Java Server Pages that use encodeURL
to rewrite the HREF
values for all the hyperlinks. So, in your HTML file where you have a line like
<a href="CallMe.jsp">
the JSP file would read
<a href="<%=response.encodeURL("CallMe.jsp")%>">
You also need to change the action
attributes in each of your <FORM>
tags. A <FORM>
tag with an action of "HandleForm.jsp" appears in the JSP like this:
<form action="<%=response.encodeURL("HandleForm.jsp")%>">
Modifying your Web site to rewrite all your forms and hyperlinks is a difficult task. Try to design your site so that you can minimize the amount of rewriting necessary.
The HttpSession
class stores data items on a per-user basis. Sometimes, however, you have data that you need to share between various servlets and Java Server Pages that doesn't need to be stored for each user. For example, if you are writing a database application, you might need to share a database connection. From a Java Server Page, you can store data in the application
object. The methods for storing data in the application
object are identical to the ones for the session
object:
public void setAttribute(String name, Object value) public Object getAttribute(String name) public void removeAttribute(String name, Object value)
From a JSP, if you want to store information in the application
object with a name of myInformation,
you make a call like this:
application.setAttribute("myInformation", "Here is the info");
To get the information back out of the application
object, you call getAttribute
:
String theInfo = (String) application.getAttribute("myInformation");
The application
object is really an object that implements the ServletContext
interface. The servlet context is also available from within the servlet. If your servlet is a subclass of GenericServlet
or HttpServlet,
as most are, you can call the getServletContext
method:
ServletContext context = getServletContext(); context.setAttribute("myInformation", "Here is the info");
Remember that your servlet doesn't have to be a subclass of GenericServlet
or HttpServlet.
You could choose to write your own class that implements the Servlet
interface. If you need to get hold of the servlet context in these cases, the context is contained in the ServletConfig
object that is passed to your servlet's init
method. You can always call getServletConfig().getServletContext()
to get the servlet context.
From all appearances, the application
object seems like overkill. What is the difference between storing something in the application
object and storing it in a static variable somewhere? You will see in Chapter 28, "Packaging a JSP Application," that it's possible to group a set of Java Server Pages and servlets into an application. The servlet engine knows what application a particular JSP or servlet belongs to. You could, for example, have a set of Java Server Pages deployed in a server under an application called "QA" and an identical set of JSPs under an application called "Beta" . These two applications, although running in the same server and the same Java Virtual Machine, would have different application
objects (that is, different ServletContext
objects).
Now you can see how this differs from a static variable. If you tried to store a data item in a static variable, you would circumvent the notion of separate applications. There is only one copy of a static variable within a single Java Virtual Machine. You can't say that the "QA" application gets its own copy of a static variable and the "Beta" application gets another unless you are somehow able to run each application in a separate virtual machine. Because you can't count on a servlet engine to support multiple JVMs, you shouldn't rely on static variables for application-level data sharing.
I turned off cookies in Internet Explorer; why don't I see the session ID when I use URL rewriting? | |
A1: | Make sure you have turned off cookies for the security zone you are using. If you are accessing your local machine, you need to change the security setting for the Local Intranet zone, at least if you use http://localhost as the first part of your URL. Internet Explorer will not always notice that a URL is really part of the local intranet, however. It may consider http://localhost as being in the local domain, and think that http://zinger.wutka.com is in the Internet zone, even though it is the same machine as |
18.191.105.15