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"%>




Insert title here




用户名:
密码:
记住用户名

历史记录

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 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 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 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("图书列表
"); /* * 书名 * Servlet返回给客户端的数据可以是html标签数据 */ for(Entry entry : DBUtils.getAllBooks().entrySet()){ Book book = entry.getValue(); String aStr = ""+ book.getName() + "
"; 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("
" + 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 cart
        //3.1先从session中取出购物车
        List cart = (List) request.getSession().getAttribute("cart");
        
        //3.2如果没有购物车对象,就创建一个
        if(cart == null){
            System.out.println("当前session没有购物车");
            cart = new ArrayList();
        }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("
" + 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("购买图书列表
"); /* * 书名 * Servlet返回给客户端的数据可以是html标签数据 */ for(Entry entry : DBUtils.getAllBooks().entrySet()){ Book book = entry.getValue(); String aStr = ""+ book.getName() + "- 点击购买
"; 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"%>




Insert title here


    
用户名
密码
验证码
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

你可能感兴趣的:(Session&Cookie)