Easy云盘总结篇-登录注册

**说在前面:该项目是跟着B站一位大佬写的,不分享源码,支持项目付费 **

获取图形验证码

在这里插入图片描述
可以看到这里有2两种图形验证码,分为:
type=0:如上图下面那个,是完成操作后要进行注册的验证码
type=1: 如上图上面那个,是要发送邮箱之前的图形验证码。
在这里插入图片描述
这里在交互时,设置了session值,存放了两种图形验证码,便于后面进行用户输入情况和session值比对。
那什么是session呢?
(1)Session用于记录用户的状态。Session指的是一段时间内,单个客户端与Web服务器的一连串相关的交互过程

(2)在一个Session中,客户可能会多次请求访问同一个资源,也有可能请求访问各种不同的服务器资源。

(3)Session是由服务器端创建的一个对象

可能涉及到的session操作

  • session.setAttribute(key,value)

    类似hashmap,存放键值。

  • session.getAttribute(key)

    根据key获取值,获得值的类型为object,要根据情况进行强转

  • session.removeAttribute(key)

    删除该key和对应的值,但session这个对象还在

  • session.invalidate()

    销毁了session对象

那如果是多服务器上部署这个项目,涉及多个session:

当系统部署到多台服务器时,由于每个服务器都有自己独立的内存空间,默认情况下 HttpSession 是无法在不同服务器之间共享的。这会导致用户在不同服务器上的请求无法正确识别其会话状态,例如用户在一台服务器上登录成功,但下一次请求被分配到另一台服务器时,该服务器无法获取到用户的登录状态。为了解决这个问题:

使用分布式缓存(如 Redis)是一种比较常用的解决方案。它将 Session 数据存储在 Redis 中,而不是存储在服务器的内存中。这样,所有服务器都可以通过 Redis 来获取和更新 Session 数据,从而实现了 Session 的共享。这种方案具有较好的扩展性和性能,而且可以避免会话复制带来的网络开销。

这里给出图形验证码是如何生成的:

public class CreateImageCode {// 图片的宽度。private int width = 160;// 图片的高度。private int height = 40;// 验证码字符个数private int codeCount = 4;// 验证码干扰线数private int lineCount = 20;// 验证码private String code = null;// 验证码图片Bufferprivate BufferedImage buffImg = null;Random random = new Random();public CreateImageCode() {creatImage();}public CreateImageCode(int width, int height) {this.width = width;this.height = height;creatImage();}public CreateImageCode(int width, int height, int codeCount) {this.width = width;this.height = height;this.codeCount = codeCount;creatImage();}public CreateImageCode(int width, int height, int codeCount, int lineCount) {this.width = width;this.height = height;this.codeCount = codeCount;this.lineCount = lineCount;creatImage();}// 生成图片private void creatImage() {int fontWidth = width / codeCount;// 字体的宽度int fontHeight = height - 5;// 字体的高度int codeY = height - 8;// 图像bufferbuffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);Graphics g = buffImg.getGraphics();//Graphics2D g = buffImg.createGraphics();// 设置背景色g.setColor(getRandColor(200, 250));g.fillRect(0, 0, width, height);// 设置字体//Font font1 = getFont(fontHeight);Font font = new Font("Fixedsys", Font.BOLD, fontHeight);g.setFont(font);// 设置干扰线for (int i = 0; i < lineCount; i++) {int xs = random.nextInt(width);int ys = random.nextInt(height);int xe = xs + random.nextInt(width);int ye = ys + random.nextInt(height);g.setColor(getRandColor(1, 255));g.drawLine(xs, ys, xe, ye);}// 添加噪点float yawpRate = 0.01f;// 噪声率int area = (int) (yawpRate * width * height);for (int i = 0; i < area; i++) {int x = random.nextInt(width);int y = random.nextInt(height);buffImg.setRGB(x, y, random.nextInt(255));}String str1 = randomStr(codeCount);// 得到随机字符this.code = str1;for (int i = 0; i < codeCount; i++) {String strRand = str1.substring(i, i + 1);g.setColor(getRandColor(1, 255));// g.drawString(a,x,y);// a为要画出来的东西,x和y表示要画的东西最左侧字符的基线位于此图形上下文坐标系的 (x, y) 位置处g.drawString(strRand, i * fontWidth + 3, codeY);}}// 得到随机字符private String randomStr(int n) {String str1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";String str2 = "";int len = str1.length() - 1;double r;for (int i = 0; i < n; i++) {r = (Math.random()) * len;str2 = str2 + str1.charAt((int) r);}return str2;}// 得到随机颜色private Color getRandColor(int fc, int bc) {// 给定范围获得随机颜色if (fc > 255) fc = 255;if (bc > 255) bc = 255;int r = fc + random.nextInt(bc - fc);int g = fc + random.nextInt(bc - fc);int b = fc + random.nextInt(bc - fc);return new Color(r, g, b);}/*** 产生随机字体*/private Font getFont(int size) {Random random = new Random();Font font[] = new Font[5];font[0] = new Font("Ravie", Font.PLAIN, size);font[1] = new Font("Antique Olive Compact", Font.PLAIN, size);font[2] = new Font("Fixedsys", Font.PLAIN, size);font[3] = new Font("Wide Latin", Font.PLAIN, size);font[4] = new Font("Gill Sans Ultra Bold", Font.PLAIN, size);return font[random.nextInt(5)];}// 扭曲方法private void shear(Graphics g, int w1, int h1, Color color) {shearX(g, w1, h1, color);shearY(g, w1, h1, color);}private void shearX(Graphics g, int w1, int h1, Color color) {int period = random.nextInt(2);boolean borderGap = true;int frames = 1;int phase = random.nextInt(2);for (int i = 0; i < h1; i++) {double d = (double) (period >> 1) * Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames);g.copyArea(0, i, w1, 1, (int) d, 0);if (borderGap) {g.setColor(color);g.drawLine((int) d, i, 0, i);g.drawLine((int) d + w1, i, w1, i);}}}private void shearY(Graphics g, int w1, int h1, Color color) {int period = random.nextInt(40) + 10; // 50;boolean borderGap = true;int frames = 20;int phase = 7;for (int i = 0; i < w1; i++) {double d = (double) (period >> 1) * Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames);g.copyArea(i, 0, 1, h1, 0, (int) d);if (borderGap) {g.setColor(color);g.drawLine(i, (int) d, i, 0);g.drawLine(i, (int) d + h1, i, h1);}}}public void write(OutputStream sos) throws IOException {ImageIO.write(buffImg, "png", sos);sos.close();}public BufferedImage getBuffImg() {return buffImg;}public String getCode() {return code.toLowerCase();}
}

发邮箱前验证码

在这里插入图片描述
这段的实现逻辑:

根据传过来的参数,其中type 0:注册邮箱时 1:重置密码时(后续)

先进行发邮箱前的图形验证码校对,对应后,执行发送邮箱操作。

最后,清空一下session存的当前验证码。如果验证码在使用后不被清除,那么恶意用户可能会获取到该验证码,并在后续的请求中重复使用,从而绕过验证码的验证机制,对系统的安全性造成威胁。

在这里插入图片描述
这段逻辑就是发送验证码前检验该账号是否已经注册

发送邮箱后,如果重复发送发送邮箱的话,需要将之前的邮箱验证码设置为1:用过了
在这里插入图片描述

然后是发送邮箱的实现:
在这里插入图片描述

AOP切面实现参数校验

在前端传过来的各种参数,我们需要进行非空校验,最笨的方法就是if else判断,这样耗时耗力,很不适用,为了减少冗杂性判断为空代码,通过注解作用在参数上,实现切面类判断。
首先,创建拦截器:
第一个是对参数进行校验,@GlobalInterceptor 注解的主要目的是标记需要进行特定拦截处理的方法,其中 checkParams = true 表示需要对方法的参数进行校验。
在这里插入图片描述
而这个,是对某参数进行具体的校验:
在这里插入图片描述
然后就是切面设计:AOP 可以在方法执行前拦截方法调用,并对方法的参数进行校验。
在这里插入图片描述

注册

在这里插入图片描述
这段逻辑
首先进行注册前的图形验证码校对
然后执行注册操作
最后再清空session存的当前图形验证码。

