Session&Cookie

会话

什么是会话

会话可简单理解为:用户开一个浏览器,点击多个超链接,访问服务器多个web资源,然后关闭浏览器,整个过程称之为一个会话。

会话过程中要解决的一些问题?

每个用户在使用浏览器与服务器进行会话的过程中,不可避免各自会产生一些数据,程序要想办法为每个用户保存这些数据。
例如:用户点击超链接通过一个servlet购买了一个商品,程序应该想办法保存用户购买的商品,以便于用户点结帐servlet时,结帐servlet可以得到用户购买的商品为用户结帐。

思考:用户购买的商品保存在request或servletContext中行不行?

保存会话数据的两种技术

Cookie

Cookie是客户端技术,程序把每个用户的数据以cookie的形式写给用户各自的浏览器。当用户使用浏览器再去访问服务器中的web资源时,就会带着各自的数据去。这样,web资源处理的就是用户各自的数据了。

Session

Session是服务器端技术,利用这个技术,服务器在运行时可以为每一个用户的浏览器创建一个其独享的HttpSession对象,由于session为用户浏览器独享,所以用户在访问服务器的web资源时,可以把各自的数据放在各自的session中,当用户再去访问服务器中的其它web资源时,其它web资源再从用户各自的session中取出数据为用户服务

Cookie API

javax.servlet.http.Cookie

 javax.servlet.http.Cookie类用于创建一个Cookie
 response接口中定义了一个addCookie方法,它用于在其响应头中增加一个相应的Set-Cookie头字段。
 request接口中也定义了一个getCookies方法,它用于获取客户端提交的Cookie。

Cookie类的方法:

 public Cookie(String name,String value)
 setValue与getValue方法
 setMaxAge与getMaxAge方法 (秒)
 setPath与getPath方法
 setDomain与getDomain方法
 getName方法

Cookie类的一些属性

9.png

Cookie应用场景

记录上次访问时间

package com.gyf.web.servlet.lesson09;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.util.Arrays;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
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 org.apache.commons.beanutils.BeanUtils;

import com.gyf.model.User;

@WebServlet("/Lesson09Servlet01")
public class Lesson09Servlet01 extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        //Cookie应用场景:记录上次访问时间
        
        //设置响应时乱码的问题
        response.setHeader("content-type", "text/html;charset=utf-8");
        
        //获取请求头的Cookie
        Cookie[] cks = request.getCookies();
        if(cks != null){
            for(Cookie c : cks){
                System.out.println(c.getName() + ":" + c.getValue());
                response.getWriter().write("上次访问的时间:" + c.getValue());
            }
        }
        //1.创建一个Cookie对象
        Cookie ck = new Cookie("lastAccessTime",System.currentTimeMillis() + "");
        
        //2.设置cookie的存活时间【单位是秒】
        ck.setMaxAge(60 * 5);
        
        //3.把cookie返回给客户端【通过响应头传给客户端】
        response.addCookie(ck);
    }
}
10.png

Cookie的maxAge方法

设置cookies的存活时间
maxAge:cookie的缓存时间。默认是-1,默认存在浏览器的缓存中。单位是秒
 负数:表示cookie的数据存在浏览器缓存中
 0:表示删除cookie
 正数:缓存在持久化磁盘上的时间

Cookie细节

 一个Cookie只能标识一种信息,它至少含有一个标识该信息的名称(NAME)和设置值(VALUE)。
 一个WEB站点可以给一个WEB浏览器发送多个Cookie,一个WEB浏览器也可以存储多个WEB站点提供的Cookie。
 浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB。
 如果创建了一个cookie,并将他发送到浏览器,默认情况下它是一个会话级别的cookie(即存储在浏览器的内存中),用户退出浏览器之后即被删除。若希望浏览器将该cookie存储在磁盘上,则需要使用maxAge,并给出一个以秒为单位的时间。将最大时效设为0则是命令浏览器删除该cookie。

记住用户名

package com.gyf.web.servlet.lesson11;

import java.io.IOException;

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;

