Cookie和Session的工作流程是什么样的?5min学懂:简易用户登录(前端+后端+数据库)

news2024/11/16 13:48:58

目录

前言

一、Cookie

1.1、Cookie从哪里来?

1.2、Cookie到哪里去?

二、Session

2.1、什么是sessionId?

三、Cookie和Session的区别

四、Cookie和Session的具体工作流程

五、代码实现用户登录

5.1、核心方法

5.2、代码


前言

        想要了解Cookie和Session的工作流程,首先需要来了解一下什么是Cookie,什么是Session?之后我将会用一个用户登录(附加:前端+后端 代码)的栗子,让你通透整个工作流程;


一、Cookie

        有时候需要让网页存储一些简单数据,但由于网页禁止js访问电脑硬盘(原因:安全性),所以就提供了特殊的api给网页用,Cookie就是最经典的一个方案,是浏览器在本地存储数据(存储到硬盘上)的一种机制;

 Cookie如何组织信息的?键值对的形式!(如下图)

Cookie是用来存放什么数据的?

  • 上次访问网页的时间;
  • 当前网页的访问次数
  • 当前访问网页网页的身份标识(最典型的应用场景);

特点:

  •         Cookie是按照域名维度来组织的,不同域名下有不同的Cookie;
  •         和query string一样,是程序员自定义的;
  •         每一个Cookie都是一个键值对;
  •         Cookie有个过期时间,到时自动清除;

        注意:Cookie不是缓存,是持久化数据的手段(保存在硬盘上),缓存的数据是用来提高访问速度的;

1.1、Cookie从哪里来?

        Cookie存在于浏览器,来源于服务器;

        解释:在网页中我们所观察的Cookie都是浏览器访问了某一个服务器后,服务器返回一个响应报文,在响应header中包含 一个/多个 Set-Cookie这样的资源(程序员自己在服务器代码中写的),浏览器接收响应后,就见Set-Cookie这样的数据保存到浏览器本地;

如下图Fiddler所捕捉到的Set-Cookie:

1.2、Cookie到哪里去?

        来自服务器,存储到浏览器,最后返回到服务器;

        解释:当浏览器保存了cookie后,下次访问同一网站,就会把之前存在本地的Cookie作为身份标识在http请求的header给返回到服务器,服务器就知道,喔,又是你来了~就把上次加载好的数据作为响应返回给浏览器;


二、Session

        服务器每一时刻接收到的请求是很多的;服务器为了区分这些请求分别是哪一个用户的,就需要记录用户和该用户信息之间的对应关系,这时Session会话机制就起到关键的作用!

        Session会话的本质就是一个哈希表,用来存放一些键值对;例如用户登录一个网站,Session的key就是用户名,value就是该用户的信息;

注意:Servlet 的 Session 默认是保存在内存中的. 如果重启服务器则 Session 数据就会丢失.

2.1、什么是sessionId?

        sessionId是由服务器生成的一个“唯一性字符串”,也可以理解为一个身份表示,通过这个,服务器就可以识别对应的用户;从session机制的角度来看,这个唯一性字符串称为 “sessionId”,但在整个登录流程来看,也可以把这个唯一字符称为 “token” ; 

如下图:


三、Cookie和Session的区别

  • Cookie是客户端机制,Session是服务器机制;
  • Cookie和Session经常一起配合使用,但不是必须配合使用;
  • 可以全都用Cookie来保存数据在客户端,这些数据不一定是用户身份信息,也不一定是token/sessionId;
  • Session的token/sessionId不一定非要通过Cookie/Set-Cookie传递;

四、Cookie和Session的具体工作流程

如下图:


五、代码实现用户登录

5.1、核心方法

把握一点:HttpSession就类似于HashMap~

方法描述
HttpSession getSession()

当服务器获取会话:

1.若该方法的参数为true,则判断当前会话是否存在,若不存在就创建一个新的键值对保存到哈希表中,并生成sessionId返回到浏览器,若存在则返回对应的HttpSession;

2.若该方法的参数为false,则判断当前会话是否存在,若不存在就返回null,若存在就返回HttpSession;

Object getAttribute(String name)

类似于HashMap的get()方法:

返回session会话中 name(key) 所对应的value;

若没有指定名称的对象,就返回null;

void setAttribute(String name, Object value)

类似于HashMap的put方法:

该方法使用指定的名称绑定一个对象到该 session 会话(绑定一对key,value);

5.2、代码