service层实现:
在这里插入图片描述
再次检查是否邮箱已经注册,比对昵称唯一(项目要求唯一)
然后根据表中之前存的邮箱和邮箱验证码,跟现在填的进行比对 ,校验通过后,插入用户信息,其中用户网盘空间分配:已用空间0,总空间初始分配5MB.
其中校验对应:在这里插入图片描述
分两种情况
1:邮箱和邮箱验证码不能对应起来,视为错误
2:邮箱验证码之前设置过15分钟内有效。一旦超时,视为无效,再次更改表,将这个邮箱验证码设置为1:已用过

System.currentTimeMillis():用来获取当前的总毫秒数

getTime():返回毫秒数

登录

在这里插入图片描述
这段的逻辑
同样检查图形验证码
然后设置了一个dto(含id昵称头像)来接收登录信息,设置session当前登录信息, 并将这个dto返回给VO
serviceImpl:
在这里插入图片描述
这段逻辑
通过邮箱比对是否该账号注册了或者密码对不上。不能分情况if,不让用户知道具体是哪个错了。
然后就算是它登录了,就要更新其登录时间,给dto的属性赋值
另外还查看是否是超级管理员,如果是,则dto的isAdmin设为true。
成功登陆后,给用户分配网盘空间。注册时是给user标注空间分配信息,现在设置的是方便在redis中存储

忘记密码

在这里插入图片描述
和注册逻辑相似,重置密码,主要就是更新一下password。而发送邮箱等业务是已经完成了的,才把emailCode传过来了。
在这里插入图片描述

修改密码

这个和忘记密码重置有区别,忘记密码是没登录进去时重置,这个是登进去后在个人设置里修改。
controller
在这里插入图片描述
这段逻辑
通过继承AbaseController类里的方法getUserInfoFromSession,通过session找到其SESSION_KEY对应的dto返回,再通过dto获取当前用户id,进行密码修改。

获取默认头像

在这里插入图片描述

mkdir()和mkdirs()
创建文件夹。
mkdir方法是用于创建最后一个/后面的文件夹,最后一个/前面的文件夹必须都存在。
mkdirs方法是无论父文件夹是否存在都会创建。

这段逻辑

先在配置文件中定义了项目根目录文件夹,随后定义文件file/和用于存放头像的avatar/文件夹,如果没有这个文件夹,就创建。总的合起来组成一个完整的头像路径字符串
项目根目录/file/avatar/user123.jpg
如果还是没有这个文件,再看看有没有设置默认头像路径 项目根目录/file/avatar/default.jpg
然后读取文件。

上传头像

在这里插入图片描述
这段逻辑
先获取dto用户信息,然后就是找到或创建存放头像的文件夹,将用户上传的文件保存到这个文件夹里
因为自定义头像需要覆盖原来的qq头像,所以qq头像设置为空
然后webUserDto的avatar也被设为null,并更新到session中,这样下次请求时用户的最新头像信息会被重新加载现在自定义好的或者使用默认头像。

关于MultipartFile

MultipartFile:

public interface MultipartFile extends InputStreamSource {
//getName() 返回参数的名称
String getName();
//获取源文件的昵称
@Nullable
String getOriginalFilename();
//getContentType() 返回文件的内容类型
@Nullable
String getContentType();
//isEmpty() 判断是否为空,或者上传的文件是否有内容
boolean isEmpty();
//getSize() 返回文件大小 以字节为单位
long getSize();
//getBytes() 将文件内容转化成一个byte[] 返回
byte[] getBytes() throws IOException;
//getInputStream() 返回InputStream读取文件的内容
InputStream getInputStream() throws IOException;default Resource getResource() {return new MultipartFileResource(this);
}
//transferTo是复制file文件到指定位置(比如D盘下的某个位置),不然程序执行完,文件就会消失,程序运行时,临时存储在temp这个文件夹中
void transferTo(File var1) throws IOException, IllegalStateException;default void transferTo(Path dest) throws IOException, IllegalStateException {FileCopyUtils.copy(this.getInputStream(), Files.newOutputStream(dest));
}
}

这里前端传过来文件,我们用MultipartFile avatar 接收

关于getPath()

将抽象路径名转换为一个路径名字符串。所得到的字符串使用默认名称分隔符来分隔名称序列中的名称。

public   static   void  test1() {File file1 = new File(".\\test1.txt");File file2 = new File("D:\\workspace\\test\\test1.txt");System.out.println("-----默认相对路径:取得路径不同------");System.out.println(file1.getPath());System.out.println(file1.getAbsolutePath());System.out.println("-----默认绝对路径:取得路径相同------");System.out.println(file2.getPath());System.out.println(file2.getAbsolutePath());  
}----- 默认相对路径:取得路径不同 ------
.\test1.txt
D:\workspace\test\.\test1.txt
----- 默认绝对路径:取得路径相同 ------
D:\workspace\test\test1.txt
D:\workspace\test\test1.txt

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

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

相关文章

【前端知识】Vue3状态组件Pinia详细介绍

Vue3状态组件Pinia详细介绍 关联知识 Pinia 组件介绍、核心原理及使用方式 Pinia 组件介绍 Pinia 是 Vue.js 的官方状态管理库&#xff0c;专为 Vue 3 设计&#xff0c;提供简洁的 API 和强大的 TypeScript 支持。其核心组件包括&#xff1a; • Store&#xff1a;状态存储容器…

mysql 云服务远程linux创建数据库

1. 本地使用已创建好的用户创建数据库出现问题 提示access deniey finalshell远程创建新用户 :~# mysql -u root -pR***34 > CREATE DATABASE r***e; > CREATE USER r**ue% IDENTIFIED BY Ry****34; > GRANT ALL PRIVILEGES ON ry_vue.* TO r***e%; > FLUSH PRI…

【“星瑞” O6 评测】 — CPU llama.cpp不同优化速度对比

前言 随着大模型应用场景的不断拓展&#xff0c;arm cpu 凭借其独特优势在大模型推理领域的重要性日益凸显。它在性能、功耗、架构适配等多方面发挥关键作用&#xff0c;推动大模型在不同场景落地 1. Kleidi AI 简介 Arm Kleidi 成为解决这些挑战的理想方案&#xff0c;它能…

wireshark抓包也能被篡改?

wireshark本身并不能修改数据包&#xff0c;但是tcprewrite 可以修改数据包&#xff0c;然后通过tcpreplay 进行重放&#xff0c;这个时候wireshark抓的包&#xff0c;就是被篡改后的pcap包了。 ailx10 网络安全优秀回答者 互联网行业 安全攻防员 去咨询 步骤一&#xff1a…

使用PyTorch进行热狗图像分类模型微调

本教程将演示如何使用PyTorch框架对预训练模型进行微调&#xff0c;实现热狗与非热狗图像的分类任务。我们将从数据准备开始&#xff0c;逐步完成数据加载、可视化等关键步骤。 1. 环境配置与库导入 %matplotlib inline import os import torch from torch import nn from d2l…

内容中台与企业内容管理核心差异剖析

功能定位与架构设计差异 在企业数字化进程中&#xff0c;内容中台与企业内容管理&#xff08;ECM&#xff09;的核心差异首先体现在功能定位层面。传统ECM系统以文档存储、版本控制及权限管理为核心&#xff0c;主要服务于企业内部知识库的静态管理需求&#xff0c;例如通过Ba…

使用PyMongo连接MongoDB的基本操作

MongoDB是由C语言编写的非关系型数据库&#xff0c;是一个基于分布式文件存储的开源数据库系统&#xff0c;其内容存储形式类似JSON对象&#xff0c;它的字段值可以包含其他文档、数组及文档数组。在这一节中&#xff0c;我们就来回顾Python 3下MongoDB的存储操作。 常用命令:…

第 12 届蓝桥杯 C++ 青少组中 / 高级组省赛 2021 年真题

一、选择题 第 1 题 题目&#xff1a;下列符号中哪个在 C 中表示行注释 ( )。 A. ! B. # C. ] D. // 正确答案&#xff1a;D 答案解析&#xff1a; 在 C 中&#xff0c;//用于单行注释&#xff08;行注释&#xff09;&#xff0c;从//开始到行末的内容会被编译器忽略。选项 A…

【python】【UV】一篇文章学完新一代 Python 环境与包管理器使用指南

&#x1f40d; UV&#xff1a;新一代 Python 环境与包管理器使用指南 一、UV 是什么&#xff1f; UV 是由 Astral 团队开发的高性能 Python 环境管理器&#xff0c;旨在统一替代 pyenv、pip、venv、pip-tools、pipenv 等工具。 1.1 UV 的主要功能 &#x1f680; 极速包安装&…

前端性能优化2:结合HTTPS与最佳实践,全面优化你的网站性能

