会话之session

session简介

在WEB开发中,服务器可以为每个客户端浏览器创建一个session对象,默认情况下一个浏览器独占一个session对象。在实际应用当中,服务器程序可以把一些敏感数据写到用户浏览器独占的session中可以提高安全性,当用户使用浏览器访问其它程序时,其它程序可以从用户的session中取出该用户的数据,为用户服务。

session和cookie的主要区别是:

  • session存储在服务器端
  • cookie存储在客户端

JavaEE中的session

在javax.servlet.http包下有个HttpSession类,通过该类就可以操作session。
获取Session对象的方式:通过调用request对象中的getSession()方法就可以获取Session对象了,不需要手动new创建。

Session中常用的方法:

  • public void setAttribute(String name, Object value)
    该方法用于向 Session 的中放入一个键值对。
  • public Object getAttribute(String name)
    该方法用于从 Session 中根据名字获取值。
  • public void removeAttribute(String name)
    该方法用于从Session中删除数据。

代码示例:
创建一个名为SessionTest01的servlet用来接收用户传入的数据并放到session对象中:

package com.monkey1024.servlet.session;

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;

/**
 * session
 */
public class SessionTest01 extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        String name = request.getParameter("name");
        //得到一个HttpSession对象
        HttpSession session = request.getSession();
        session.setAttribute("name", name);

    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}

创建一个名为SessionTest02的servlet从session对象中取得之前用户传入的数据:

package com.monkey1024.servlet.session;

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;

/**
 * session
 */
public class SessionTest02 extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        //得到一个HttpSession对象
        HttpSession session = request.getSession();
        String  name = (String) session.getAttribute("name");
        System.out.println("你的姓名是:" + name);


    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}

首先访问第一个servlet,在url中写上name的数据:
localhost:8080/07-03-cs/session01?name=monkey
再访问第二个servlet:
localhost:8080/07-03-cs/session02
在eclipse控制台中可以看到第一个servlet中传入的name数据

再打开另外一个浏览器直接访问第二个servlet:
localhost:8080/07-03-cs/session02
此时控制台中打印的结果是null
这说明Web开发中的 Session机制会为每个浏览器分配了一个 Session。即一个浏览器一个 Session,不同的Session之间的数据不能共享。

session工作原理
服务器会为每个浏览器分配一个session,每个浏览器只能访问自己的session对象,可http协议是无状态的,那服务器是如何识别这些浏览器的呢?
服务器对Session对象是以Map的形式进行管理的,每创建一个session对象,服务器都会向该Map中的 key放入一个32位长度的随机串,这个随机串称为JSessionID, 之后将该session对象的引用放入到map的value中。
session放入到Map之后,服务器还会自动将”JSESSIONID”作为 name,32位长度的随机串作为value,放到cookie中并发送到客户端。该cookie会默认放到浏览器的缓存中,只要浏览器不关闭就一直存在。
当浏览器第二次向服务器发送请求时会携带该cookie,服务器接收到之后会根据JSessionID从Map中找到与之对应的session对象。

session原理

Session的失效
若某个Session 在指定的时间范围内一直未被访问,那么 Session 将超时,即将失效。在 web.xml 中可以通过标签设置 Session 的超时时间,单位为分钟。默认 Session 的超时时间为 30 分钟。这个时间并不是从 Session 被创建开始计时的生命周期时长,而是从最后一次被访问开始计时,在指定的时长内一直未被访问的时长。

 <!-- 设置失效时间为60分钟 -->
 <session-config>
      <session-timeout>60</session-timeout>
 </session-config>

可以在servlet中调用session中的invalidate()方法使session失效:

//使session失效
session.invalidate();

数据空间范围对比

在 JavaWeb 编程的 API 中,存在三个可以存放数据的空间范围对象,这三个对象中所
存储的数据作用范围,由大到小分别为:
ServletContext—>HttpSession—>HttpServletRequest
ServletContext,即application,置入其中的数据是整个web应用范围的,可以完成跨会话
共享数据。
HttpSession,置入其中的数据是会话范围的,可以完成跨请求共享数据。
HttpServletRequest,置入其中的数据是请求范围的,可以完成跨 Servlet 共享数据。
但这些 Servlet 必须在同一请求中。
对于这三个域属性空间对象的使用原则是,在可以保证功能需求的前提下,优先使用小
范围的。这样不仅可以节省服务器内存,还可以保证数据的安全性。

数据范围对比

数据范围对比

练习

1.使用web中的session来实现网站购物车功能

答案

代码:

假设是一个图书的购物网站,因此创建一个实体类Book:

package com.monkey1024.servlet.bean;

/**
 * 图书
 *
 */
public class Book {

    private String id;
    private String name;
    private double price;
    private String author;

    public Book(){

    }

    public Book(String id, String name, double price, String author) {
        this.id = id;
        this.name = name;
        this.price = price;
        this.author = author;
    }
    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;
    }
    public double getPrice() {
        return price;
    }
    public void setPrice(double price) {
        this.price = price;
    }
    public String getAuthor() {
        return author;
    }
    public void setAuthor(String author) {
        this.author = author;
    }
    @Override
    public String toString() {
        return "Book [id=" + id + ", name=" + name + ", price=" + price
                + ", author=" + author + "]";
    }

}

创建一个用于初始化图书数据的DBUtil工具类(实际应用中会从数据库中读取):

package com.monkey1024.servlet.util;

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

import com.monkey1024.servlet.bean.Book;

/**
 * 初始化图书数据
 *
 */
public class DBUtil {
    private static Map<String, Book> books = new HashMap<String, Book>();

    static{
        books.put("1", new Book("1", "java快速入门", 20, "马化腾"));
        books.put("2", new Book("2", "java进阶之路", 30, "李彦宏"));
        books.put("3", new Book("3", "java高手速成", 40, "马云"));
        books.put("4", new Book("4", "java编程之道", 50, "雷军"));
    }

    //取得全部图书
    public static Map<String, Book> findAllBooks(){
        return books;
    }

    /**
     * 根据id查找指定的书
     * @param id
     * @return
     */
    public static Book findBookById(String id){
        return books.get(id);
    }
}

创建用户展示书籍的servlet:

package com.monkey1024.servlet.session;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;

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

import com.monkey1024.servlet.bean.Book;
import com.monkey1024.servlet.util.DBUtil;

/**
 * 展示书籍
 */
public class ShowBookServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        out.print("全部java书籍:<br/>");

        //取得全部书籍
        Map<String, Book> books = DBUtil.findAllBooks();

        //生成html
        for (Map.Entry<String, Book> book : books.entrySet()) {
            String url1 = "/AddCart?id="+book.getKey();
            out.print("<a href='"+url1+"' >"+book.getValue().getName()+"</a><br/>");
        }
        String url2 = "/ShowCart";
        out.print("<a href='"+url2+"'>查看购物车</a> <br/>");

        String url3 = "/ClearCart";
        out.print("<a href='"+url3+"'>清空购物车</a> <br/>");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}

创建向购物车中添加数据的servlet:

package com.monkey1024.servlet.session;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.monkey1024.servlet.bean.Book;
import com.monkey1024.servlet.util.DBUtil;

/**
 * 向购物车中添加书籍
 */
public class AddCartServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        //取得书籍的id
        String id = request.getParameter("id");
        //得到session对象
         HttpSession session = request.getSession();
        //从session中取出map,其中key存储图书编号,value存储数量
        Map<String,Integer>  map= (Map<String,Integer>)session.getAttribute("ShoppingCart");
        if(map==null){
            map = new HashMap<String,Integer>();
        }
        //如果是null则说明还未向购物车中添加过
        if(map.get(id) == null){
            map.put(id, 1);
        }else{
            //向购物车中书籍的数量加1
            map.put(id, map.get(id) + 1);
        }

        //把map放回到session中
        session.setAttribute("ShoppingCart", map);
        out.print("购物车添加成功!");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}

创建用于展示购物车中数据的servlet:

package com.monkey1024.servlet.session;

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

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.monkey1024.servlet.bean.Book;
import com.monkey1024.servlet.util.DBUtil;

/**
 * 展示购物车中的数据
 */
public class ShowCartServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        out.print("购物车有以下商品:<br/>");
        HttpSession session = request.getSession();
        //得到session对象
        Map<String,Integer> books = (Map<String,Integer>)session.getAttribute("ShoppingCart");
        if(books==null){
            out.print("购物车为空");
            response.setHeader("refresh", "2;url=/ShowBook");
            return;
        }
        for (Map.Entry<String, Integer> book : books.entrySet()) {
            Book b = new Book();
            b = DBUtil.findBookById(book.getKey());
            out.write("名称:" + b.getName() + ",数量:" + book.getValue() + "<br/>");
        }
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}

创建用于清空购物车的servlet:

package com.monkey1024.servlet.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;
import javax.servlet.http.HttpSession;

/**
 * 清空购物车
 */
public class ClearCartServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        HttpSession session = request.getSession();
        session.removeAttribute("ShoppingCart");
        out.write("购物车清空成功!");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}