1. loginServlet实现登录界面的服务器,登录次数通过数据库持久化保存;(如下代码)

import com.mysql.jdbc.Connection;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;

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 javax.sql.DataSource;
import java.io.IOException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html; charset=utf8");
        //从客户端请求中获取用户名和密码
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        //判定账户密码是否正确
        //这里假设已经注册的账户为:
        //username:zhangsan  password:123
        if (!"zhangsan".equals(username) || !"123".equals(password)) {
            resp.getWriter().write("很抱歉,登录失败,您的用户名或密码输入错误!");
            return;
        }
        //登录成功
        System.out.println("" + username + "成功登录");
        //从数据库中获取该用户的登录次数
        int loginCount = 0;
        try {
            loginCount = load(username);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        //由于登录成功,所以登录次数加一,保存到数据库中
        try {
            save(username, String.valueOf(++loginCount));
        } catch (SQLException e) {
            e.printStackTrace();
        }
        //设置Session
        //getSession的参数true表示若查找不到HttpSession,就会新建立一个,并生成
        //一个sessionId插入哈希表,通过Set-Cookie返回给浏览器
        HttpSession session = req.getSession(true);
        //HttpSession对象自身相当于一个哈希表,可以根据需求设置里面的参数
        session.setAttribute("username", "zhangsan");
        session.setAttribute("loginCount", loginCount);
        //设置重定向到主界面index
        resp.sendRedirect("index");
    }

    //修改数据库中的数据(登录次数)
    private void save(String username, String loginCount) throws SQLException {
        //创建数据源
        DataSource dataSource = new MysqlDataSource();
        ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/login?characterEncoding=utf8&useSSL=false");
        ((MysqlDataSource)dataSource).setUser("root");
        ((MysqlDataSource)dataSource).setPassword("1111");//不嫌麻烦,你就来攻击~
        //建立连接
        Connection connection = (Connection) dataSource.getConnection();
        //构造sql
        String sql = "update message set loginCount = ? where name = ?";
        PreparedStatement statement = connection.prepareStatement(sql);
        statement.setString(1, loginCount);
        statement.setString(2, username);
        //执行sql
        int ret = statement.executeUpdate();
        //打印日志
        System.out.println("ret = " + ret);
        //关闭数据库
        statement.close();
        connection.close();
    }

    //从数据库中获取登录次数
    private int load(String username) throws SQLException {
        //创建数据源
        DataSource dataSource = new MysqlDataSource();
        ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/login?characterEncoding=utf8&useSSL=false");
        ((MysqlDataSource)dataSource).setUser("root");
        ((MysqlDataSource)dataSource).setPassword("1111");//不嫌麻烦,你就来攻击~
        //建立连接
        Connection connection = (Connection) dataSource.getConnection();
        //构造sql
        String sql = "select loginCount from message where name = ?";
        PreparedStatement statement = connection.prepareStatement(sql);
        statement.setString(1, username);
        //执行sql
        ResultSet resultSet = statement.executeQuery();
        int loginCount = 0;
        while(resultSet.next()) {//这里只对应一个结果
            loginCount = resultSet.getInt("loginCount");
        }
        //关闭数据库
        statement.close();
        connection.close();
        return loginCount;
    }
}

2. indexServlet实现登录后主页面的反馈;(如下图)

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("/index")
public class indexServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html; charset=utf8");
        //判断当前用户是否已经登录
        //getSession参数为false,表示若没有创建过HttpSession,则返回null;
        //若创建过,则返回该对象
        HttpSession session = req.getSession(false);
        if(session == null) {
            resp.getWriter().write("很抱歉,尚未登录");
            //重定向到index
            resp.sendRedirect("login");
            return;
        }
        //已登录过,就从Session中访问数据
        //这里由于getAttribute返回的是Object类型,所以这里需要强转成String
        String username = (String)session.getAttribute("username");
        int loginCount = (int)session.getAttribute("loginCount");
        resp.getWriter().write("欢迎回来:" + username + "~" + "<br>"
                + "您今日已经登录了:" + loginCount + "次");
    }
}

3. login.html 一个简易登录界面,用来发送post请求登录

<!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">
    <title>登录界面</title>