点亮极速体验&#xff1a;结合HTTPS与最佳实践&#xff0c;为你详解网站性能优化的道与术 在如今这个信息爆炸、用户耐心极其有限的数字时代&#xff0c;网站的性能早已不是一个可选项&#xff0c;而是关乎生存和发展的核心竞争力。一个迟缓的网站&#xff0c;无异于在数字世界…

JavaWeb:vueaxios

一、简介 什么是vue? 快速入门 <!-- 3.准备视图元素 --><div id"app"><!-- 6.数据渲染 --><h1>{{ msg }}</h1></div><script type"module">// 1.引入vueimport { createApp, ref } from https://unpkg.com/vu…

Tauri联合Vue开发中Vuex与Pinia关系及前景分析

在 TauriVue 的开发场景中&#xff0c;Vuex 和 Pinia 是两种不同的状态管理工具&#xff0c;它们的关系和前景可以从以下角度分析&#xff1a; 一、Vuex 与 Pinia 的关系 继承与发展 Pinia 最初是作为 Vuex 5 的提案设计的&#xff0c;其目标是简化 Vuex 的复杂性并更好地适配 …

Linux中的时间同步

一、时间同步服务扩展总结 1. 时间同步的重要性 多主机协作需求&#xff1a;在分布式系统、集群、微服务架构中&#xff0c;时间一致性是日志排序、事务顺序、数据一致性的基础。 安全协议依赖&#xff1a;TLS/SSL证书、Kerberos认证等依赖时间有效性&#xff0c;时间偏差可能…

【算法基础】三指针排序算法 - JAVA

一、基础概念 1.1 什么是三指针排序 三指针排序是一种特殊的分区排序算法&#xff0c;通过使用三个指针同时操作数组&#xff0c;将元素按照特定规则进行分类和排序。这种算法在处理包含有限种类值的数组时表现出色&#xff0c;最经典的应用是荷兰国旗问题&#xff08;Dutch …

《操作系统真象还原》第十二章(2)——进一步完善内核

文章目录 前言可变参数的原理实现系统调用write更新syscall.h更新syscall.c更新syscall-init.c 实现printf编写stdio.h编写stdio.c 第一次测试main.cmakefile结果截图 完善printf修改main.c 结语 前言 上部分链接&#xff1a;《操作系统真象还原》第十二章&#xff08;1&#…

ICML2021 | DeiT | 训练数据高效的图像 Transformer 与基于注意力的蒸馏

Training data-efficient image transformers & distillation through attention 摘要-Abstract引言-Introduction相关工作-Related Work视觉Transformer&#xff1a;概述-Vision transformer: overview通过注意力机制蒸馏-Distillation through attention实验-Experiments…

深度学习:AI 机器人时代

在科技飞速发展的当下&#xff0c;AI 机器人时代正以汹涌之势席卷而来&#xff0c;而深度学习作为其核心驱动力&#xff0c;正重塑着我们生活与工作的方方面面。 从智能工厂的自动化生产&#xff0c;到家庭中贴心服务的智能助手&#xff0c;再到复杂环境下执行特殊任务的专业机…

《告别试错式开发:TDD的精准质量锻造术》

深度解锁TDD&#xff1a;应用开发的创新密钥 在应用开发的复杂版图中&#xff0c;如何雕琢出高质量、高可靠性的应用&#xff0c;始终是开发者们不懈探索的核心命题。测试驱动开发&#xff08;TDD&#xff09;&#xff0c;作为一种颠覆性的开发理念与方法&#xff0c;正逐渐成…

应用层自定义协议序列与反序列化

目录 一、网络版计算器 二、网络版本计算器实现 2.1源代码 2.2测试结果 一、网络版计算器 应用层定义的协议&#xff1a; 应用层进行网络通信能否使用如下的协议进行通信呢&#xff1f; 在操作系统内核中是以这种协议进行通信的&#xff0c;但是在应用层禁止以这种协议进行…

Excel-CLI:终端中的轻量级Excel查看器

在数据驱动的今天&#xff0c;Excel 文件处理成为了我们日常工作中不可或缺的一部分。然而&#xff0c;频繁地在图形界面与命令行界面之间切换&#xff0c;不仅效率低下&#xff0c;而且容易出错。现在&#xff0c;有了 Excel-CLI&#xff0c;一款运行在终端中的轻量级Excel查看…