@WebServlet("/Lesson11LoginServlet")
public class Lesson11LoginServlet extends HttpServlet{
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        response.setHeader("content-type","text/html;charset=utf-8");
        //1.获取表单请求参数
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String remember = request.getParameter("remember");
        
        //2.简单判断是否登陆成功
        boolean success = "gyf".equals(username) && "123".equals(password);
        if(success){
            response.getWriter().write("登陆成功");
        }else{
            response.getWriter().write("登陆失败");
        }
        
        //3.把remeber和username存在cookie中
        if("true".equals(remember) && success == true){
            Cookie ck1 = new Cookie("remember",remember);
            ck1.setMaxAge(60 * 60);//存活1个小时
            response.addCookie(ck1);
            
            Cookie ck2 = new Cookie("username",username);
            ck2.setMaxAge(60 * 60);//存活1个小时
            response.addCookie(ck2);
        }else{
            //清除cookie
            Cookie[] cks = request.getCookies();
            if(cks != null){
                for(Cookie c: cks){
                    c.setMaxAge(0);//删除cookie
                    response.addCookie(c);
                }
            }
        }
    }
}
<%@ page language="java" contentType="text/html; UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
    
    /*1.通过cooki的key来获取值*/
    function getCookieValue(key) {
        //1.通过js来获取cookies
        var cookie = document.cookie;//remember=true; remember=true
        
        //2.拆分cookie
        var cks = cookie.split('; ');
        
        for(var i = 0; i<cks.length;i++){
            var ck = cks[i];//remember=true   或者   remember=true
            
            //3.取name和value
            var ckArr = ck.split("=");
            var name = ckArr[0];
            var value = ckArr[1];
            
            //4.找到对应的key的value
            if(key == name){
                return value;
            }
        }
    }
    
    window.onload = function(){
        var remember = getCookieValue('remember');
        if(remember == 'true'){
            //1.给记住用户名勾选中
            var rememberTag = document.getElementById('remember');
            rememberTag.checked = 'checked';
            //2.给用户名显示上次登陆名字
            var username = getCookieValue('username');
            var usernameTag = document.getElementById('username');
            usernameTag.value = username;
            
        }
    }
    var v1 = getCookieValue('remember');
    var v2 = getCookieValue('username');
    console.log(v1);    
    console.log(v2);    
</script>
</head>
<body>

<form action="/day10-20180321/Lesson11LoginServlet" method="post">
    <table border="1">
        <tr>
            <td>用户名:</td>
            <td><input id="username" type="text" name="username"></td>
        </tr>
        <tr>
            <td>密码:</td>
            <td><input type="password" name="password"></td>
        </tr>
        <tr>
            <td colspan="2">
                <input id="remember" type="checkbox" name="remember" value="true">记住用户名
            </td>
        </tr>
        <tr>
            <td colspan="2">
            <input type="submit" value="登陆">
            </td>
        </tr>
    </table>
</form>
</body>
</html>

历史记录

package com.gyf.web.servlet.lesson01;

import java.util.HashMap;
import java.util.Map;

import com.gyf.model.Book;

public class DBUtils {
    private static Map<Integer, Book> books = new HashMap<>();
    //公用的数据写在一个静态集合,赋值一次的内容最好写在static代码块中
    static{
        books.put(1, new Book(1,"吉他弹奏入门","lp","168.88"));
        books.put(2, new Book(2,"锁呐弹奏入门","hg","168.88"));
        books.put(3, new Book(3,"军事杂志","wf","168.88"));
        books.put(4, new Book(4,"帅哥杂志","sgx","168.88"));
        books.put(5, new Book(5,"美女杂志","xd","168.88"));
    }
    //返回所有书
    public static Map<Integer, Book> getAllBooks(){ 
        return books;
    }
    //通过id找到书
    public static Book findBookById(Integer id){
        return books.get(id);
    }
}
package com.gyf.web.servlet.lesson13;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;

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 com.gyf.model.Book;

@WebServlet("/ShowAllBookServlet")
public class ShowAllBookServlet extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        response.setHeader("content-type","text/html;charset=utf-8");
        
        //1.准备一些书的数据
        List<Book> books = new ArrayList<>();
        /*books.add(new Book(1,"吉他弹奏入门","lp","168.88"));
        books.add(new Book(2,"锁呐弹奏入门","hg","168.88"));
        books.add(new Book(3,"军事杂志","wf","168.88"));
        books.add(new Book(4,"帅哥杂志","sgx","168.88"));
        books.add(new Book(5,"美女杂志","xd","168.88"));*/
        //2.显示书的数据给浏览器
        PrintWriter writer = response.getWriter();
        writer.write("图书列表<br>");
        /*
         * <a href='/项目名/ViewBookServlet?id=1'>书名</a>
         * Servlet返回给客户端的数据可以是html标签数据
         */
        for(Entry<Integer, Book> entry : DBUtils.getAllBooks().entrySet()){
            Book book = entry.getValue();
            String aStr = "<a href='http://localhost:8080" + request.getContextPath() + "/ViewBookServlet?id="+ book.getId() +"'>"+ book.getName() + "</a><br>";
            writer.write(aStr);
        }
    }
}
package com.gyf.web.servlet.lesson01;

import java.io.IOException;
import java.io.PrintWriter;

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 com.gyf.model.Book;

@WebServlet("/ViewBookServlet")
public class ViewBookServlet extends HttpServlet{
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        /*
         * 常识:从浏览器/客户端获取的所有数据都是字符串类型
         */
        response.setHeader("content-type","text/html;charset=utf-8");
        //1.获取书的id
        String str_id = request.getParameter("id");
        //2.自己把字符串转成int
        int id = Integer.parseInt(str_id);
        
        PrintWriter writer = response.getWriter();
        writer.write("查看书的id:" + id);
        //3.取出对应的书:
        Book book = DBUtils.findBookById(id);
        writer.write("<br>" + book.toString());
        
        //4.把浏览的书的ID存在cookie中,也就是通过cookie形式返回给客户端、
        //4.1获取客户端的Cookies
        Cookie[] cks = request.getCookies();
        if(cks == null){//未传过cookie
            System.out.println("未传过cookie");
            //存一个Cookie
            Cookie ck = new Cookie("historyBookIds",str_id);
            ck.setMaxAge(60 * 60);//1小时
            response.addCookie(ck);
            
        }else{//有Cookie
            System.out.println("有传过cookie");
            //拼接bookid
            for (Cookie ck : cks) {
                if(ck.getName().equals("historyBookIds")){
                    String historyBookIds = ck.getValue();
                    System.out.println("以前访问过的书的ID:" + historyBookIds);
                    
                    //判断是否有当前的ID包括在里面
                    if(historyBookIds.equals(str_id)) return;//如果第一个和第二个相同,则不执行后面的代码
                    if(historyBookIds.startsWith(str_id)){
                        historyBookIds = historyBookIds.replaceAll(str_id + "-", "");
                    }else{
                        historyBookIds = historyBookIds.replaceAll( "-" + str_id, "");
                    }
        
                    //拼接
                    historyBookIds += "-" + str_id;
                    System.out.println("现在访问过的书的ID:" + historyBookIds);
                    
                    //响应客户端
                    ck.setValue(historyBookIds);
                    ck.setMaxAge(60 * 60);
                    response.addCookie(ck);
                }
            }
        }
    }
}

Session API

session概述

在WEB开发中,服务器可以为每个用户浏览器创建一个会话对象(session对象),注意:一个浏览器独占一个session对象(默认情况下)。因此,在需要保存用户数据时,服务器程序可以把用户数据写到用户浏览器独占的session中,当用户使用浏览器访问其它程序时,其它程序可以从用户的session中取出该用户的数据,为用户服务。
Session和Cookie的主要区别在于:

  • Cookie是把用户的数据写给用户的浏览器。
  • Session技术把用户的数据写到用户独占的session中。

Session对象由服务器创建,开发人员可以调用request对象的getSession方法得到session对象。

Session原理图

11.png
  • 每个浏览器存储自己的数据到Session中
  • Session的数据是不能被其它浏览器共享的
  • Session一般可用于判断用户是否登录

Session小实验

package com.gyf.web.servlet.lesson04;

import java.io.IOException;

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;

@WebServlet("/Lesson04Servlet1")
public class Lesson04Servlet1 extends HttpServlet{

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        
        //通过request获取Session对象
        HttpSession session = request.getSession();
        
        //存数据到session
        session.setAttribute("name", "gyf");
    }
}
package com.gyf.web.servlet.lesson04;

import java.io.IOException;

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;

@WebServlet("/Lesson04Servlet2")
public class Lesson04Servlet2 extends HttpServlet{

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        response.setHeader("content-type", "text/html;charset=utf-8");
        //通过request获取Session对象
        HttpSession session = request.getSession();
        
        //获取session的值
        String name = (String) session.getAttribute("name");
        
        //响应客户端
        response.getWriter().write(name);
    }
}

Session的疑问

Session的实现原理:

  1. 当浏览器访问后台时,后台会创建一个Session对象,并分配一个ID
  2. 把这个Session ID通过响应头Cookie的形式返回给客户端
  3. 客户端就会把Cookie存在本地
  4. 当下次再访问这个站点时,会把sessionid通过请求头cookie的形式传回给后台
    疑问:服务器是如何实现一个session为一个用户浏览器服务的?
    服务器会为每个浏览器分配一个session ID,然后把Session ID通过Cookie的形式存储在客户端

Session的应用场景

购物车实现

购物车实现方案:
1.把商品存在session中
问题:

  1. 当浏览器重新打开,以前数据不在了【把书的id放在cookie】
  2. 当服务重启后,以前数据也不在【1.把书的id放在cookie,2.把session保存起来】
package com.gyf.web.servlet.lesson06;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;

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 com.gyf.model.Book;
import com.gyf.web.servlet.lesson01.DBUtils;

@WebServlet("/BuyBookServlet")
public class BuyBookServlet extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        response.setHeader("content-type","text/html;charset=utf-8");
        
        //用户买书-书放在购物车【掌握】
        
        //1.获取书的ID
        String bookId = request.getParameter("id");
        
        //2.通过书id找到这本书
        Book book = DBUtils.findBookById(Integer.parseInt(bookId));
        
        //3.把这个书放在购物车List<Book> cart
        //3.1先从session中取出购物车
        List<Book> cart = (List<Book>) request.getSession().getAttribute("cart");
        
        //3.2如果没有购物车对象,就创建一个
        if(cart == null){
            System.out.println("当前session没有购物车");
            cart = new ArrayList<Book>();
        }else{
            System.out.println("当前session有购物车");
        }
        cart.add(book);
        
        //4.把这个list放在session中
        request.getSession().setAttribute("cart", cart);
        
        //5.显示购物车的信息
        PrintWriter writer = response.getWriter();
        writer.write("购物车信息:");
        for(Book b : cart){
            writer.write("<br>" + b.getName());
        }
    }
}
package com.gyf.web.servlet.lesson06;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;

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 com.gyf.model.Book;
import com.gyf.web.servlet.lesson01.DBUtils;

@WebServlet("/ShowAllBookServlet6")
public class ShowAllBookServlet extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        response.setHeader("content-type","text/html;charset=utf-8");
        
        //1.显示书的数据给浏览器
        PrintWriter writer = response.getWriter();
        writer.write("购买图书列表<br>");
        /*
         * <a href='/项目名/BuyBookServlet?id=1'>书名</a>
         * Servlet返回给客户端的数据可以是html标签数据
         */
        for(Entry<Integer, Book> entry : DBUtils.getAllBooks().entrySet()){
            Book book = entry.getValue();
            String aStr = "<a href='http://localhost:8080" + request.getContextPath() + "/BuyBookServlet?id="+ book.getId() +"'>"+ book.getName() + "- 点击购买</a><br>";
            writer.write(aStr);
        }
    }
}

验证码登陆

package com.gyf.web.servlet.lesson07;

import java.io.IOException;
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 cn.dsna.util.images.ValidateCode;

/**
 * 验证码的Servlet
 */
@WebServlet("/ValidateCodeServlet")
public class ValidateCodeServlet extends HttpServlet {

    
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        
        //1.生成验证码
        ValidateCode vc = new ValidateCode(100, 30, 4, 6);
        System.out.println("生成的验证码" + vc.getCode());
        
