Session 服务器端数据存储技术


Session

  • 使用 Cookie 的问题:
    • 最多存储 4K 字符串;
    • 存储数据不太安全。
  • Session 作用:在一次会话的多次请求之间共享数据,将数据 保存到服务器端

1. HttpSession

  • HttpSession 是 Java 平台对 Session 机制的实现规范,HttpSession 也是一个域对象。
  • 常用 API:
    1. 存储数据:
      void setAttribute(String name,Object value)
    2. 获取数据:
      Object getAttribute(String name)
    3. 删除数据:
      void removeAttribute(String name)

2. 存取与获得 Session

a. 将数据存储到 Session 中

  1. 通过 Request 对象,获取 Session 对象:
    HttpSession session = request.getSession();
  2. 操作 Session 的 API,存储数据:
    session.setAttribute("username","Regino,哈哈");

b. 从 Session 中获取数据

  1. 通过 Request 对象,获取 Session 对象:
    HttpSession session = request.getSession();
  2. 操作 Session 的 API,获取数据:
    session.getAttribute("username");

c. 代码示例

  • SetSession:
package servlet;

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;
import java.io.IOException;

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

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

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.通过rquest对象,获取session对象
        HttpSession session = request.getSession();
        // 2.操作session的API,存储数据
        session.setAttribute("username", "Regino,哈哈");
    }
}
  • GetSession:
package servlet;

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;
import java.io.IOException;

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

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

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.通过rquest对象,获取session对象
        HttpSession session = request.getSession();
        // 2.操作session的API,获取数据
        String username = (String) session.getAttribute("username");
        System.out.println("GetSession获取:" + username);
    }
}

3. Session 的工作原理

  • Session 是基于 Cookie 技术实现的。
    在这里插入图片描述

a. 第一次请求的 Request

在这里插入图片描述

b. 第二次请求的 Response

在这里插入图片描述

c. 创建 Session 空间

  • HttpSession session = request.getSession();
    • 如果用户是第 1 次访问,表示创建 Session 对象,并生成编号;
    • 如果用户是第 N 次访问,根据浏览器携带编号找 Session 对象,如果没找到再创建。

d. IDEA 中的 Session 位置

  • 先找到 IDEA 克隆 Tomcat 时复制出的临时空间:
    在这里插入图片描述
  • 根据空间找到对应的 Session 文件:
    在这里插入图片描述

4. JSESSIONID

  • JSESSIONID 就是 Session 的 ID。
  • JSESSIONID 只是 Tomcat 中对 Session ID 的叫法,在其它容器里面,不一定是叫 JSESSIONID。
  • JSESSIONID 与 Session 是唯一对应关系。

a. 客户端关闭,服务器不关闭

  • 两次获取的 Session 数据是否为相同?
    • 默认情况下,浏览器关闭,再次打开后两次获取的 Session 不一样。因为 Session 是基于 Cookie 的实现(浏览器关闭,Cookie 会销毁)
    • 通过设置 Cookie 的存活时间(即指定 JSESSIONID 的存活时间)可以改变 Session 的存活时间:cookie.setMaxAge(60);
i. 关闭浏览器,如何找回 Session
  • 需要创建一个同名的 Cookie,保存 Session 的 ID,并且设置有效时间。

b. 客户端不关闭,服务器关闭

  • 两次获取的 Session 数据是否为相同?
    • 当服务器正常关闭,重启后两次获取的 Session 数据一样。
    • 原因:Tomcat 实现了以下 2 个功能:
      • 钝化(序列化):当 Tomcat 服务器正常关闭时,Session 中的数据,会序列化到磁盘;
      • 活化(反序列化):当 Tomcat 服务器开启后,数据从磁盘文件中,被反序列化到内存中,从而重新读取到 Session 的数据。
  • 注意:IDEA 默认仅支持钝化,不支持活化。因为 Session 会话在 IDEA 关闭后会自动清除。要让 IDEA 支持活化,可以强制设置 IDEA 重启时,不清除 Session 会话:
    在这里插入图片描述
i. 关闭服务器,如何保存 Session 的数据
  • Tomcat 会完成钝化的工作,只不过钝化的数据所属的类一定要实现 Serializable 接口。
ii. Session 钝化的注意事项
  • 钝化的数据所属类一定要实现 Serializable 接口,否则无法钝化。
1. 实体类
package servlet;

import java.io.Serializable;

public class User implements Serializable {

    private int id;

    private String name;



    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}
2. SetSession
package servlet;

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;
import java.io.IOException;

@WebServlet("/setSession")
public class SetSession extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.  创建一个User对象
        User user = new User();
        user.setId(110);
        user.setName("Regino");
        //2. 获取Session
        HttpSession session = request.getSession();


        //3. 把User对象存储到Session中
        session.setAttribute("user", user);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}
3. GetSession
package servlet;

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;
import java.io.IOException;

@WebServlet("/getSession")
public class GetSession extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        HttpSession session = request.getSession();
        //从Session获取User
        User user = (User) session.getAttribute("user");

        response.getWriter().write("从Session获取到的数据:" + user);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}
  • 出现了 22-Apr-2020 02:25:59.169 严重 [RMI TCP Connection(3)-127.0.0.1] org.apache.tomcat.util.modeler.BaseModelMBean.invoke Exception,导致 Tomcat 启动失败:
    在这里插入图片描述
  • 成功 Debug。原来是把 GetSession 里的 @WebServlet("/getSession") 也写成了 "/setSession"
4. 测试

5. Session 的生命周期

a. 何时创建

  • 用户第一次调用 request.getSession() 方法时创建。
  • 如果用户是第 N 次访问,根据浏览器携带编号找 Session 对象,如果没找到再创建。

b. 何时销毁

  • 非活跃状态 30 分钟(默认)后。
i. 自定义销毁时间
  • Tomcat 可以进行配置 /tocmat安装目录/conf/web.xml。推荐在项目下的 web.xml(默认继承了 Tomcat 中的 web.xml)中修改,不建议修改全局。
<session-cofig>
	<session-timeout>30</session-timeout>
</session-config>
ii. 其他销毁方式
  • 服务器非正常关闭时。
  • 调用 session.invalidate(); 方法时(表示 Session 对象的自杀)。

c. 作用范围

  • 一次会话中,多次请求之间。
  • 注意:每一个浏览器跟服务器都是独立的会话。

6. URL 的重写

  • Session 基于 Cookie 技术实现的,而浏览器的 Cookie 是可以被禁用的,所以一旦禁用之后,Session 就会出现问题。
  • 开发中,一般是不关注用户的 Cookie 是否被禁用,如果要处理用户禁用 Cookie 的问题,可以使用 URL 重写技术。即用另一个 Servlet 处理获得的 JSESSIONID。

a. 写入 Session

package servlet;

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;
import java.io.IOException;

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

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

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 获取Session对象
        HttpSession session = request.getSession();
        // 向Session中存数据
        session.setAttribute("username", "浏览器禁用了Cookie,但不影响使用");

        // 定义URL
        String url = "/webappPractice2/GetSession?JSESSIONID=" + session.getId();

        // 重写URL,拼接JSESSIONID
        url = response.encodeURL(url);
        System.out.println(url);// /webappPractice2/GetSession?JSESSIONID=547B2304838BDDCE7C7A1A8F572DE9ED

        response.setContentType("text/html;charset=utf-8");
        response.getWriter().write("<a href='" + url + "'>跳转到获取Session内容</a>");
    }
}

b. 获得 Session

  • 与一般的获得 Session 的 Servlet 一样就可以,不用改变。
package servlet;

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;
import java.io.IOException;

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

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

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.通过rquest对象,获取session对象
        HttpSession session = request.getSession();
        // 2.操作session的API,获取数据
        String username = (String) session.getAttribute("username");
        System.out.println("GetSession获取:" + username);
    }
}

c. 测试

