Java Web Session技术详解(全网最详细) (原理分析 + 简易购物车相关案例)

1.什么是Session

        简单来说Session也是会话技术的一种,另一种是Cookie,在BS架构浏览器,与服务器进行交互过程中,数据的保存一是保存在浏览器端也就是Cookie的作用,二是保存在服务器端也就是Session的作用。会话就是人与人之间的交流,在这里就是一个用户浏览器和服务器之间的交流。一次会话产生,服务器就会为此用户浏览器创建一个唯一的Session对象,并分配唯一的JSESSIONID标识符。

2.Session的注意点

1.  Session 是服务器端技术,服务器在运行时为每一个用户的浏览器创建一个其独享的
session 对象/集合
2. 由于 session 为各个用户浏览器独享,所以用户在访问服务器的不同页面时,可以从各自
session 中读取 / 添加数据 , 从而完成相应任务
3. Session 的作用可以用来标识一次会话,或者说确认一个用户;并且在一次会话(一个用户的多次请 求)期间共享数据。我们可以通过 request.getSession()方法,来获取当前会话的 session 对象
4. session 无论客户端还是服务器端都可以感知到,若重新打开一个新的浏览器,则无法取得之前设置 session,因为不同的浏览器是不同的用户,浏览器的Cookie里面有JSESSIONID,就是为该浏览器用户分配的唯一的ID标识符,具体原理下面讲解
5.session也可以看做是一个集合或者容器,session的默认存在时间是30s具体位置在你下载的Tomcat 的conf/web.xml里
如图:

3.Session的基本原理

原理示意图:

解释如下:当浏览器通过HTTP请求访问服务器的时候,服务器通过request.getSession()对session进行获取时,就会从HTTP请求中的Cookie信息中获取是否有对应的JSESSIONID(用来表示唯一的用户)

如果有JSESSIONID,则会判断对应JSESSIONID中是否创建了session对象,如果有JSESSIONID多对应的对象,则服务器对session对象进行相应的业务处理,如果没有session对象,服务器会为此对话创建一个session对象,并分配一个JSESSIONID,并最后通过HTTP响应以Cookie的形式将JSESSIONID=xxx保存在浏览器中(这样浏览器的Cookie中有了JSESSIONID,在HTTP请求时,服务器才知道此会话是哪一个用户)。

如果没有JSESSIONID,服务器会直接创建一个session对象,并为此对象创建一个JSESSIONID标识符,通过Cookie的形式传入给浏览器,会发现浏览器的响应头中有Set-Cookie: JSESSIONID= xxx。

对Session原理进行抓包分析

写的代码程序:

package exercise;

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

/**
 * @author sn
 */
@WebServlet("/d")
public class SessionID extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        HttpSession session = req.getSession();
        String id = session.getId();
        PrintWriter writer = resp.getWriter();
        writer.println("此会话的JSESSIONID="+id);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}

浏览器结果:(注意的是在Tomcat启动的时候不要默认同时打开浏览器,因为默认打开浏览器,浏览器会默认访问网站的index.html的首页面,此时服务器会为浏览器中也会被分配一个JSESSIONID,但因为没有session的相关操作,所以不会有session对象出现,当你再次访问服务器的时候,抓包分析会看到有JSESSIONID的存在。) 如果未讲清楚请留言,将进行抓包分析。

4.Session的生命周期:

注意的是Session的生命周期和Cookie的不一样,Cookie的生命周期是一创建就开始计时,而Session的生命周期是两次请求的最大间隔时长,比如Session的默认存在时间是30分钟,如果你在30分钟里再次发出了HTTP请求,那么Session又会以30分钟重新计时比如15分钟访问了一次,那么45分才会过期。而Cookie是无论你是否发出HTTP请求,时间一到就会被销毁。

1. public void setMaxInactiveInterval(int interval) 设置 Session 的超时时间(以秒为单位),
超过指定的时长,Session 就会被销毁。


2. 值为正数的时候,设定 Session 的超时时长。


3. 负数表示永不超时


4. public int getMaxInactiveInterval()获取 Session 的超时时间


5. public void invalidate() 让当前 Session 会话立即无效


6. 如果没有调用 setMaxInactiveInterval() 来指定 Session 的生命时长,Tomcat 会以 Session
默认时长为准,Session 默认的超时为 30 分钟, 可以在 tomcat 的 web.xml 设置


