【easy视频 | day01】项目了解 + 登录注册 + 使用 token 作为客户端请求令牌
文章目录
- 前言
- 完成任务
- 1. 项目了解
- 2. 登录注册
- 2.1 创建数据表
- 2.2 验证码
- 如果使用 Session 存储验证码:
- 不用 Session 存储验证码,用 Redis 会有什么问题?
- 2.3 注册功能
- 2.4 登录功能
- 2.5 自动登录
- 2.6 退出登录
- 总结

前言
本项目非原创,我只是个小小白,跟随 b 站脚步,找到老罗的这个项目,视频来源于:
高仿B站(单服务版) springboot项目实战 easylive
本人不分享项目源码,支持项目付费!!!
完成任务
1. 项目了解
这是一个仿 b 站的项目,页面分为客户端和后台管理端,可发布视频,在线互动(评论、点赞、投币、发弹幕),后台管理对视频进行审核。
项目采用微服务架构构建,系统架构图:
- 正常线上部署会有 nginx 集群,本地上不存在 nginx 集群,直接就是:前端 ——> 网关。
- 有很多个服务,服务跑起来后,每个服务有一个端口,但是这些服务的端口都不对外,对外的端口只有一个,就是 gateway 的端口。
- 服务与服务之间存在相互调用。
- Nacos 实现服务发现注册、作为配置中心。微服务部署加上 nginx 集群的情况下,将每个的配置抽离出来,放在一个配置中心进行配置,修改的时候不用一个个地去改,只需要修改配置中心。
2. 登录注册
2.1 创建数据表
根据该系统的用户特点,创建用户数据表。
为什么用邮箱发送验证码 ,而不使用手机号 ?
手机号发送验证码需要做财务报表,需要付费;邮箱目前接收验证码不需要付费。对于一个小型的项目,使用邮箱验证码就足够了。
注意:创建表字段后,某些字段可设置不为 NULL、主键、默认值;还需要设计必要的索引。
2.2 验证码
如果使用 Session 存储验证码:
后端将生成的验证码 code 保存到 Session 会话中,当前端调用获取验证码的该接口时,响应头 Set-Cookie 中会包含 JSESSIONID :
如果此时,在进行 register 注册时,校验所填的验证码是否与刚刚存入 Session 的验证码相同,发起的请求中,也会携带这个 JSESSIONID:
JSESSIONID 就是一个会话的标记,使用 Session 会返回一个 JSESSIONID 来标记这个会话,下一次请求时,就会携带这个 JSESSIONID,判断这两个请求是否是同一个会话发出来的(会话可认为是一个浏览器,或者说新开的一个浏览器页面)。如果是同一个会话,校验验证码时就会获取存入当前会话 Session 中的验证码与前端填入的验证码进行比较;如果不是同一个会话,那么获取验证码请求和注册请求都不是同一个 JSESSIONID,那么就不可能从 Session 中获取到刚刚存入的验证码。
不用 Session 存储验证码,用 Redis 会有什么问题?
这里请求验证码时,将验证码保存在 Redis 中,设置过期时间为 10 分钟。
注册时,获取 Redis 中的验证码与前端传入的验证码进行比对:
比对成功,返回 true;不成功,返回 false。
但是,
这里有一个问题,当用户 A 获取验证码 a 后,将 a 存入 Redis;此时,另外一个用户 B 也获取验证码,得到验证码 b ,Redis 会将最新获得的验证码 b 存入,遮蔽掉先前存入的验证码 a。用户 A 输入他获得的验证码 a 进行校验,后端就会从 Redis 中取出最新获得的 b 与之校验,用户 A 就发现不匹配,就会觉得疑惑:明明输入是正确的,为什么就是不匹配呢?
原因就是 Redis 中存储验证码的 key 是定死了的,就是 “checkCode”,全站所有人都用的这一个 key,每个人请求一下获取验证码的接口,这个 key 的值就更新了。它不是一个用户的唯一标识。
所以说,直接这样使用 Redis 来存储验证码,是不可行的。
但就是要用 Redis 来存储验证码,该怎么实现呢 ?
让每个用户请求验证码时,存入 Redis 的 key 是唯一的,能唯一标识这个用户。可以随机生成一个随机数作为每个用户验证码的 key,返回客户端数据时,将对应的 key 也和验证码图片一起返回。
Redis 保存、获取和清除验证码的方法:
UUID:是 Java 中一个主要为对象生成一个唯一标识符的类
randomUUTD():生成一个随机的 UUID 对象,由 128 位数字组成,通常由 32 位十六进制表示,中间用破折号连接。
controller 层调用:
2.3 注册功能
先看 contoller 层中的参数:
这里直接使用注解对方法参数进行校验。要使用 @NotEmpty、@Email、@Size 这些注解,需要在 Controller 类上加上 @Validated 注解。
@NotEmpty: 确保参数不为空。
@Email: 确保字符串是一个有效的电子邮件地址。
@Size: 确保字符串的长度不超过指定的最大值。
@Pattern: 确保字符串符合指定的正则表达式。
密码的正则表达式通常是,至少包含一个数字和一个英文字母,密码长度在 8~18 之间,可以包含特殊字符:
public static final String REGEX_PASSWORD = "^(?=.*\\d)(?=.*[a-zA-Z])[\\da-zA-Z~!@#$%^&*_]{8,18}$";
service 层实现:
用户 ID 使用工具类方法中,随机生成字符串来实现:
第一个生成指定长度的字符串,可以包含字母和数字;第二个生成指定长度的字符串,不能包含字母。用户 ID 不需要字母,使用的是第二个。
设置用户密码,使用 MD5 加密:
这里直接使用 Apache 库中的 DigestUtils 类,计算给定字符串的 MD5 值。
2.4 登录功能
controller 层:
需要获取用户的 IP 地址,通过 HttpServletRequest 来获取用户 ip:
protected String getIpAddr() {HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();String ip = request.getHeader("x-forwarded-for");if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {// 多次反向代理后会有多个ip值,第一个ip才是真实ipif (ip.indexOf(",") != -1) {ip = ip.split(",")[0];}}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("Proxy-Client-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("WL-Proxy-Client-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("HTTP_CLIENT_IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("HTTP_X_FORWARDED_FOR");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("X-Real-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getRemoteAddr();}return ip;}
sevice 层:
之前是使用 Session 来存储用户登录后的标识,在这里使用 token 来作为用户标识,以便于用户登录后,无需再重新登录,可以继续访问。
这里返回的 TokenUserInfoDto 中除了用户相关信息,还有 token 及其过期时间:
@JsonIgnoreProperties(ignoreUnknown = true)注解:无论传入的JSON数据中是否包含类中未定义的属性,这些属性都会被忽略,而不会导致反序列化失败。在这里非常有用,如果说这个类中添加了其它属性,这个注解能保证数据的反序列化不会失败。
Redis 中存储 token 和用户信息,设置 token 值及其过期时间:
还有一步,将这个 token 手动地存入到 Cookie 中:
其实,获得 tokenUserInfoDto 后可以直接返回的,返回给前端后,前端去存放这个 token。但是为了保险,我们也可以像 Session 一样,Session 会在 Cookie 中存放一个 JSESSIONID,这其实就是服务端的工作。我们也可以将 token 存放在 Session 中:
成功访问 login 接口后,可看到 Cookie 中会有 token :
这样的话,当前用户再次访问其它接口,就不需要前端参与,Cookie 会自动将 token 携带过来。
如果服务端还要获取 token 的话,直接使用 Response 不太方便,需要循环寻找,因为 Cookie 中有很多东西,获取 Cookie 得到的是一个数组,还需要遍历数组才能拿到 token。 但是,前端会从 Cookie 里把 token 解析出来,然后放到 head 头中带过来,这时候,在后端,就可以通过 @RequestHeader(“token”) 拿到 token。
登录最后,不能忘记还要清理掉 Redis 中的 验证码,token 可清理也可不清理:
2.5 自动登录
用户第一次成功登录后,Cookie 中会存在一个 token,设置的有效期为 7 天,7 天以内打开这个页面,应该是自动登录的:
如果是 7 天以内,再次登录,还需要再此执行 saveTokenInfo,重新生成一个 token,并重新开始计算时间:
并将这个重新生成的 token 存入 Cookie 中。
2.6 退出登录
退出登录,需要做的就是清理掉 Cookie 和 Redis 中的 token:
总结
一般来说,一个项目的登录注册功能,往往是这个项目动手写代码时第一个要做的功能。这部分功能包括验证码获取、注册、登录、自动登录、退出登录等。这段功能理解起来并不复杂,重点就是对 Redis 数据的操作、细节的把控、以及代码书写规范。
在老罗的这个项目里,通过登录注册功能就可以学到很多以前不太了解的知识:尤其是 token 的使用,Session 的理解。
相关文章:

【easy视频 | day01】项目了解 + 登录注册 + 使用 token 作为客户端请求令牌
文章目录 前言完成任务1. 项目了解2. 登录注册2.1 创建数据表2.2 验证码如果使用 Session 存储验证码:不用 Session 存储验证码,用 Redis 会有什么问题? 2.3 注册功能2.4 登录功能2.5 自动登录2.6 退出登录 总结 前言 本项目非原创,我只是个…...
使用elasticdump导出/导入 -- ES数据
导出指定索引数据到指定文件夹: ./elasticdump --inputhttp://用户:密码IP:9201/索引名字 --output导出路径/out.json --typedata 将导出的文件导入 ./elasticdump --input路径/out.json --outputhttp://账号:密码IP:9201/索引名称 --typedata --fileTypejson 【el…...
React + TypeScript 复杂布局开发实战
React TypeScript 复杂布局开发实战 一、项目架构设计(基于最新技术栈) 1.1 技术选型与工程创建 # 使用Vite 5.x React 19 TypeScript 5.4 npx create-vitelatest power-designer-ui --template react-ts cd power-designer-ui && npm inst…...
工业AR眼镜的‘芯’动力:FPC让制造更智能【新立电子】
随着增强现实(AR)技术的快速发展,工业AR智能眼镜也正逐步成为制造业领域的重要工具。它不仅为现场工作人员提供了视觉辅助,还极大地提升了远程协助的效率、优化了仓储管理。新立电子其高性能的FPC产品在AI眼镜中的应用,…...
mapbox实现添加历史轨迹,并进行动画播放效果
1、引入播放插件类 https://download.csdn.net/download/qq_48795482/90437319 2、添加图层 drawRouteLine(resData, layerType) {console.log("调用了轨迹线函数", resData);var jsondata {type: "FeatureCollection",features: [],};var linejsondat…...

最好Wordpree+Apache+PHP安装教程
前提需要 PHP的安装最少需要7.4以上Mysql的安装,直接默认最新版就行APache服务器(HTTP服务器,只有用这个你的软件才能在服务器上运行) 安装apache 安装 sudo apt install apache2查看防火墙 sudo ufw app list如果有 Apache那…...

Windows搭建jenkins服务
jenkins下载 官网:https://www.jenkins.io 中文文档:Jenkins 直接可下载网址:Jenkins 的安装和设置 安装前准备 在安装 jenkins 之前要先确保电脑上是否已配置过 Java 的环境变量,可调出命令窗口(win R 再输入 cmd&…...
鸿蒙-AVPlayer
compileVersion 5.0.2(14) 音频播放 import media from ohos.multimedia.media; import common from ohos.app.ability.common; import { BusinessError } from ohos.base;Entry Component struct AudioPlayer {private avPlayer: media.AVPlayer | nu…...

解决单元测试 mock final类报错
文章目录 前言解决单元测试 mock final类报错1. 报错原因2. 解决方案3. 示例demo4. 扩展 前言 如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^ _ ^。 而且听说点赞的人每天的运气都不会太差࿰…...

Kafka消费者相关
Kafka生产者相关-CSDN博客 消费者消费数据基本流程 package com.hrui;import org.apache.kafka.clients.consumer.ConsumerConfig; import org.apache.kafka.clients.consumer.ConsumerRecord; import org.apache.kafka.clients.consumer.ConsumerRecords; import org.apache…...
Vue nextTick原理回顾
nextTick就是将异步函数放在下一次实践循环的微任务队列中执行 实现原理比较简单,极简版本: function myNextTick(cb){let p;pPromise.resolve().then(cb)return cb?p:Promise.resolve() }复杂版本,考虑异步函数入队、执行锁、兼容处理 l…...

JavaWeb登录认证
在Web系统中,如果没有登录功能和登录认证,是可以直接访问到Web系统的后台的。 这是不安全的,所以我们今天的主题就是登录认证。最终要实现的效果是: 如果用户名密码错误,不允许登录系统。如果用户名和密码都正确&…...

半导体制造工艺(二)光刻工艺—掩模版
在上文中我们已经简单概述了光刻工艺的大致流程。接下来将会介绍在光刻工艺中所需用到的必备材料以及设备。例如掩模版、光刻胶、匀胶机、光刻机等等。由于需要保持讲述工艺的完整性以及流畅,每一个都需要涉及,所以每次仅是侧重点不同。此篇主要讲述的是…...

计算机视觉算法实战——高精度分割(主页有源码)
✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ 1. 高精度分割领域简介✨✨ 图像分割是计算机视觉中的核心任务之一,其目标是将图像划分为多个语义区域,并为…...

DeepSeek-R1-Zero:基于基础模型的强化学习
注:此文章内容均节选自充电了么创始人,CEO兼CTO陈敬雷老师的新书《自然语言处理原理与实战》(人工智能科学与技术丛书)【陈敬雷编著】【清华大学出版社】 文章目录 DeepSeek大模型技术系列四DeepSeek大模型技术系列四》DeepSeek-…...
判断一个文件中以三个#号开头有多少行的shell脚本怎么写
在Linux中,你可以使用grep命令结合正则表达式来统计一个文件中以三个#号开头的行数。以下是一个简单的命令: grep -c ^### filename这里的grep是搜索工具,-c选项表示统计匹配的行数,###是正则表达式,表示行…...
PHP如何与HTML结合使用?
PHP与HTML结合使用的主要方式是通过在HTML文件中嵌入PHP代码,从而实现动态内容的生成和网页的交互性。以下是详细的方法和最佳实践: 1. 嵌入PHP代码到HTML中 PHP代码可以直接嵌入到HTML文件中,通过<?php ?>标签来包裹PHP代码。服务…...
计算机网络之传输层(传输层的功能)
一、数据分段与重组 传输层从会话层接收数据,并将其分割成较小的数据段,以适应网络层的最大传输单元(MTU)限制。在目的端,传输层负责将这些数据段重新组合成原始数据,确保数据的完整性和正确性。 二、端口…...

矩阵碰一碰发视频源码搭建之,支持OEM
引言 阵碰一碰发视频" 技术凭借其便捷的交互方式和高效的传播能力,已成为品牌推广和内容创作的重要工具。为进一步提升视频传播效果,本文将深入探讨如何在矩阵碰一碰系统中集成 AI 文案生成功能,实现 "一碰即传 智能文案" 的…...
DeepSeek 2月27日技术突破:三大核心功能解析与行业影响
DeepSeek 2月27日技术突破:三大核心功能解析与行业影响 一、最新发布功能全景图 1. DualPipe:双向流水线并行革命 DualPipe是一项极具创新性的双向管道并行算法,旨在解决大规模模型训练过程中计算与通信效率低下的关键问题。在传统的模型训…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
Java - Mysql数据类型对应
Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序
一、开发环境准备 工具安装: 下载安装DevEco Studio 4.0(支持HarmonyOS 5)配置HarmonyOS SDK 5.0确保Node.js版本≥14 项目初始化: ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

三分算法与DeepSeek辅助证明是单峰函数
前置 单峰函数有唯一的最大值,最大值左侧的数值严格单调递增,最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值,最小值左侧的数值严格单调递减,最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...
python爬虫——气象数据爬取
一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用: 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests:发送 …...

如何应对敏捷转型中的团队阻力
应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中,明确沟通敏捷转型目的尤为关键,团队成员只有清晰理解转型背后的原因和利益,才能降低对变化的…...

MySQL体系架构解析(三):MySQL目录与启动配置全解析
MySQL中的目录和文件 bin目录 在 MySQL 的安装目录下有一个特别重要的 bin 目录,这个目录下存放着许多可执行文件。与其他系统的可执行文件类似,这些可执行文件都是与服务器和客户端程序相关的。 启动MySQL服务器程序 在 UNIX 系统中,用…...