7. Session 的特点

  1. Session 存储数据在服务器。
  2. Session 存储类型任意(Object)。
  3. Session 存储大小和数量没有限制(相对于内存)。
  4. Session 存储相对安全。

8. Cookie 和 Session 的选择

a. 选择 Cookie

  • Cookie 存储的数据保存在浏览器端,相对不安全:
  • Cookie 存储的数据成本低,对服务器要求不高;
  • 建议敏感的数据不要放在 Cookie 中;
  • Cookie 存储的数据大小是有限制的,但是可以通过在浏览器端存放 localStroage,来解决这个容量不足的问题。

b. 选择 Session

  • Session 存储的数据在服务器端,相对安全;
  • Session 存储的数据大小要比 Cookie 中的数据灵活很多;
  • Session 存储的数据成本较高,对服务器压力较大。

9. 综合案例:商品购物车

a. 主要需求

  • 有一个商品页面,可以点击超链接将商品添加到购物车,还有一个超链接,点击它的时候可以查看购物车中商品信息。

b. 步骤分析

在这里插入图片描述

c. 代码实现

i. goods.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>goods.jsp</title>
</head>
<body>
<h3>商品列表</h3>
<a href="/webappPractice2/AddCartServlet?name=电视机">电视机,加入购物车</a><br>
<a href="/webappPractice2/AddCartServlet?name=冰箱">冰箱,加入购物车</a><br>
<a href="/webappPractice2/AddCartServlet?name=洗衣机">洗衣机,加入购物车</a><br>
<a href="/webappPractice2/AddCartServlet?name=电脑">电脑,加入购物车</a><br>
</body>
</html>
ii. AddCartServlet
package servlet;

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.util.HashMap;
import java.util.Map;

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

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

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8"); // 请求解码
        response.setContentType("text/html;charset=utf-8");// 响应编码

        // 1.获取请求参数
        String product = request.getParameter("name");
        // 2.返回结果
        response.getWriter().write(product + ",商品已成功加入购物车<br>");

        // 3.从Session中获取购物车
        Map<String, Integer> cart = (Map<String, Integer>) request.getSession().getAttribute("cart");

        // 4.判断购物车是否为空
        if (cart == null) {
            cart = new HashMap<>();
        }
        // 5.判断购物车中是否包含本次添加的商品
        if (cart.containsKey(product)) {// 6.存在,数量+1
            Integer oldCount = cart.get(product); // 之前数量
            cart.put(product, oldCount + 1);// 数量加1
        } else { // 7.不存在,直接添加商品,数量为1
            cart.put(product, 1);
        }
        // 8.重新将购物车,写入到Session中
        request.getSession().setAttribute("cart", cart);

        // 9.继续浏览
        response.getWriter().write("<a href='/webappPractice2/goods.jsp'>继续浏览</a><br>");
        // 10.查看购物车
        response.getWriter().write("<a href='/webappPractice2/cart.jsp'>查看购物车</a><br>");
    }
}
iii. cart.jsp
<%@ page import="java.util.Map" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>cart</title>
</head>
<body>
<h3>购物车页面</h3>

<table border="1" width="200px" align="center">
    <tr>
        <th>商品</th>
        <th>数量</th>
    </tr>
    <%
        // 1.从Session中获取购物车
        Map<String, Integer> cart = (Map<String, Integer>) request.getSession().getAttribute("cart");
        // 2.判断是否为空
        if (cart == null) {
            out.write("购物车内暂时没有商品<br>");
        } else {
            for (String s : cart.keySet()) {
                out.write("<tr><td>" + s + "</td><td>" + cart.get(s) + "</td></tr>");
            }
        }
    %>
</table>
</body>
</html>
  • JSP 要放在 web 目录下,src 中只能放 Java 文件。
  • JSP 虽然在应用上更接近浏览器端,但是操作上更接近服务器端,而且不管静态动态资料都会在 Tomcat 中运行的,所以 JSP 一般和 Servlet 一起出现在服务器里。
iv. 测试

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

10. 综合案例:用户登录(有验证码)

