首先客服浏览器向web服务器端,发送一个请求,web服务器端给客户浏览器应答,只要浏览器不关,就会不断的通信,就会有多个请求多个应答,一个请求一个应答一一对应。
Cookie技术解决的是多个请求和应答之间数据共享的问题。
其实多组请求和应答,不断的请求和应答就是一个会话过程,Cookie为什么能访问到上次购买的记录,是因为把上次Cookie的键值对放到请求头,这是浏览器自动进行的工作,这样请求1和请求2直接就可以达到共享数据
就如上面的图,就是因为请求1的Cookie的键值对放到了请求2的请求头中,所以接算的时候才可以有请求1的购买记录
那什么是session技术呢?
打个很简单的比方,就比如我们去餐馆吃饭会购买那种会员卡,会员卡里面会存有钱,通过会员卡来消费就是Cookie技术,而我们如果没有带会员卡就只需要报出自己的手机号就可以了,这就是Session技术。
第一次访问的时候还是请求,因为是第一次访问会创建一个Session,为了区分多个Session,每个Session有自己的一个id,Session会在服务器端存储下来,给用户浏览器端也会发一个set-Cookie键值对,但是不再是像上面那样存的是购买的信息,购买的信息已经在服务器端的Session里面存下来了他给客户浏览器端发送的应答其实是Session的id号。这个时候键值对的键就是Session的id,值就是id的值
客户端收到这个set-Cookie这个应答之后,会把这个Session的id给存下来,然后再次请求的时候会把这个Session的id放到请求头里
每次服务器收到这个Session的id的时候,他就会在服务器去找这个Session,然后通过API把上次的记录从Session取出来
其实我们不难发现,Session技术是依托于Cookie技术的。
因为Session技术要通过Cookie去保存Session的id。这个id不正是类似于餐馆消费可以不用带卡而是用电话号码吗?餐馆就会把这个电话号码记录下来,餐馆就可以通过这个电话号码来查到你的消费。一样的道理。
Cookie技术是在客户端实现的,而Session技术是在服务器端实现的
会话是占用服务器资源的,会话也有自己的生命周期
Session
是与每个请求消息紧密相关的,为此HttpServlet定义了用于获取Session对象的getSession()方法,还有两种重载形式,具体如下:
我们获取了Session对象就可以调用Session对象的相关的方法
之前说过,会话是占用服务器资源的,所以无法一直存在于服务器。但是web服务器也无法判断浏览器是否还会访问,也无法检测客户端浏览器是否关闭,所以当会话越来越多的时候,服务器的内存终将会被耗尽
为了解决这个问题,web服务器采用了"超时限制"
来判断客户端是否还在继续访问
在一定的时间内,如果某个客户端一直没有请求访问,服务器就会认为该客户的会话已经结束,并将对应的HttpSession对象变成垃圾对象,等待垃圾收集器从内存中彻底的清除,反之,如果浏览器超时之后再进行访问,那么服务器会创建一个新的Session对象,并且会为这个Session对象配一个新的id。
在web.xml配置里面可以改超时的时间限制
<session-config>
<session-timeout>30session-timeout>
session-config>
通过Session来模拟实现一个网上购书,和购物车清单显示。
流程图如下:
代码实现
//1.首先创建一个图书的实体类
public class Book {
private static final long serialVersionUID = 1L; //serialVersionUID版本号。
private String name;
private String id;
public Book() {
}
public Book(String id, String name) {
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
//新建一个保存图书的数据库的BookDB类
//模拟数据库的类,工具类
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
public class BookDB {
private static Map<String,Book> books = new LinkedHashMap<>();
//静态代码块,静态总是优先于非静态,而且静态代码块只执行唯一一次
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<Book> getAll() {
return books.values();
}
//根据指定的id获取图书
public static Book getBook(String id) {
return books.get(id);
}
}
//ListBookServlet用来显示商城中所有的图书,
//通过单击购买链接就可以加入购物车
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 java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
@WebServlet(name = "ListBookServlet",urlPatterns = "/ListBookServlet")
public class ListBookServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//处理中文乱码问题
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
Collection<Book> books = BookDB.getAll();
out.write("本站的图书有:
");
//通过增强for循环来遍历Collection集合
//格式: for(集合/数组中的数据类型 变量名 : 集合名/数组名){ }
for (Book book : books) {
//通过GET方式给每本书加上购物车的URL
String url = "PurchaseServlet?id=" + book.getId();
out.write(book.getName() + "点击购买
");
}
}
}
遍历之后实现的链接是这样的
本站的图书有: <br> javaweb开发<a href='PurchaseServlet?id=1'>点击购买a><br>jdbc开发<a href='PurchaseServlet?id=2'>点击购买a><br>java基础<a href='PurchaseServlet?id=3'>点击购买a><br>struts开发<a href='PurchaseServlet?id=4'>点击购买a><br>spring开发<a href='PurchaseServlet?id=5'>点击购买a><br>
/*
4.新建一个购买的Servlet
(1).将用户购买的书籍信息保存在Session中
(2).让用户购买书籍之后,将页面重定向到用户已经购买的图书列表
*/
@WebServlet(name = "PurchaseServlet",urlPatterns = "/PurchaseServlet")
public class PurchaseServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//获得用户购买的商品
String id = request.getParameter("id");
//如果用户一上来直接访问PurchaseServlet那么id就是null
if (null == id) {
//如果id为null,那么就重定向到ListBookServlet
String url = "ListBookServlet";
response.sendRedirect(url);
return;
}
Book book = BookDB.getBook(id);
//创建或者获得用户的Session,采用无参的getSession如果没有总是会新创建Session
HttpSession session = request.getSession();
//从Session对象中获得用户的购物车
List<Book> cart = (List) session.getAttribute("cart");
if (null == cart) {
//首次购买为用户创建一个cart
cart = new ArrayList<Book>(); //采用多态写法
//将购物车存入Session对象
session.setAttribute("cart",cart);
}
//将商品放入购物车
cart.add(book);
//创建Cookie要存放Session的id
Cookie cookie = new Cookie("JSESSIONID",session.getId());
//设置Session的超时限制
cookie.setMaxAge(60 * 30);
response.addCookie(cookie);
//重定向到购物车页面
String url = "CartServlet";
response.sendRedirect(url);
}
}
/*
5.创建一个购物车CartServlet
*/
@WebServlet(name = "CartServlet",urlPatterns = "/CartServlet")
public class CartServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
List<Book> cart = null;
//变量purFlag来标记用户是否买过商品
boolean purFlag = true;
//获取用户的Session
HttpSession session = request.getSession();
//如果Session为null则purFlag为false
if (null == session) {
purFlag = false;
}else {
//获取用户的购物车
cart = (List)session.getAttribute("cart");
//如果购物车为空,purFlag为false
if (null == cart) {
purFlag = false;
}
}
//如果purFlag为false,表示用户没有买书,重定向到ListBookServlet
if (!purFlag) {
out.write("对不起,您还没有购买任何商品!
");
}else {
//否则显示用户购买图书的信息
out.write("您购买的图书有:
");
double price = 0;
for (Book book : cart) {
out.write(book.getName() + "
");
}
}
}
}
运行结果:
接下来测试一下超时限制,按理说如果Cookie正常的话,我们设置的在30分钟之内访问购物车,购买的书籍应该还是存在的
具体可参考:
https://blog.csdn.net/mdong9/article/details/105731120
当浏览器不支持Cookie或者关闭了Cookie 功能时,在会话过程中,如果想 让Web服务器可以保存用户的信息,必须对所有可能被客户端访问的请求路径进 行URL重写。在HttpServletResponse接口中,定义了两个用于完成URL重写的方法。
URL重写,指的是将Session的会话标识号以参数 的形式附加在超链接的URL地址后面。对于Tomcat服务器来说,就是将JSessionID关键字作为参数名以及会话标识号的值作为参数值附加到URL地址 后面。
//网页首界面,判断是否有用户登录
@WebServlet(name = "indexServlet",urlPatterns = "/indexServlet")
public class indexServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request,response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
//创建或者获取保存用户信息的Session对象
HttpSession session = request.getSession();
User user = (User) session.getAttribute("user");
if (null == user) {
response.getWriter().print("您还没有登录,请登录");
}else {
response.getWriter().print("您已经登录,欢迎您" +user.getUsername() + "!");
response.getWriter().print("退出");
//创建Cookie存放Session的id
Cookie cookie = new Cookie("JSESSIONID",session.getId());
cookie.setMaxAge(60 * 30);
response.addCookie(cookie);
}
}
}
因为是登录首先得有一个登录界面
Insert title here
因为登录界面每个用户会有账号和密码,我们通过JavaBean实体类来封装用户的信息
//创建一个实体类用于封装前端传过来的用户的账号和密码
public class User {
private String username;
private String password;
public User() {
}
public User(String username, String password) {
this.username = username;
this.password = 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;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
//写一个用户登录的请求loginServlet
@WebServlet(name = "loginServlet",urlPatterns = "/loginServlet")
public class loginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
String username = request.getParameter("username");
String password = request.getParameter("password");
PrintWriter pw = response.getWriter();
//假设正确的用户名是yangtze,密码是123
if (("yangtze").equals(username) && ("password").equals(password)) {
User user = new User(username,password);
// user.setUsername(username);
// user.setPassword(password);
request.getSession().setAttribute("user",user);
response.sendRedirect("/indexServlet");
}else {
pw.write("用户名或密码错误,登录失败");
}
}
}
运行结果: