【综合项目】api系统——基于Node.js、express、mysql等技术
目录
0 前言
1 初始化
2 注册登录
2.1 注册
2.1.1 功能:密码加密(2.3.3)
2.1.1.1 操作
2.1.1.2 bcryptjs详解
2.1.2 插入新用户(2.3.4)
2.1.3 优化:表单数据验证(2.5)
2.1.3.1 过时代码修正
2.1.3.2 关键操作
2.2 登录
2.2.1 判断密码是否正确(2.6.3)
2.2.2 生成 JWT 的 Token 字符串的注意点(2.6.4)
3 个人中心
3.1 更新用户基本信息
3.1.1 验证表单数据(3.2.2)
3.2 重置密码
3.2.1 验证表单数据(3.3.2)
3.3 更新头像
3.3.1 验证表单数据(3.4.2)
4 文章分类管理
4.1 根据Id更新文章分类数据
4.1.1 查询分类名称与别名是否被占用(4.5.4)
5 文章管理
5.1 发布新文章
5.1.1 使用 multer 解析表单数据(5.2.3)
5.1.2 验证表单数据(5.2.4)
5.1.3 新建数据对象(5.2.5)
0 前言
本章仅记录部分功能代码(以前文章中未涉及的新内容)以及所遇到的问题
详细内容见 项目首页 - api系统 - GitCode 中的指导文档
❗❗❗最终完整代码也会上传至GitCode中,收藏方便查找
注:部分标题后面跟了原文档中的序号,方便查看
1 初始化
此部分暂无内容
2 注册登录
2.1 注册
2.1.1 功能:密码加密(2.3.3)
2.1.1.1 操作
使用 bcryptjs 对用户密码进行加密
安装指定版本的 bcryptjs :
npm i bcryptjs@2.4.3
导入 bcryptjs :
const bcrypt = require('bcryptjs')
在注册用户的处理函数中,确认用户名可用之后,调用 bcrypt.hashSync(明文密码, 随机盐的长度) 方法,对用户的密码进行加密处理:
// 对用户的密码,进行 bcrype 加密,返回值是加密之后的密码字符串
userinfo.password = bcrypt.hashSync(userinfo.password, 10)
2.1.1.2 bcryptjs详解
bcrypt.hashSync 是 `bcrypt` 库中用于同步生成哈希值的函数,在 Node.js 中经常使用该库来对密码等敏感信息进行哈希处理。以下详细介绍 bcrypt.hashSync 函数的参数:
函数
bcrypt.hashSync(data, saltOrRounds);
参数说明
1. data
类型:string
描述:需要进行哈希处理的数据,通常是用户的密码。这是一个必需的参数,代表你要加密的原始文本。
2. saltOrRounds
类型:string 或 number
描述:该参数可以是一个盐值(string 类型),也可以是生成盐的轮数(number 类型)。
当 saltOrRounds 为 number 类型时
它代表生成盐的轮数,也称为成本因子(cost factor)。这个值越大,生成盐和哈希值所花费的时间就越长,安全性也相对更高。推荐的值通常在 10 - 12 之间。
bcrypt 会根据这个轮数自动生成一个随机的盐值,然后使用这个盐值对 data 进行哈希处理。当 saltOrRounds 为 string 类型时
它代表一个预先定义好的盐值。使用自定义盐值时,每次使用相同的盐和数据进行哈希处理,会得到相同的哈希结果。
一般情况下,不建议手动指定盐值,因为 bcrypt 自动生成的随机盐值可以更好地保证安全性。
返回值
bcrypt.hashSync 函数会返回一个包含盐值和哈希值的字符串,这个字符串可以安全地存储在数据库中,用于后续的密码验证。
2.1.2 插入新用户(2.3.4)
判断插入是否成功
if (results.affectedRows !== 1) {
return res.send({ status: 1, message: '注册用户失败,请稍后再试!' })
}
即判断影响数据行数是否为1
2.1.3 优化:表单数据验证(2.5)
2.1.3.1 过时代码修正
const joi = require('@hapi/joi') 的写法现在已经失效,
应该这样导入:const joi = require('joi')
2.1.3.2 关键操作
安装 @hapi/joi 包,为表单中携带的每个数据项,定义验证规则:
npm install @hapi/joi@17.1.0
安装 @escook/express-joi 中间件,来实现自动对表单数据进行验证的功能:
npm i @escook/express-joi
常用验证规则:
除此之外,本文下方的验证表单数据中还包含一些其他常用规则
/*** string() 值必须是字符串* alphanum() 值只能是包含 a-zA-Z0-9 的字符串* min(length) 最小长度* max(length) 最大长度* required() 值是必填项,不能为 undefined* pattern(正则表达式) 值必须符合正则表达式的规则*/
注意:一定要先指定一种数据类型string()或者其他(包括any()),然后才能执行后续操作
导出规则
// 注册和登录表单的验证规则对象
exports.reg_login_schema = {
// 表示需要对 req.body 中的数据进行验证body: {username,password,},}
使用规则
// 1. 导入验证表单数据的中间件
const expressJoi = require('@escook/express-joi')// 2. 导入需要的验证规则对象
const { reg_login_schema } = require('../schema/user')//...router.post('/reguser', expressJoi(reg_login_schema), userHandler.regUser)
2.2 登录
2.2.1 判断密码是否正确(2.6.3)
使用加密密码的包bcrypt
返回值是布尔值(true 一致、false 不一致)
bcrypt.compareSync(用户提交的密码, 数据库中的密码)
示例:
// 拿着用户输入的密码,和数据库中存储的密码进行对比
const compareResult = bcrypt.compareSync(userinfo.password, results[0].password)
// 如果对比的结果等于 false, 则证明用户输入的密码错误
if (!compareResult) {return res.cc('登录失败!')
}
// TODO:登录成功,生成 Token 字符串
2.2.2 生成 JWT 的 Token 字符串的注意点(2.6.4)
核心注意点:在生成 Token 字符串的时候,一定要剔除 密码 和 头像 的值
通过 ES6 的高级语法,快速剔除 密码 和 头像 的值:
// 剔除完毕之后,user 中只保留了用户的 id, username, nickname, email 这四个属性的值
const user = { ...results[0], password: '', user_pic: '' }
3 个人中心
3.1 更新用户基本信息
3.1.1 验证表单数据(3.2.2)
记录新属性
const id = joi.number().integer().min(1).required()const nickname = joi.string().required()const email = joi.string().email().required()
integer() 方法用于验证一个值是否为整数
3.2 重置密码
3.2.1 验证表单数据(3.3.2)
body: {// 使用 password 这个规则,验证 req.body.oldPwd 的值oldPwd: password,newPwd: joi.not(joi.ref('oldPwd')).concat(password),},
使用 joi.not(joi.ref('oldPwd')).concat(password) 规则,验证 req.body.newPwd 的值
解读:
1. joi.ref('oldPwd') 表示 newPwd 的值必须和 oldPwd 的值保持一致
2. joi.not(joi.ref('oldPwd')) 表示 newPwd 的值不能等于 oldPwd 的值
3. .concat() 用于合并 joi.not(joi.ref('oldPwd')) 和 password 这两条验证规则
3.3 更新头像
3.3.1 验证表单数据(3.4.2)
// dataUri() 指的是如下格式的字符串数据:
// data:image/png;base64,VE9PTUFOWVNFQ1JFVFM=const avatar = joi.string().dataUri().required()
dataUrl() 方法用于验证一个字符串是否符合数据 URL 的格式
4 文章分类管理
4.1 根据Id更新文章分类数据
4.1.1 查询分类名称与别名是否被占用(4.5.4)
SELECT * FROM ev_article_cate WHERE Id <> ? AND (name = ? or alias = ?)
注意:已有数据的情况下进行更新内容,需要排除当前数据的内容,否做无法做到部分内容修改!
5 文章管理
5.1 发布新文章
5.1.1 使用 multer 解析表单数据(5.2.3)
URL-encoded:适用于传输简单的文本数据,例如表单中的文本字段
multipart/form-data:适用于上传文件或包含二进制数据的表单
注意:使用 express.urlencoded() 中间件无法解析 multipart/form-data 格式的请求体数据
当前项目,推荐使用 multer 来解析 multipart/form-data 格式的表单数据
安装:
npm i multer@1.4.2
创建与使用:
// 导入解析 formdata 格式表单数据的包
const multer = require('multer')// 导入处理路径的核心模块
const path = require('path')
// 创建 multer 的实例对象,通过 dest 属性指定文件的存放路径
const upload = multer({ dest: path.join(__dirname, '../uploads') })// 发布新文章的路由
// upload.single() 是一个局部生效的中间件,用来解析 FormData 格式的表单数据
// 将文件类型的数据,解析并挂载到 req.file 属性中
// 将文本类型的数据,解析并挂载到 req.body 属性中
router.post('/add', upload.single('cover_img'), article_handler.addArticle)
之后文本类型的数据,即字段会通过joi来进行规则验证,但是文件类型的数据不行,得额外用if判断
5.1.2 验证表单数据(5.2.4)
注意:先后顺序一定不能变,因为multer会将其他字段挂载到req.body上,如果在joi之后,会导致部分字段不会被joi检测
// 导入验证数据的中间件
const expressJoi = require('@escook/express-joi')// 导入文章的验证模块
const { add_article_schema } = require('../schema/article')// 发布新文章的路由
// 注意:在当前的路由中,先后使用了两个中间件:
// 先使用 multer 解析表单数据
// 再使用 expressJoi 对解析的表单数据进行验证
router.post('/add', upload.single('cover_img'), expressJoi(add_article_schema),
article_handler.addArticle)
验证文件类型:
// 发布新文章的处理函数
exports.addArticle = (req, res) => {// 手动判断是否上传了文章封面if (!req.file || req.file.fieldname !== 'cover_img') return res.cc('文章封面是必选
参数!')// TODO:表单数据合法,继续后面的处理流程...})
5.1.3 新建数据对象(5.2.5)
const articleInfo = {// 标题、内容、状态、所属的分类Id...req.body,// 文章封面在服务器端的存放路径cover_img: path.join('/uploads', req.file.filename),// 文章发布时间pub_date: new Date(),// 文章作者的Idauthor_id: req.user.id,}
断更...
相关文章:
【综合项目】api系统——基于Node.js、express、mysql等技术
目录 0 前言 1 初始化 2 注册登录 2.1 注册 2.1.1 功能:密码加密(2.3.3) 2.1.1.1 操作 2.1.1.2 bcryptjs详解 2.1.2 插入新用户(2.3.4) 2.1.3 优化:表单数据验证(2.5) …...
Go中slice和map引用传递误区
背景 关于slice和map是指传递还是引用传递,很多文章都分析得模棱两可,其实在Go中只有值传递,但是很多情况下是因为分不清slice和map的底层实现,所以导致很多人在这一块产生疑惑,下面通过代码案例分析slice和map到底是…...
C++ ++++++++++
初始C 注释 变量 常量 关键字 标识符命名规则 数据类型 C规定在创建一个变量或者常量时,必须要指定出相应的数据类型,否则无法给变量分配内存 整型 sizeof关键字 浮点型(实型) 有效位数保留七位,带小数点。 这个是保…...
【北京迅为】iTOP-RK3568OpenHarmony系统南向驱动开发-第1章 GPIO基础知识
瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工…...
linux在vim中查找和替换
在Linux中使用Vim编辑器查找文本的方法非常直观和强大。Vim是一个高度可配置的文本编辑器,支持多种查找和替换的命令。下面是一些基本的查找命令: 1. 向前查找 要向前查找文本,可以使用以下命令: /text_to_find 例如,…...
AWS中使用CloudFront分发API Gateway
首先需要准备一个Lambda function(Lambda->Functions) 还要准备一个证书,要覆盖子域名(AWS Certificate Manager->Certificates)。 1、API Gateway->Create API->REST API->Build->API endpoint type( Edge-optimized )-…...
探秘《矩阵之美》:解锁矩阵的无限魅力
在这个数据驱动的时代,矩阵作为数学中的瑰宝,不仅在理论研究中占据核心地位,更在工程技术、计算机科学、物理学、经济学等众多领域发挥着不可替代的作用。今天,让我们通过中科院大学耿修瑞老师(中科院空天信息研究院研…...
进行性核上性麻痹患者的生活护理指南
进行性核上性麻痹是一种神经系统退行性疾病,合理的生活护理能有效改善症状,提高生活质量。 居家环境要安全。移除地面杂物,铺设防滑垫,安装扶手,降低跌倒风险。在浴室、厨房等湿滑区域要特别加强防护措施。建议在床边、…...
JVM--虚拟机
JVM,即虚拟机,可以简单理解为将字节码文件翻译成机器码的机器。 .class文件-->机器码文件 JVM整体组成部分 1.类加载器 负责从磁盘中加载字节码文件到JVM中 2.运行时数据区 按照不同的数据分区进行存储(方法区,堆,栈,本地方…...
pyside6学习专栏(八):在PySide6中使用matplotlib库绘制三维图形
本代码原来是PySide6官网的一个示例程序,我对其进行的详细的注释,同时增加了一个功能:加载显示cass的地形图坐标数据示例,示例可显示以下几种三维图形 程序运行界面如下: 代码如下: # -*- coding: utf-8 -…...
松灵机器人地盘 安装 ros 驱动 并且 发布ros 指令进行控制
安装驱动 $ cd ~/catkin_ws/src $ git clone https://github.com/agilexrobotics/ugv_sdk.git $ git clone https://github.com/agilexrobotics/scout_ros.git $ cd .. $ catkin_make安装 ● 使能 gs_usb 内核模块 ● 设置 500k 波特率和使能 can-to-usb 适配器 sudo modp…...
Highcharts 配置语法详解
Highcharts 配置语法详解 引言 Highcharts 是一个功能强大的图表库,广泛应用于数据可视化领域。本文将详细介绍 Highcharts 的配置语法,帮助您快速上手并制作出精美、实用的图表。 高级配置结构 Highcharts 的配置对象通常包含以下几部分:…...
python力扣2:两数相加
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。 请你将两个数相加,并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外,这两个数都不会以 0 开…...
服务器间迁移conda环境
注意:可使用迁移miniconda文件 or 迁移yaml文件两种方式,推荐前者,基本无bug! 一、迁移miniconda文件: 拷贝旧机器的miniconda文件文件到新机器: 内网拷贝:scp -r mazhf192.168.1.233:~/miniconda3 ~/ 外…...
LeetCode第58题_最后一个单词的长度
LeetCode 第58题:最后一个单词的长度 题目描述 给你一个字符串 s,由若干单词组成,单词前后用一些空格字符隔开。返回字符串中最后一个单词的长度。 单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。 难度 简单 题目链接 点…...
Python 绘制迷宫游戏,自带最优解路线
1、需要安装pygame 2、上下左右移动,空格实现物体所在位置到终点的路线,会有虚线绘制。 import pygame import random import math# 迷宫单元格类 class Cell:def __init__(self, x, y):self.x xself.y yself.walls {top: True, right: True, botto…...
恶意 SSP 注入收集密码
SSP 安全服务提供者,是微软提供的与安全有关的函数接口,用户可根据自己的需求调用 SSP 接口实现高度自定义的身份验证等安全功能。攻击者注入恶意的 SSP 接口覆盖微软默认的某些安全功能,导致用户一旦进行身份验证,恶意的 SSP 将保…...
Llama 2中的Margin Loss:为何更高的Margin导致更大的Loss和梯度?
Llama 2中的Margin Loss:为何更高的Margin导致更大的Loss和梯度? 在《Llama 2: Open Foundation and Fine-Tuned Chat Models》论文中,作者在强化学习与人类反馈(RLHF)的Reward Model训练中引入了Margin Loss的概念&a…...
Python----数据分析(Numpy:安装,数组创建,切片和索引,数组的属性,数据类型,数组形状,数组的运算,基本函数)
一、 Numpy库简介 1.1、概念 NumPy(Numerical Python)是一个开源的Python科学计算库,旨在为Python提供 高性能的多维数组对象和一系列工具。NumPy数组是Python数据分析的基础,许多 其他的数据处理库(如Pandas、SciPy)都依赖于Num…...
Android Logcat 高效调试指南
工具概览 Logcat 是 Android SDK 提供的命令行日志工具,支持灵活过滤、格式定制和实时监控,官方文档详见 Android Developer。 基础用法 命令格式 [adb] logcat [<option>] ... [<filter-spec>] ... 执行方式 直接调用(通过ADB守…...
Pytest之fixture的常见用法
文章目录 1.前言2.使用fixture执行前置操作3.使用conftest共享fixture4.使用yield执行后置操作 1.前言 在pytest中,fixture是一个非常强大和灵活的功能,用于为测试函数提供固定的测试数据、测试环境或执行一些前置和后置操作等, 与setup和te…...
如何把网络ip改为动态:全面指南
在数字化时代,网络IP地址作为设备在网络中的唯一标识,扮演着至关重要的角色。随着网络环境的不断变化,静态IP地址的局限性逐渐显现,而动态IP地址则因其灵活性和安全性受到越来越多用户的青睐。那么,如何把网络IP改为动…...
anythingLLM和deepseek4j和milvus组合建立RAG知识库
1、deepseek本地化部署使用 ollama 下载模型 Tags bge-m3 bge-m3:latest deepseek-r1:32b deepseek-r1:8b 2、安装好向量数据库 milvus docker安装milvus单机版-CSDN博客 3、安装 anythingLLM AnythingLLM | The all-in-one AI application for everyone …...
和鲸科技推出人工智能通识课程解决方案,助力AI人才培养
2025年2月,教育部副部长吴岩应港澳特区政府邀请,率团赴港澳宣讲《教育强国建设规划纲要 (2024—2035 年)》。在港澳期间,吴岩阐释了教育强国目标的任务,并与特区政府官员交流推进人工智能人才培养的办法。这一系列行动体现出人工智…...
当我删除word文件时无法删除,提示:操作无法完成,因为已在Microsoft Word中打开
现象: 查看电脑桌面下方的任务栏,明明已经关闭了WPS和WORD软件,但是打开word文档时还是提示: 解决方法步骤: 1、按一下键盘上的ctrl Shift Esc 键打开任务管理器 2、在进程中找到如下: 快速找到的方法…...
高频面试题(含笔试高频算法整理)基本总结回顾3
目录 一、基本面试流程回顾 二、基本高频算法题展示 三、基本面试题总结回顾 (一)Java高频面试题整理 (二)JVM相关面试问题整理 (三)MySQL相关面试问题整理 (四)Redis相关面试…...
Python中字符串的常用操作
一、r原样输出 在 Python 中,字符串前加 r(即 r"string" 或 rstring)表示创建一个原始字符串(raw string)。下面详细介绍原始字符串的特点、使用场景及与普通字符串的对比。 特点 忽略转义字符࿱…...
卷积神经网络(cnn,类似lenet-1,八)
我们第一层用卷积核,前面已经成功,现在我们用两层卷积核: 结构如下,是不是很想lenet-1,其实我们24年就实现了sigmoid版本的: cnn突破九(我们的五层卷积核bpnet网络就是lenet-1)-CS…...
Win32 C++ 电源计划操作
CPowerCfgUtils.h #pragma once#include <Windows.h> #include <powrprof.h>// https://learn.microsoft.com/zh-cn/windows/win32/api/powrprof/?sourcerecommendations//节能 //DEFINE_GUID(GUID_MAX_POWER_SAVINGS, 0xA1841308, 0x3541, 0x4FAB, 0xBC, 0x81, …...
PH热榜 | 2025-03-01
1. Helix 标语:从想法到原型只需3分钟 介绍:Helix可以在几分钟内将你的创业想法变成一个准备好接受投资的原型。你可以创建功能齐全、可点击的用户界面和用户体验设计,完全不需要任何设计技能。 产品网站: 立即访问 Product H…...