        //2.把验证码存在session
        request.getSession().setAttribute("code", vc.getCode());
        
        vc.write(response.getOutputStream());
    }

}
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
    <form action="/day11-20180322/LoginServlet" method="post">
        <table border="1">
            <tr>
                <td>用户名</td>
                <td><input type="text" name="username" /></td>
            </tr>
            <tr>
                <td>密码</td>
                <td><input type="password" name="password" /></td>
            </tr>
            <tr>
                <td>验证码</td>
                <td><input type="text" name="code" /> <img alt=""
                    src="/day11-20180322/ValidateCodeServlet"></td>
            </tr>
            <tr>
                <td colspan="2"><input type="submit" value="登陆"></td>
            </tr>
        </table>
    </form>
</body>
</html>
package com.gyf.web.servlet.lesson07;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class LoginServlet
 */
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
    
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        
        response.setHeader("content-type", "text/html;charset=utf-8");
        //1.获取请求参数
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String client_code = request.getParameter("code");
        
        //2.获取服务端的code
        String server_code = (String) request.getSession().getAttribute("code");
        
        //3.验证码对比
        if(!server_code.equalsIgnoreCase(client_code)){
            response.getWriter().write("验证码不对");
        }else{
            response.getWriter().write("验证码正确");
        }
        
        //4.把验证码从服务器删除
        //request.getSession().removeAttribute("code");
        request.getSession().invalidate();//让session的所有数据都删除
        System.out.println(request.getSession().getAttribute("code"));
    }

}

HttpSession常用方法

 把数据保存在HttpSession对象中,该对象也是一个域对象。
 void setAttribute(String name,Object value);存数据
 Object getAttribute(String name);取数据
 void removeAttribute(String name);删除一个key数据
 HttpSession.getId();获取Session的ID
 setMaxInactiveInterval(int interval) 设置session的存活时间,单位是秒。
 invalidate() 使此会话无效,把session数据删除

getSession():内部执行原理

HttpSession request.getSession():内部执行原理
1、获取名称为JSESSIONID的cookie的值。
2、没有这样的cookie,创建一个新的HttpSession对象,分配一个唯一的SessionID,并且向客户端写了一个名字为JSESSIONID=sessionID的cookie
3、有这样的Cookie,获取cookie的值(即HttpSession对象的值),从服务器的内存中根据ID找那个HttpSession对象:
找到了:取出继续为你服务。
找不到:从2开始。

HttpSession request.getSession(boolean create)
参数:
true:和getSession()功能一样。
false:根据客户端JSESSIONID的cookie的值,找对应的HttpSession对象,找不到返回null(不会创建新的,只是查询)。 这个在演示的时候似乎不一样

Session的状态

Session的状态三种:

创建:当浏览器第一次访问服务器动态资源就创建
活着:服务器应用运行时
死亡:
Session.invalidate();强制销毁
超时:默认30分钟
setMaxInactiveInterval(int )单位秒

在Web.xml中配置Session的有效时间

12.png

Session的持久化

为什么要持久化Session

持久化的优点:确保在服务器重启或单个Web应用重启后,能恢复重启前的会话;
Session在其生命周期中,可能会在运行时状态和持久化状态之间转换。

搁置
会话从运行时状态变为持久化状态的过程称为 —— 搁置;
在以下情况下,Session会被搁置:
当服务器重启或单个Web应用终止时,Web应用中的Session会被搁置;
会话处于不活动状态的时间太长,达到了特定的限定值;
Web应用中处于运行状态的会话数目太多,达到了特定的限制值,部分Session被搁置

激活
会话从持久化状态变为运行时状态的过程称为激活;
在以下情况下,Session会被激活:
当服务器重启或单个Web应用重启时,Web应用中的Session会被激活
处于Session中的客户端想Web应用发出HTTP请求,相应的Session会被激活

持久化对象系列化接口

当存在Session中的对象,重启tomcat时,如果有session对象,会出现下面的问题
表示对象不能被序列化,需要让Book实现序列化接口Serialize


13.png

就是说只需要实现一个Serializable接口就可以持久化Session

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容