7. Session 的生命周期指的是 :客户端/浏览器两次请求最大间隔时长,而不是累积时长。
即当客户端访问了自己的 session,session 的生命周期将从 0 开始重新计算。(老韩解读: 指
的是同一个会话两次请求之间的间隔时间)


8. 底层: Tomcat 用一个线程来轮询会话状态,如果某个会话的空闲时间超过设定的最大值,
则将该会话销毁

5.Session相关的使用方法

1.创建和获取Session的API是一样的

HttpSession sn=request.getSession();

2. 向Session中添加属性

sn.setAttribute(String name,Object val);

3.向Session中得到属性

Object obj=sn.getAttribute(String name);

4.删除Session中的某个属性

sn.removeAttribute(String name);

5.isNew判断Session是否是刚创建出来的

sn.isNew();

6.防止用户非法访问登录管理界面实例+过滤器(简易唯美界面)

采用了过滤器指的是当你只有登录完成过后才能登录到成功登录的界面,你不能通过URL地址栏

去访问成功登录过后的界面(过滤器的作用更加的安全)

效果演示:

代码展示

目录:

LoginMonitorFilter:

package filter;

import javax.servlet.*;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

/**
 * @author ygd
 */
public class LoginMonitorFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        HttpSession session = httpServletRequest.getSession();
        Object username = session.getAttribute("username");
        if(username != null)
        {
            filterChain.doFilter(servletRequest,servletResponse);
        }
        else {
            httpServletRequest.getRequestDispatcher("/index.jsp").forward(servletRequest,servletResponse);
        }

    }

    @Override
    public void destroy() {

    }
}

LoginCheckServlet:

package login;

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;

/**
 * @author sn
 */
@WebServlet("/lcs")
public class LoginCheckServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        //这里用两个用户名
        if("zhangsan".equals(username) && "123456".equals(password))
        {
            //将用户名保存到session中去
            HttpSession session = req.getSession();
            session.setAttribute("username",username);
            req.getRequestDispatcher("/login_handle/success.jsp").forward(req,resp);
        }

        else if("lisa".equals(username) && "123456".equals(password))
        {
            //将用户名保存到session中去
            HttpSession session = req.getSession();
            session.setAttribute("username",username);
            req.getRequestDispatcher("/login_handle/success.jsp").forward(req,resp);
        }
        else{
            req.getRequestDispatcher("/index.jsp").forward(req,resp);
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req,resp);
    }
}

login.css:

*{
    user-select: none;
    /* 无法选中,整体感更强 */
}

body{
    background: url(wallpaper.jpg) no-repeat;
    background-size: cover;
    background-attachment: fixed;
}

.login{
    position: absolute;
    top: 50%;
    margin-top: -200px;
    left: 50%;
    margin-left: -200px;
    /* absolute居中的一种方法 */
    background-color: whitesmoke;
    width: 400px;
    height: 400px;
    border-radius: 25px;
    text-align: center;
    padding: 5px 40px;
    box-sizing: border-box;
    /* 这样padding就不会影响大小 */
}

p{
    font-size: 42px;
    font-weight: 600;
}

input{
    background-color: whitesmoke;
    width: 100%;
    height: 48px;
    margin-bottom: 10px;
    border: none;
    border-bottom: 2px solid silver;
    /* 下面的会覆盖上面的步伐 */
    outline: none;
    font-size: 22px;
}

.btn{
    background-color: #59c2c5;
    width: 38%;
    height: 48px;
    border-radius: 8px;
    margin-top: 40px;
    font-size: 28px;
    font-weight: 600;
    color: white;
}
.btn:hover{
    background-color: #59c2a0;
}

success.jsp

<%--
  Created by IntelliJ IDEA.
  User: Administrator :ygd
  Date: 2024/4/14
  Time: 12:58
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登陆成功</title>
</head>
<body>
<h2>登录成功,欢迎您~<%=request.getParameter("username")%></h2>

</body>
</html>

index.jsp:

<%--
  Created by IntelliJ IDEA.
  User: Administrator :ygd
  Date: 2024/4/14
  Time: 12:41
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="css/login.css">
  <title>Document</title>
</head>
<body><form action="${pageContext.request.contextPath}/lcs" class="login">
  <p>Login</p>
  <input type="text" placeholder="用户名" name="username">
  <input type="password" placeholder="密码" name="password">
  <input type="submit" class="btn" value="登  录">