a. 主要需求

  • 用户访问带有验证码的登录页面,输入用户名,密码以及验证码实现登录功能。

b. 步骤分析

在这里插入图片描述

c. 代码实现

i. 创建 web 项目

在这里插入图片描述

ii. CheckcodeServlet
package servlet;

import javax.imageio.ImageIO;
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.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

@WebServlet("/CheckcodeServlet")
public class CheckcodeServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //  创建画布
        int width = 120;
        int height = 40;
        BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        //  获得画笔
        Graphics g = bufferedImage.getGraphics();
        //  填充背景颜色
        g.setColor(Color.white);
        g.fillRect(0, 0, width, height);
        //  绘制边框
        g.setColor(Color.red);
        g.drawRect(0, 0, width - 1, height - 1);
        //  生成随机字符
        //  准备数据
        String data = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";
        //  准备随机对象
        Random r = new Random();
        //  声明一个变量 保存验证码
        String code = "";
        //  书写4个随机字符
        for (int i = 0; i < 4; i++) {
            //  设置字体
            g.setFont(new Font("宋体", Font.BOLD, 28));
            //  设置随机颜色
            g.setColor(new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255)));

            String str = data.charAt(r.nextInt(data.length())) + "";
            g.drawString(str, 10 + i * 28, 30);

            //  将新的字符 保存到验证码中
            code = code + str;
        }
        //  绘制干扰线
        for (int i = 0; i < 6; i++) {
            //  设置随机颜色
            g.setColor(new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255)));

            g.drawLine(r.nextInt(width), r.nextInt(height), r.nextInt(width), r.nextInt(height));
        }

        //  将验证码 打印到控制台
        System.out.println(code);

        //  将验证码放到session中
        request.getSession().setAttribute("code_session", code);

        //  将画布显示在浏览器中
        ImageIO.write(bufferedImage, "jpg", response.getOutputStream());
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
iii. login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>login.jsp</title>
</head>
<body>
<h3>用户登录</h3>
<form action="/webappPractice2/LoginServlet" method="post">
    用户:<input type="text" name="username"> <br>
    密码:<input type="password" name="password"><br>
    验证码:<input type="text" name="checkcode"> <img src="/webappPractice2/CheckcodeServlet" alt=""><br>
    <input type="submit" value="登录">
    <span style="color:red">
        <%
            String error = (String) request.getAttribute("error");
            if (error != null) {
                out.write(error);// 输出提示信息
            }
        %>
    </span>
</form>
</body>
</html>
iv. LoginServlet
package servlet;

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;

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

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

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");
        // 1.获取用户输入的验证码
        String checkcode = request.getParameter("checkcode");
        // 2.获取Session中验证码
        String codeSession = (String) request.getSession().getAttribute("code_session");
        // 3.校验是否匹配
        if (!checkcode.equalsIgnoreCase(codeSession)) {
            // 验证码不配,友情提示...
            request.setAttribute("error", "验证码输入错误...");
            // 转发到login.jsp
            request.getRequestDispatcher("/login.jsp").forward(request, response);
            // 代码不在往下执行....
            return;
        }

        // 4.获取用户输入的用户名和密码
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        // 5.判断用户名密码不正确
        if (!("Regino".equals(username) && "123".equals(password))) {
            // 友情提示
            request.setAttribute("error", "用户名或密码错误...");
            // 转发到login.jsp
            request.getRequestDispatcher("/login.jsp").forward(request, response);
            // 代码不在往下执行....
            return;
        }

        // 6. 将用户名存入到Session中
        request.getSession().setAttribute("username", username);
        // 7.重定向到success.jsp
        response.sendRedirect(request.getContextPath() + "/success.jsp");
    }
}
v. success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>success</title>
</head>
<body>
<h3><%
    // 获取用户信息
    String username = (String) request.getSession().getAttribute("username");
    if (username != null) {
        out.write("用户您好,登录成功:"+username);
    }
%></h3>
</body>
</html>
vi. 测试

原文链接:https://qwert.blog.csdn.net/article/details/105640570

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值