</head>
<body>
    <style>
        .container {
            width: 400px;
            margin: 0 auto;
        }
        h1 {
            padding: 10px;
            width: 200px;
            margin: 0 auto;
            text-align: center;
        }
        p {
            margin: 10px auto;
            color: gray;
            text-align: center;
        }
        .row {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 2px 0;
            width: 300px;
        }
        div input {
            height: 30px;
            width: 200px;
        }
        form {
            width: 300px;
            margin: 0 auto;
        }
        .button {
            margin: 0 auto;
            height: 40px;
            width: 300px;
            background-color: orange;
            border: none;
            color: white;
        }
        .button:active {
            background-color: rgb(251, 209, 130);
        }
    </style>
    <div class="container">
        <h1>登录界面</h1>
        <p>输入后点击登录,若信息正确自动跳转</p>
        <form class action="login" method="post">
            <div class="row">
                <span>账户</span>
                <input type="text" name="username">
            </div>
            <div class="row">
                <span>密码</span>
                <input type="password" name="password">
            </div>
            <div class="row">
                <input class="button" type="submit" value="登录">
            </div>
        </form>
    </div>
</body>
</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/30496.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【设计模式】桥接模式(Bridge Pattern)

桥接模式属于结构型模式&#xff0c;主要解决因业务增长时滥用继承而导致的**“类爆炸”问题。桥接模式将一个树型的整体继承结构替换为由抽象的类&#xff08;抽象化角色&#xff09;组成的抽象部分和由实现接口&#xff08;实现化角色&#xff09;与实现类&#xff08;具体实…

无法访问mybatis.dto.StudengInVO-使用maven编译报错

一、问题由来 最近一次拉代码后&#xff0c;合并代码然后进行编译时出现一个问题&#xff0c;使用maven在进行编译的时候报一个错&#xff0c;无法访问mybatis.dto.StudengInVO。 突然出现这个错误让自己感觉很奇怪&#xff0c;开发工具已经使用了好几个月&#xff0c;项目也已…

SSM毕设项目 - 基于SSM的汉服文化平台网站(含源码+论文)

文章目录1 项目简介2 实现效果2.1 界面展示3 设计方案3.1 概述3.2 系统流程3.3 系统结构设计4 项目获取1 项目简介 Hi&#xff0c;各位同学好呀&#xff0c;这里是M学姐&#xff01; 今天向大家分享一个今年(2022)最新完成的毕业设计项目作品&#xff0c;【基于SSM的汉服文化…

(十三)Spring之JdbcTemplate

文章目录环境新增、删除与修改数据新增修改删除查询一个查询一个对象查询一个值查询多个对象批量操作批量添加批量修改批量删除使用回调函数使用德鲁伊连接池上一篇&#xff1a;&#xff08;十二&#xff09;Spring IoC注解式开发JdbcTemplate是Spring提供的一个JDBC模板类&…

高阶数据结构:二叉搜索树

本篇主要是在初级数据结构中介绍的二叉树的提升&#xff0c;了解二叉搜索树的特性。 文章目录 一、二叉搜索树的概念二、二叉搜索树操作 1、二叉搜索树的查找2、二叉搜索树的插入3、二叉搜索树的删除三、二叉搜索树的实现四、二叉搜索树的应用五、关于二叉树进阶面试题一、二叉…

大衣哥又有喜事了,孟文豪新作《克什克腾的眼泪》,是给他写的吗

农民歌唱家大衣哥又出新歌啦&#xff01; 就在大衣哥被谷传民起诉不久&#xff0c;互联网上面又传出新消息&#xff0c;继《火火的情怀》之后&#xff0c;大衣哥的新歌《新时代的新农民》&#xff0c;又要和大家见面了。很多人不明白&#xff0c;大衣哥不过是一个农民歌唱家&am…

Java中的反射,枚举和Lambda表达式

一. 反射 1. 反射的概述 2. 反射的使用 反射常用的类 通过反射获取Class对象 获得Class类相关的方法 使用反射创建实例对象 使用反射获取实例对象中的构造方法 通过反射获取实例对象的属性 通过反射获取实例对象的方法 3. 反射的优缺点 二. 枚举 1…

Graalvm 安装和静态编译

文章目录1、下载2、graalvm安装3、native-image工具安装3.1 安装native-image3.2 安装C编译工具4、java编译成二进制exe4.1、普通的java命令行应用4.2、Swing应用编译4.3、使用maven插件静态编译4.4、javafx应用编译1、下载 文件下载&#xff1a;https://www.graalvm.org/down…

[附源码]计算机毕业设计JAVA剧本杀门店管理系统-

[附源码]计算机毕业设计JAVA剧本杀门店管理系统- 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM myb…

OBS-VirtualCam OBS的虚拟摄像头插件