</form>

</body>
</html>

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <filter>
        <filter-name>LoginMonitorFilter</filter-name>
        <filter-class>filter.LoginMonitorFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>LoginMonitorFilter</filter-name>
        <url-pattern>/login_handle/*</url-pattern>
    </filter-mapping>
</web-app>

7.简易购物车案例(更新完毕)

结果展示(至于前端界面以及后续更复杂的购物车系统将在后续持续更新)

 

 


 

代码目录展示 


 

 Cake

package entity;

/**
 * @author sn
 */
public class Cake {
    private static final long serialVersionUID =1L;
    private String id;
    private String name;

    private double price;

    public Cake(String id, String name, double price) {
        this.id = id;
        this.name = name;
        this.price = price;
    }

    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;
    }
}

 


 

CakeDB

package entity;

import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author sn
 */
public class CakeDB {
    private static Map<String,Cake> cake = new LinkedHashMap<>();
    static {
        cake.put("1",new Cake("1","A类蛋糕",50));
        cake.put("2",new Cake("2","B类蛋糕",60));
        cake.put("3",new Cake("3","C类蛋糕",70));
        cake.put("4",new Cake("4","D类蛋糕",52));
        cake.put("5",new Cake("5","E类蛋糕",40));
    }
    public static Collection<Cake> getAll()
    {
        return cake.values();
    }

    public static Cake getCake(String id)
    {
        return cake.get(id);
    }

}

 


 CartServlet

package servlet;

import entity.Cake;

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;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.List;

/**
 * @author sn
 */
@WebServlet("/CartServlet")
public class CartServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf8");
        PrintWriter writer = resp.getWriter();
        List<Cake> cart = null;
        boolean pruFlag = true;
        HttpSession session = req.getSession();
        if(session == null)
        {
            pruFlag = false;
        }else{
            cart = (List) session.getAttribute("cart");
            if(cart == null)
            {
                pruFlag = false;
            }
        }
        //如果你直接进入购物车的话
        if(!pruFlag)
        {
            writer.write("对不起您没有购买商品<br>");
        }else {
            double all_price = 0;
            writer.write("您购买的商品有<br>");
            for(Cake cake:cart)
            {
                writer.write(cake.getName() +" 单价:"+cake.getPrice()+"<br>");
                all_price += cake.getPrice();
            }
            writer.write("总计价格为:"+all_price);
        }

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req,resp);
    }
}

 


 ListCaketServlet

package servlet;

import entity.Cake;
import entity.CakeDB;

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;

/**
 * @author sn
 */
@WebServlet("/list")
public class ListCakeServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf8");
        PrintWriter writer = resp.getWriter();
        //将模拟数据库中的所有蛋糕都放入列表中显现
        Collection<Cake> cakes = CakeDB.getAll();
        writer.write("本店所提供的蛋糕有:<br>");
        for (Cake cake : cakes)
        {
            String url = "PurchaseServlet?id="+cake.getId();
            writer.write(cake.getName()+" 单价:"+cake.getPrice()+"<a href='"
            +url+"'>点击购买</a><br>");
        }
       
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req,resp);
    }
}

 


 PurchaseServlet

package servlet;

import entity.Cake;
import entity.CakeDB;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * @author sn
 */
@WebServlet("/PurchaseServlet")
public class PurchaseServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        String id = req.getParameter("id");
        //相当于过滤器的一种替代
        if(id == null)
        {
            String url = "list";
            resp.sendRedirect(url);
            return;
        }
        Cake cake = CakeDB.getCake(id);
        HttpSession session = req.getSession();
        List<Cake> cart = (List) session.getAttribute("cart");

        if(cart == null)
        {
            cart = new ArrayList<Cake>();
            session.setAttribute("cart",cart);
        }
        //将商品放入购物车
        cart.add(cake);
        //创建Cookie存放Session的标识符
        Cookie cookie = new Cookie("JSESSIONID", session.getId());
        cookie.setMaxAge(30*60);
        resp.addCookie(cookie);

        //重定向到购物车的界面
        String url = "CartServlet";
        resp.sendRedirect(url);


    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req,resp);
    }
}

 当启动Tomcat过后在地址栏中加入list便可访问资源列表

  • 20
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值