第六章:会话及其会话技术
学习目标
一、学会掌握cookie对象的概述以及使
二、掌握Session对象
三、HttpSession APL
四、利用URL重写实现Session跟踪
五、总结
一、前言
1.会话概述:
在日常生活中,从拨通电话到挂断电话之间的一连串的你问我答过程就是一个会话。
web应用中会话过程类似于生活中的打电话过程,它是指一个web服务器之间连续发生的一系列请求和响应过程。
一、Cookie对象
1.1cookie概述:类似于商场中办理的会员卡,每次去商场都能通过这张卡来识别你的用户信息,并对你的消费记录。这样,当该浏览器再次访问服务器的时候,都会在请求头中将Cookie发送给服务器,方便服务器对浏览器做出正确的响应。
服务向客户端发送Cookie时,会在HTTP响应字段中增加Set-Cookie响应字段。
Set-Cookie头字段中设置的Cookie遵循一定语法格式,具体示例如下:
Set-Cookie: user=itcast; path=/ ;
user表示Cookie的名称,itcast表示Cookie的值,Path表示Cookie的属性。
1.2为什么要Cookie:
为HTTP协议是无状态的,对于一个浏览器发出的请求,服务器无法区分是不是同一个来源,无法知道上一次用户做了什么。所以,需要额外的数据用于维护会话。 Cookie 正是这样的一段随HTTP请求一起被传递的额外数据,用于维护浏览器和服务器的会话。
1.3Cookie API:
为了封装Cookie信息,在Serlet API中提供了一个javax. serttp.Cooke类,该类包含了生成Cookie信息和提取Cookie信息各个属性的方法。Cookie的构造方法和常用方法具体
- 构造方法:Cookie类有且仅有-一个构造方法,具体语法格式如下。
public Cookie (java.lang.String name, java.lang .String value)
在Cookie的构造方法中,参数name用于指定Cookie的名称,value 用于指定Cookie的值。需要注意的是,Cookie 一旦创建,它的名称就不能更改,Cookie 的值可以为任何值,创建后允许被修改。
[任务5-1 ]显示用户上次访问时间
== 2. 常用方法:
1.)setMaxAge (int expiry)和getMaxAge()方法
2.)setPath (String uri)和getPath()方法
3)setDomian (string patten)和getDomain()方法==
3.任务5-1显示用户上次访问的时间
[任务目标]:
当用户访问某些Web应用时,经常会显示出该用户上-次的访问时间。例如,QQ登录成功后,会显示用户上次的登录时间。通过本任务,读者将学会如何使用Cookie技术实现显示用户上次的访问时间的功能。
[实现步骤]
1.创建Servlet
在Eclipse中新建Web项目chapter05 ,并在该项目下新建-一个 名称为cn.itcast.chapter05.cookie.example的包,在该包中编写一个名称为LastAccessServlet的Servlet类,该类主要用于实现获取Cookie信息并将当前时间作为Cookie值发送给客户端。LastAccessServlet 类的具体实现代码如下所示。
** LastAccessServletjava**
package cn.itcast.chapter05.cookie;
import java.io.IOException;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/
Servlet implementation class LastAcess
/
@WebServlet("/last")
public class LastAcess extends HttpServlet {
private static final long serialVersionUID = 1L;
/*
@see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType(“text/html;charset=utf-8”);
Cookie[] cookies=request.getCookies();
String lasttime=null;
for(int i=0;cookies!=null&&i<cookies.length;i++) {
String name=cookies[i].getName();
if(“lastAccess”.equals(name)) {
lasttime=cookies[i].getValue();
}
}
if(lasttime==null) {
response.getWriter().print(“你是第一次访问本网站”);
}else {
response.getWriter().print(“你是第一次访问的时间是:”+lasttime);
}
1
String time = String.format("%tF%<tT", new Date());
Cookie cookie= new Cookie(“lastAccess”,time);
Cookie cookie2=new Cookie(“lastAccess”,“123”);
response.addCookie(cookie);
response.addCookie(cookie2);
}
/**
@see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
example
package cn.itcast.chapter05.session;
import java.io.IOException;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/*
Servlet implementation class example
/
@WebServlet("/example")
public class example extends HttpServlet {
private static final long serialVersionUID = 1L;
/*
@see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String time = String.format("%tF%<tT", new Date());
Cookie cookie= new Cookie(“lastAccess”,time);
Cookie cookie2=new Cookie(“lastAccess”,“123”);
response.addCookie(cookie);
response.addCookie(cookie2);
}
/*
@see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}*
二、Session对象
Cookie技术可以将用户的信息保存在各自的浏览器中,并且可以在多次请求下实现数据的共享。但是,如果传递的信息比较多,使用Cookie技术显然会增大服务器端程序处理的难度,这时,可以使用Session技术。Session 是-种将会话数据保存到服务器端的技术。接下来,本节将针对Session进行详细的讲解。
三、HttpSession Apl
Session是与每一个请求消息紧密相关的,为此,HttpServletRequest定义了用于获取Session对象的getSession()方法,该方法有以下两种重载方式
public HttpSession getSession(boolean create)
public HttpSession getSession()
在相关的HttpSession对象不存在时总是创建新的HttpSession对象。这里特别需要注意的是:由于getSession方法可能会产生发送会话标记号的Cookie字段头,因此,必须在发送任何响应内容之前调用 getSession()方法。
2.1 Session超时管理
session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。
当程序需要为某个客户端的请求创建一个session的时候,服务器首先检查这个客户端的请求里是否已包含了一个session标识 - 称为session id,如果已包含一个session id则说明以前已经为此客户端创建过session,服务器就按照session id把这个session检索出来使用(如果检索不到,可能会新建一个),如果客户端请求不包含session id,则为此客户端创建一个session并且生成一个与此session相关联的session id,session id的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个session id将被在本次响应中返回给客户端保存。
保存这个session id的方式可以采用cookie,这样在交互过程中浏览器可以自动的按照规则把这个标识发挥给服务器。一般这个cookie的名字都是类似于SEEESIONID,而。比如weblogic对于web应用程序生成的cookie。
这两种方式对于用户来说是没有区别的,只是服务器在解析的时候处理的方式不同,采用第一种方式也有利于把session id的信息和正常程序参数区分开来。
为了在整个交互过程中始终保持状态,就必须在每个客户端可能请求的路径后面都包含这个session id。
另一种技术叫做表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把session id传递回服务器。
比如下面的表单:
<form name="testform" action="/xxx">
<input type="text">
</form>
在被传递给客户端之前将被改写成:
<form name="testform" action="/xxx">
<input type="hidden" name="jsessionid" value="ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764">
<input type="text">
</form>
这种技术现在已较少应用,笔者接触过的很古老的iPlanet6(SunONE应用服务器的前身)就使用了这种技术。
实际上这种技术可以简单的用对action应用URL重写来代替。
2.2[任务5-2实现购物车]
任务目标:创建封装图书信息类
在chapter05项目下新建一一个名称为cn.itcast.chapter05 .session.example01的包,在该包中创建一个名称为Book的类,该类用于封装图书的信息,其中定义了id 和name属性。分别用来表示书的编号和名称。
实现步骤:
1.Book的java类
Book.java
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;
}**
data = pd.read_csv(
'https://labfile.oss.aliyuncs.com/courses/1283/adult.data.csv')
print(data.head())
2.数据库模拟BookDB的java类
创建数据库模拟类
cn.itcast.chapter05. session.example01包中创建一个名为 BookDB拟保存所有图书的数据库。
BookDB.java
package cn.itcast.chapter05.session;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
public class BookDB {
private static Map<String,Book> map = new LinkedHashMap<String,Book>();
static{
map.put(“1”, new Book(“1”,“javaWeb”));
map.put(“2”, new Book(“2”,“jdbc入门”));
map.put(“3”, new Book(“3”,“java基础”));
map.put(“4”, new Book(“4”,“struts框架”));
map.put(“5”, new Book(“5”,“hibernate框架”));
}
//1.得到所有图书
public static Collection<Book> getAll(){
return map.values();
}
//2.根据map的key,也就是图书的id,得到某本图书
public static Book getBook(String id){
return map.get(id);
}
3.创建Servlet
1.创建一个名称为ListBookServlet的Servlet类,该Servlet用于显示所有可购买图书的列表,通过单击“购买”链接,便可将指定的图书添加到购物车中。其实现代码如下所示。
ListBookServlet的Servlet类
package cn.itcast.chapter05.session;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class ListBookServlet
*/
@WebServlet("/list")
public class ListBookServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//response.getWriter().append("Served at: ").append(request.getContextPath());
response.setContentType("text/html;charset=utf-8");
Cookie[] cookies =request.getCookies();
Collection<Book> books=BookDB.getAll();
PrintWriter out = response.getWriter();
out.print("本网站售卖的书如下:");
for(Book b:books) {
String name= b.getName();
String id=b.getId();
String url="<a href='purcharse?id="+id+"'>点击购买</a>";
out.print("图书名称:"+name+" "+url+"<br/><br/>");
}
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
2.创建一个 名称为PurchaseServlet的Servlet类,其实现代码。
PurchaseServlet的Servlet类
package cn.itcast.chapter05.session;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* Servlet implementation class PucharseServlet
*/
@WebServlet("/purcharse")
public class PucharseServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public PucharseServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//response.getWriter().append("Served at: ").append(request.getContextPath());
response.setContentType("text/html;charset=utf-8");
String id=request.getParameter("id");
if(id==null){
response.sendRedirect("/chapter05/list");
return;
}
Book book =BookDB.getBook(id);
HttpSession session=request.getSession();
List<Book> list=(List<Book>) session.getAttribute("cart");
if(list==null) {
list=new ArrayList<Book>();
session.setAttribute("cart", list);
}
list.add(book);
Cookie cookie = new Cookie("JESSIONID", session.getId());
response.addCookie(cookie);
response.sendRedirect("/chapter05/cart");
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
以上实现了两个功能,一一个是将用户购买的图书信息保存到Session对象中:一个是在用户购买图书结束后,将页面重定向到用户已经购买的图书列表。该类在实现时,通过ArrayList集合模拟了一个购物车,然后将购买的所有图书添加到购物车中,最后通过Session对象传递给CartServlet,由CartServlet 展示用户已经购买的图书。
3.创建一一个名称为CartServlet的Servlet类,该类主要用于展示用户已经购买的图书列表,其实现代码。
CartServlet的Servlet类
package cn.itcast.chapter05.session;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* Servlet implementation class CartServlet
*/
@WebServlet("/cart")
public class CartServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//response.getWriter().append("Served at: ").append(request.getContextPath());
response.setContentType("text/html;charset=utf-8");
PrintWriter out=response.getWriter();
List<Book> cart=null;
HttpSession session = request.getSession(false);
boolean cartflag=false;
if(session==null) {
cartflag=false;
}else {
cart=(List<Book>)session.getAttribute("cart");
if(cart==null) {
cartflag=false;
}
}
if(!cartflag) {
out.print("对不起,请前往购买图书");
}else {
out.print("购买图书如下:"+"<br/>");
for(Book b:cart) {
out.print("购买图书:"+b.getName()+"<br/>");
}
}
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
4.运行项目,查看结果
在web.xml中对相应的Servlet进行配置,然后启动Tomcat服务器,在浏览器中输入地址http://ocalhost:9999/chapter05/ListBookServlet”访问ListBookServlet,浏览器显示的结果如下:
至此,使用Session实现购物车程序完成了。需要注意的是:为了保存Session的ID属性,需要创建一个Cookie对象,并设置Cookie的有效时间。这样做的好处是,在一定时间内,即使用户关闭了浏览器,重新打开浏览器这个页面时,服务器也能找到之前为用户创建的Session对象。
四、利用URL重写实现Session跟踪
前面提到过得,服务器在传递Session对象的ID属性时,是以Cookie的形式传输递给浏览器的。
**1.url重写原理:**当服务器程序调用request.getSession();代码时,其会先看request.getCookies()方法中有没有名为JSESSIONID的cookie带过来,如果没有,就看URL有没有被重写(即附带JSESSIONID),如果有,则从服务器中找key为JSESSIONID的session对象,如果都没有,则创建一个新的session。如果用户禁用了cookie,则只能通过URL重写方式实现会话跟踪!
1.1在Servlet中实现URL重写:
客户端在访问本Servlet后,会返回主页面:
package edu.session;
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 EncodeURL extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
request.getSession(); //创建session
//调用response的encodeURL方法,将自动将JSESSION追加到url后面,如:url;jsessionid=BD111FFC653497E81B702A29B3AC6FE4
String buyurl = response.encodeURL("/CookieAndSession/servlet/buy");
String payurl = response.encodeURL("/CookieAndSession/servlet/pay");
out.print("<a href='"+buyurl+"'>购买</a><br/>");
out.print("<a href='"+payurl+"'>结账</a><br/>");
}
}
1.2:禁用浏览器的Cookie。
单击图中的确定按钮,此时,浏览器所有的Cookie都被禁用了。
1.3:刷新或者重新访问地址 “http://localhost:8080/chapter05/CarServle”,这时,发现浏览器显示结果如下图:
这边要特别* 注意:
1. 但是如果用户禁用cookie,则关闭了浏览器后,重新开启浏览器,则回话失效,无法实现回话跟踪;如果是用户没有禁用cookie,则可以通过设置装载JSESSIONID的cookie的失效时间来控制浏览器关闭后session仍未失效。
== 2.如果用户没有禁用cookie,而且又使用URL重写,则:用户在第一次访问EncodeURLServlet时,由于不知道用户是否禁用了cookie,所以response.encodeURL()方法内部会将JSESSIONID重写在url上,但是一旦第二次访问时,由于用户是带着cookie来的,所以response.encodeURL()不会将JSESSIONID重写在url上。===
五、总结:
本章主要讲解了Cookie对象和Session对象的相关知识,其中Cookie最早期会话跟踪技术,它将信息保存到客户浏览器中。浏览器访问网站时会携带这些Cookie,它将信息保存在服务器端。Session中能够存储复杂的Java对象,因此使用更加方便。