用户通过浏览器访问Web应用时,通常情况下,服务器需要对用户的状态进行跟踪。例如,用户在网站结算商品时,Web服务器必须根据请求用户的身份,找到该用户所购买的商品,在Web开发中,服务器跟踪用户信息的技术称为会话技术。
两人通电话,一连串的你问我答就是的过程就是一个会话,Web应用中的会话过程类似于生活中的打电话过程,即指一个客户端(浏览器)与Web服务器之间连续发生的一系列请求和响应过程。
用户甲和用户乙分别登录了购物网站,甲购买了一个粪叉手机,乙购买了一个平板,当他们结账时,Web服务器根据甲乙的信息分别进行保存,我们知道HttpServletRequest对象和ServletContext对象都可以对数据进行保存,但是他们都做不到,为什么?
(1)客户端请求Web服务器时,针对每次HTTP请求,Web服务器都会创建一个HttpServletRequest对象,该对象只能保存本次请求所传递的数据,由于购买和结账是两个不同的请求,因此再发送结账请求时,之前购买请求中的数据会丢失。
(2)使用ServletContext对象保存数据时,由于一个Web应用共享的是同一个ServletContext对象,因此,当用户发送结账请求时,由于无法区分哪些商品时哪个用户的所购买的,而会将该购物网站中所有用户购买的商品进行结算,这不成了冤大头了。
因此,为了保存会话过程中产生的数据,在Servlet技术中,提供了两个用于保存会话数据的对象,分别是Cookie和Session。
Cookie
Cookie是一种会话技术,它用于将会话过程中的数据保存到用户的浏览器中,从而使浏览器和服务器可以更好地进行数据交互。
举个例子,上超市,有会员卡,卡上记录个人信息如姓名,电话,超市根据卡的积分来进行优惠。Cookie的功能就好比于这张会员卡,当用户通过浏览器访问Web服务器时,服务器会给客户端(浏览器)发送一些信息,这些信息就保存在Cookie中。当浏览器再次访问服务器,都会在请求头中将Cookie发送给服务器,方便服务器对浏览器做出正确的响应。
服务器向客户端发送Cookie时,会在HTTP响应头字段中增加Set-Cookie响应头字段。格式如下Set-Cookie: user = itcast;Path=/;
user是Cookie的名称,itcast表示Cookie的值,Path表示Cookie的属性。Cookie必须以键值对存在,其属性可以有多个,属性之间用分号和空格隔开。
当用户(客户端浏览器)第一次访问服务器,服务器会在响应消息中增加Set-Cookie头字段,将用户信息以Cookie的形式发送给浏览器。然后浏览器将接受的服务器发回的Cookie信息保存在浏览器的缓冲区中。
用户第二次访问该服务器时,都会在请求消息中将用户信息以Cookie的形式发送给Web服务器,从而使服务器端分辨出当前请求是由哪个用户发出的。
Cookie API
为了封装Cookie信息,在Servlet API中提供了一个javax.servlet.http.Cookie类,该类包含了生成Cookie信息和提取Cookie信息的各个属性的方法。
我们结合具体例子说
打开eclipse,新建web项目,在java Resource目录下,新建Servlet文件,
package t;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
*该类主要用于实现获取Cookie信息并将当前时间作为Cookie值发送给客户端。
*/
public class LastAccessServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 指定服务器输出内容的编码格式UTF-8,防止发生乱码
response.setContentType("text/html;charset=utf-8");
// 创建变量上一次时间,赋予初值为空
String lastAccessTime = null;
// 获取所有的cookie,并将这些cookie存放在数组中,是服务器请求时发过来的
Cookie[] cookies = request.getCookies();
// 遍历cookies数组
for(int i =0;cookies != null&& i
结果如下,第一次执行,所以没有Cookie,也就是为空,然后服务器要setCookie
第二次执行
但是当我们关闭浏览器,再次打开浏览器访问LastAccessServlet时,浏览器的显示结果为
这说明之前的浏览器存放的信息被删除了,因为默认情况下,Cookie对象的Max-Age属性的值为-1,即浏览器关闭后,删除这个Cookie对象。
为了让Cookie对象在客户端有较长的存活时间,可以通过setMaxAge()方法进行设置,例如将Cookie有效时间设置为1小时,增加的代码如下,cookie.setMaxAge(60*60)。
加在response.addCookie(cookie);前面即可
Session
去医院就诊,有一张就诊卡,卡上只有卡号(相当于ID),没有其他信息,但病人每次去,只用出示就诊卡,医务人员便可以根据卡号查询到病人的信息。Session就是医院给病人的就医卡和医院为每个人保留档案的过程。
当浏览器访问Web服务器时,Servlet容器就会创建一个Session对象和ID属性,其中,Session对象就相当于病历档案,ID相当于就诊卡号。当客户端后续访问服务器时,只要将标示号(ID)传递给服务器,服务器就能判断出该请求是那个客户端发出的,从而选择与之对应的Session对象为其服务。
用户甲和用户乙都调用buyServlet将商品添加到购物车里,调用payServlet进行商品结算,当用户甲访问购物网站时,服务器为甲创建了一个Session对象(相当于购物车),set-Cookie:JSESSIONID =111,当甲将粪叉添加到购物车时,粪叉的信息便存储到了Session对象中,同时服务器将Session对象的 ID属性以Cookie(set-Cookie:JSESSIONID =111)的形式返回给甲的浏览器,当甲完成购物,进行结账时,需向服务器发送结账请求,这时,浏览器自动在请求消息头中将Cookie(set-Cookie:JSESSIONID =111)信息回送给服务器,服务器根据ID属性找到为用户甲所创建的Session对象,并将Session对象中所存放的粪叉信息取出进行结算。
实现购物车:
创建图书信息类
package cn.itcast.chapter05.session.example01;
import java.io.Serializable;
public class Book implements Serializable {
private static final long serialVersionUID = 1L;
private String id;
private String name;
public Book() {
}
public Book(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
创建图数集合
package cn.itcast.chapter05.session.example01;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
public class BookDB {
private static Map
static {
books.put("1", new Book("1", "javaweb开发"));
books.put("2", new Book("2", "jdbc开发"));
books.put("3", new Book("3", "java基础"));
books.put("4", new Book("4", "struts开发"));
books.put("5", new Book("5", "spring开发"));
}
// 获得所有的图书
public static Collection
return books.values();
}
// 根据指定的id获得图书
public static Book getBook(String id) {
return books.get(id);
}
}
显示所有图书
package cn.itcast.chapter05.session.example01;
import java.io.*;
import java.util.Collection;
import javax.servlet.ServletException;
import javax.servlet.http.*;
public class ListBookServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
Collection
out.write("本站提供的图书有:
");
for (Book book : books) {
/*String url = "/chapter05/PurchaseServlet?id=" + book.getId();
out.write(book.getName() + "点击购买
");//用超链接标签转到
*/
String url = "/chapter05/PurchaseServlet?id=" + book.getId();
HttpSession s=req.getSession();
String newUrl=resp.encodeRedirectURL(url);
out.write(book.getName() + "点击购买
");
}
}
}
用户购买的图书
package cn.itcast.chapter05.session.example01;
import java.io.IOException;
import java.util.*;
import javax.servlet.ServletException;
import javax.servlet.http.*;
public class PurchaseServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 获得用户购买的商品
String id = req.getParameter("id");
if (id == null) {
// 如果id为null,重定向到ListBookServlet页面
String url = "/chapter05/ListBookServlet";
resp.sendRedirect(url);
return;
}
Book book = BookDB.getBook(id);
// 创建或者获得用户的Session对象
HttpSession session = req.getSession();
// 从Session对象中获得用户的购物车
List
if (cart == null) {
// 首次购买,为用户创建一个购物车(List集合模拟购物车)
cart = new ArrayList
// 将购物车存入Session对象
session.setAttribute("cart", cart);
}
// 将商品放入购物车
cart.add(book);
// 创建Cookie存放Session的标识号
Cookie cookie = new Cookie("JSESSIONID", session.getId());
cookie.setMaxAge(60 * 30);//设置有效时间
cookie.setPath("/chapter05");
resp.addCookie(cookie);
// 重定向到购物车页面
String url = "/chapter05/CartServlet";
// resp.sendRedirect(url);
String newurl=resp.encodeRedirectURL(url);
resp.sendRedirect(newurl);
}
}
购物车
package cn.itcast.chapter05.session.example01;
import java.io.*;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.*;
public class CartServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
// 变量cart引用用户的购物车
List
// 变量pruFlag标记用户是否买过商品,初始值为true即购买过
boolean purFlag = true;
// 获得用户的session,HttpServletRequest.getSession(false) 等同于 如果当前Session没有就为null;
HttpSession session = req.getSession(false);
// 如果session为null,purFlag置为false
if (session == null) {
purFlag = false;//即没有购买过
}
else {
// 获得用户购物车
cart = (List) session.getAttribute("cart");
// 如果用的购物车为null,purFlag置为false
if (cart == null) {
purFlag = false;
}
}
/*
* 如果purFlag为false,表明用户没有购买图书 重定向到ListServlet页面
*/
if (!purFlag) {
out.write("对不起!您还没有购买任何商品!
");
} else {
// 否则显示用户购买图书的信息
out.write("您购买的图书有:
");
double price = 0;
for (Book book : cart) {
out.write(book.getName() + "
");
}
}
}
}