OBS-VirtualCam 是OBS的一个虚拟摄像头插件&#xff0c;可以将OBS中的内容提供给一个虚拟摄像头&#xff0c;这样其它软件就可以使用这个内容了&#xff0c;这里试试这个插件功能。 1. 下载obs并安装 登录OBS Studio网站&#xff0c;下载windows版&#xff0c; 下载完成后并安装…

栈的基本操作

目录 一、什么是栈&#xff1f; 二、用单链表实现栈 三、用顺序表数组实现栈 一、什么是栈&#xff1f; 栈&#xff08;stack&#xff09;是一个先进后出&#xff08;FILO-First In Last Out&#xff09;的有序列表。 主要方法&#xff1a;入栈&#xff08;push&#xff09;…

SCA算法优化脉冲耦合神经网络的图像自动分割(Matlab代码实现)

&#x1f352;&#x1f352;&#x1f352;欢迎关注&#x1f308;&#x1f308;&#x1f308; &#x1f4dd;个人主页&#xff1a;我爱Matlab &#x1f44d;点赞➕评论➕收藏 养成习惯&#xff08;一键三连&#xff09;&#x1f33b;&#x1f33b;&#x1f33b; &#x1f34c;希…

【C语言】初识指针(终篇)

摸了一手秀发&#xff0c;发现还在~ 目录 1、指针运算 1.1指针加减整数 1.2指针减指针 1.3指针关系运算 2、二级指针 3、指针和数组 4、指针数组 前言&#xff1a; 大家好&#xff0c;我是拳击哥。上一期我们讲到了指针类型&#xff0c;指针的访问步长&#xff0c;野指针…

Redis数据类型总结

文章目录一、5种数据类型二、常用指令汇总三、应用汇总提示&#xff1a;以下是本篇文章正文内容&#xff0c;Redis系列学习将会持续更新 一、5种数据类型 Redis 数据存储格式&#xff1a;  ● redis 自身是一个 Map ,其中所有的数据都是采用 key : value 的形式存储。  ● 数…

如何设计用户体验测试用例

一、 什么是用户体验 UE&#xff1a; User Experience 用户体验。 用户体验是指用户在使用产品过程中的个人主观感受&#xff0c;即用户在使用一个产品之前、使用过程中、使用后的整体感受&#xff0c;包括行为、情感、喜好、生理和心里反应、成就等各个方面。 通俗的讲用户体…

希望所有计算机学生都知道这些宝藏网站

GitHub GitHub是一个面向开源及私有软件项目的托管平台&#xff0c;因为只支持Git作为唯一的版本库格式进行托管&#xff0c;故名GitHub。 作为开源代码库以及版本控制系统&#xff0c;Github拥有超过900万开发者用户。随着越来越多的应用程序转移到了云上&#xff0c;Github已…

数据结构与算法(五) 动态规划

这篇文章来讲动态规划&#xff08;Dynamic Programming&#xff09;&#xff0c;这是一个在面试中很经常出现的题型 1、本质 之前说过&#xff0c;解决算法问题的主流思路就是穷举搜索&#xff0c;即遍历整个搜索空间&#xff0c;找到给定问题的解 只是在某些场景下&#xff…

Python学习 - 异常处理

Python学习 - 语法入门&#xff1a;https://blog.csdn.net/wanzijy/article/details/125287855 Python学习 - 数据类型&#xff1a;https://blog.csdn.net/wanzijy/article/details/125341568 Python学习 - 流程控制&#xff1a;https://blog.csdn.net/wanzijy/article/details…

3dmax网渲云渲染哪个平台费用低?一张图要多少钱多长时间?怎么收费

话说现在的设计师应该没有不知道云渲染的吧&#xff1f;毕竟比起本地渲&#xff0c;云渲染不占本地资源&#xff0c;一次能渲很多张&#xff0c;方便又快捷&#xff0c;有谁不喜欢呢&#xff01;那么这么多的云渲染平台用哪个呢&#xff1f;今天我们就以主流的4个平台为例&…

(STM32)从零开始的RT-Thread之旅--SPI驱动ST7735(4)使用LVGL

上一篇&#xff1a; (STM32)从零开始的RT-Thread之旅--SPI驱动ST7735(3)使用DMA 经过前几章的搭建&#xff0c;底层显示已经没有问题了&#xff0c;现在需要添加上层的库&#xff0c;我选择了比较火的开源GUI库--LVGL。而RT-Thread Studio支持直接添加LVGL代码库的。 在RT-T…