Java Web程序设计——会话及其会话技术
思维导图放上:
会话概述
- 从打开浏览器,到访问网页,到最终关闭浏览器,整个过程就是一次会话。
比如:一个用户在某网站上的整个购物过程就是一个会话
会话的特点
- 包含多个请求,一次完整的会话针对一个用户
会话技术
- Cookie技术,客户端技术
- Session技术,服务端技术
会话中的数据存储问题
在一次会话中往往会产生一些数据,而这些数据是需要保存起来的
- 如果使用request作用域来保存会话中产生的数据,由于会话是多次请求,多次响应,而request域的作用范围仅仅是一次请求,所以用request域保存会话中产生的数据,作用范围太小了
- 如果使用ServletContext作用域来保存会话中产生的数据,ServletContext的作用范围是整个WEB应用,如果将每一个客户端和服务器产生的会话数据都保存在ServletContext域中,很可能会发生混乱
例:
在某宝买东西,买完商品后,买的商品存到什么对象比较合适?
- 使用request域对象保存商品信息:不可以,因为每次发送请求,都会产生一个新的请求对象
- 使用ServletContext域对象保存商品信息:可以,但是不合理。
所以在开发中,保存会话过程中产生的数据,采用会话技术,也就是使用Cookie和Session技术来保存会话过程产生的数据。
Cookie对象
- Cookie是一种会话管理技术,它是用老保存会话过程中产生的数据,然后在浏览器和服务器交互时,会使用cookie里面保存的数据。
注:首次访问服务器,浏览器不会携带Cookie到服务端。
Cookie在浏览器和服务器之间的传输:
结论:1.第一次访问服务器,服务器会增加Set-Cookie头字段,将Cookie信息发送给浏览器,并保存在客户端。
2.当后续访问服务器时,会在请求消息中将用户信息以Cookie的形式发送给服务器,从而使服务器端分辨出当前请求是由哪个用户发出的。
Cookie常用的API
- 得到Cookie对象:Cookie cookie = new Cookie(String key,String value);
- 响应Cookie到浏览器端:response.addCookie(cookie);
- 得到Cookie名称:String key = cookie.getName();
- 得到Cookie的值:String value = cookie.getValue();
- 给Cookie设置生命时长:setMaxAge(int sr);
例:cookie.setMaxAge(606024*7),说明Cookie能存活7天 - 给Cookie设置路径,设置域名:setPath(路径的url),setDomain(域名);
例:域名就是服务器名称,比如:www.CSDN.net - 获取Cookie:Cookie[ ] cookies = request.getCookies();
通过Cookie实现显示用户上次访问时间
步骤:
- 判断是否是首次访问:如果Cookie里面有时间,说明就不是第一次访问
- 如果是第一次访问,创建Cookie,保存时间,把这个Cookie回写到浏览器端
- 如果不是第一次访问,把时间回写到浏览器,记住当前时间,把时间保存Cookie里面
package chapter.cookie.example;
import java.io.IOException;
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;
/**
* 显示用户的上次访问时间
*/
public class LastAccessServlet 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");
// 1.获取cookie数组
Cookie[] cookies = request.getCookies();
// 2.遍历cookie数组
String lastTime = null;
for (int i = 0; cookies != null && i < cookies.length; i++) {
// 3.获取cookie的名称
String name = cookies[i].getName();
if ("lastAccess".equals(name)) {
// 获取cookie的时间
lastTime = cookies[i].getValue();
}
}
// 4.判断是否是首次访问,如果cookie里有时间,就不是第一次访问,否则就是第一次访问
if (lastTime == null) {
// 第一次访问
response.getWriter().print("你是首次访问本网站");
} else {
// 说明不是第一次访问
// 把上次访问时间,回写到浏览器
response.getWriter().print("你的上次访问时间:"+lastTime);
}
// 第三次,第四次------
String time = String.format("%tF %<tT", new Date());
Cookie cookie = new Cookie("lastAccess", time);
cookie.setMaxAge(60*60*24*7);
response.addCookie(cookie);
}
/**
* @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);
}
}
启动服务器,在浏览器中打开可见
cookie规范
- 一个cookie最大4kb
- 一个服务器最多在一个客户端寄存20个cookie
- 一个浏览器最多保存300个cookie
- cookie是有安全隐患的:由于数据保存在浏览器端,所以可以被任意的查看,安全性较低,但是可以长时间存储数据。cookie善于存储安全性要求较低,但是存储时间较长的数据。
Session对象
- Session是一种会话管理技术,用来保存会话过程中的数据,保存的数据存储到服务器。是基于Cookie实现的,更确切的说是基于会话级别的Cookie实现的。
HttpSession API
- 得到Session的id(JESSIONID对应的值):getId()
- 设置Session的生命时长:setMaxInactiveInterval(int interval)
- 销毁Session:invalidate()
- 得到Session:HttpSession session = getSession()
- Seesion域对象:作用范围一次完整的会话(包含多个请求):
存值:setAttribute(String key,object obj);
取值:Object obj = getAttribute(String key);
移除:removeAttribute(String key);
注:域对象:request域对象:作用范围一次请求,通常和转发操作配合使用;
session域对象:作用范围一次会话,通常和重定向操作配合使用
servletContext域对象:作用范围整个项目,和重定向、转发操作都可以配合使用。
以上作用范围依次变大。
Session超时管理
- Session对象是由生命时长,它的默认存活时间是30分钟
- 在会话过程中,会话的有效时间可以在web.xml文件中设置,其默认值由Servlet容器定义。在<tomcat安装目录>\conf\web.xml文件中,可以找到如下一段配置信息:
<session-config>
<session-timeout>30</session-timeout>
</session-config>
注:如果将<session-timeout>
元素中的时间值设置成0或负数,则表示会话永不超时!
Session实现购物车
步骤:
- 创建Book封装图书信息:Book
package session.example01;
public class Book {
private String id;
private String name;
public Book() {
super();
}
public Book(String id, String name) {
super();
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;
}
}
- 创建BookDB,模拟数据库,里面保存图书
package session.example01;
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", "java基础"));
map.put("3", new Book("3", "python"));
map.put("4", new Book("4", "php"));
map.put("5", new Book("5", "C语言"));
}
// 1.得到所有图书
public static Collection<Book> getAll() {
return map.values();
}
// 2.根据map的key,也就是图书的id,得到某本图书
public static Book getBook(String id) {
return map.get(id);
}
}
- 提供图书的购买页面:ListBookServlet
package session.example01;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 提供一个购买图书的页面
*/
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 {
// 处理响应中文的乱码
response.setContentType("text/html;charset=utf-8");
//1.得到所有图书
Collection<Book> books = BookDB.getAll();
//2.显示页面
PrintWriter out = response.getWriter();
out.print("以下是本网站售卖的所有图书:"+"<br/><br/>");
//3.遍历集合,显示图书页面
for(Book b:books) {
//4.得到图书名称
String name = b.getName();
String id = b.getId();
//提供一个购买图书的链接
String url="<a href='/chapter/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);
}
}
- 添加购物车:PurcharseServlet
package session.example01;
import java.io.IOException;
import java.util.ArrayList;
import javax.servlet.ServletException;
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;
/**
* 添加购物车
*/
public class PurcharseServlet 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");
// 1.获取图书信息
String id = request.getParameter("id");
//判断id是否存在
if (id == null) {
// 没有购买图书
response.sendRedirect("/chapter/list");
return;
}
//2.图书已经购买了
Book book = BookDB.getBook(id);
//3.把图书添加到购物车
HttpSession session = request.getSession();
java.util.List<Book> list = (java.util.List<Book>) session.getAttribute("cart");
//4.判断购物车是否存在,是不是首次购买
if (list==null) {//首次购买
list = new ArrayList<Book>();
session.setAttribute("cart", list);
}
//5.把图书添加到购物车
list.add(book);
//6.把请求跳转到CartServlet
//session基于自己创建的cookie完成效果:在浏览器关闭后,cookie对象还存在,就能找到session对象
Cookie cookie = new Cookie("JEAAIONID", session.getId());
cookie.setMaxAge(60*60*24);
cookie.setPath("/chapter");
response.addCookie(cookie);
//跳转到cartServlet里面
response.sendRedirect("/chapter/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);
}
}
- 显示购物车图书信息:CartServlet
package session.example01;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* Servlet implementation class CartServlet
*/
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 {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
// 1.得到购物车
List<Book> cart = null;
// 2.得到用户自己的session
HttpSession session = request.getSession(false);
// 3.自己定义一个flag,判断购物车里面是否有图书
boolean cartFlag = true;
if (session == null) {
cartFlag = false;
} else {
cart = (List<Book>) session.getAttribute("cart");
if (cart == null) {
cartFlag = false;
}
}
// 4.购物车有商品了
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);
}
}
6.启动服务器,用浏览器打开
注:如果浏览器禁用了cookie,购物车功能就不能实现了,因为session是基于cookie实现的。
Session实现用户登录
- 创建User类,封装用户名和密码
package session.example;
public class User {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public User() {
super();
}
}
- 提供首页面,欢迎用户登录:IndexServlet,提供一个退出的链接
package session.example;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* Servlet implementation class IndexServlet
*/
public class IndexServlet 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");
//1.获取用户信息
HttpSession session = request.getSession();
User user = (User)session.getAttribute("key");
//2.判断用户是否存在
if(user==null) {
//说明用户不存在,也就是用户根本没有登录
response.sendRedirect("chapter/login.html");
}else {
String name = user.getUsername();
String url = "<a href='/chapter/logOut'>退出</a>";
response.getWriter().print("欢迎您:"+name+" 登录本网站"+url);
}
}
/**
* @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);
}
}
- 提供登录的servlet:处理登录请求
package session.example;
import java.io.IOException;
import javax.servlet.ServletException;
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 LoginServlet
*/
public class LoginServlet 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");
// 1.获取用户名和密码
String name = request.getParameter("username");
String psw = request.getParameter("password");
// 2.判断用户和密码是否正确,用户名是admin,密码是123,就认为是正确的,否则是错误的
if ("admin".equals(name) && "123".equals(psw)) {
// 登录成功
User u = new User();
u.setUsername(name);
u.setPassword(psw);
HttpSession session = request.getSession();
session.setAttribute("key", u);
// 自己创建cookie,让session使用自己的cookie
Cookie c = new Cookie("JESSIONID", session.getId());
c.setMaxAge(3600 * 24 * 7);
c.setPath("/chapter");
response.sendRedirect("/chapter/index");
} else {
// 登陆失败
response.getWriter().print("用户名和密码错误,登录失败!");
}
}
/**
* @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);
}
}
login.html
- 提供退出servlet:处理退出页面的请求
package session.example;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* Servlet implementation class LogOutServlet
*/
public class LogOutServlet 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 {
// 清空session
HttpSession session = request.getSession();
// session.removeAttribute("key");
session.invalidate();
}
/**
* @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);
}
}
启动服务器,用浏览器打开
登录成功:
登陆失败: