当前位置: 首页 > article >正文

【综合项目】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 功能&#xff1a;密码加密&#xff08;2.3.3&#xff09; 2.1.1.1 操作 2.1.1.2 bcryptjs详解 2.1.2 插入新用户&#xff08;2.3.4&#xff09; 2.1.3 优化&#xff1a;表单数据验证&#xff08;2.5&#xff09; …...

Go中slice和map引用传递误区

背景 关于slice和map是指传递还是引用传递&#xff0c;很多文章都分析得模棱两可&#xff0c;其实在Go中只有值传递&#xff0c;但是很多情况下是因为分不清slice和map的底层实现&#xff0c;所以导致很多人在这一块产生疑惑&#xff0c;下面通过代码案例分析slice和map到底是…...

C++ ++++++++++

初始C 注释 变量 常量 关键字 标识符命名规则 数据类型 C规定在创建一个变量或者常量时&#xff0c;必须要指定出相应的数据类型&#xff0c;否则无法给变量分配内存 整型 sizeof关键字 浮点型&#xff08;实型&#xff09; 有效位数保留七位&#xff0c;带小数点。 这个是保…...

【北京迅为】iTOP-RK3568OpenHarmony系统南向驱动开发-第1章 GPIO基础知识

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工艺&#xff0c;搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码&#xff0c;支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU&#xff0c;可用于轻量级人工…...

linux在vim中查找和替换

在Linux中使用Vim编辑器查找文本的方法非常直观和强大。Vim是一个高度可配置的文本编辑器&#xff0c;支持多种查找和替换的命令。下面是一些基本的查找命令&#xff1a; 1. 向前查找 要向前查找文本&#xff0c;可以使用以下命令&#xff1a; /text_to_find 例如&#xff0c…...

AWS中使用CloudFront分发API Gateway

首先需要准备一个Lambda function(Lambda->Functions) 还要准备一个证书&#xff0c;要覆盖子域名&#xff08;AWS Certificate Manager->Certificates&#xff09;。 1、API Gateway->Create API->REST API->Build->API endpoint type( Edge-optimized )-…...

探秘《矩阵之美》:解锁矩阵的无限魅力

在这个数据驱动的时代&#xff0c;矩阵作为数学中的瑰宝&#xff0c;不仅在理论研究中占据核心地位&#xff0c;更在工程技术、计算机科学、物理学、经济学等众多领域发挥着不可替代的作用。今天&#xff0c;让我们通过中科院大学耿修瑞老师&#xff08;中科院空天信息研究院研…...

进行性核上性麻痹患者的生活护理指南

进行性核上性麻痹是一种神经系统退行性疾病&#xff0c;合理的生活护理能有效改善症状&#xff0c;提高生活质量。 居家环境要安全。移除地面杂物&#xff0c;铺设防滑垫&#xff0c;安装扶手&#xff0c;降低跌倒风险。在浴室、厨房等湿滑区域要特别加强防护措施。建议在床边、…...

JVM--虚拟机

JVM,即虚拟机&#xff0c;可以简单理解为将字节码文件翻译成机器码的机器。 .class文件-->机器码文件 JVM整体组成部分 1.类加载器 负责从磁盘中加载字节码文件到JVM中 2.运行时数据区 按照不同的数据分区进行存储(方法区&#xff0c;堆&#xff0c;栈&#xff0c;本地方…...

pyside6学习专栏(八):在PySide6中使用matplotlib库绘制三维图形

本代码原来是PySide6官网的一个示例程序&#xff0c;我对其进行的详细的注释&#xff0c;同时增加了一个功能&#xff1a;加载显示cass的地形图坐标数据示例&#xff0c;示例可显示以下几种三维图形 程序运行界面如下&#xff1a; 代码如下&#xff1a; # -*- 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 是一个功能强大的图表库&#xff0c;广泛应用于数据可视化领域。本文将详细介绍 Highcharts 的配置语法&#xff0c;帮助您快速上手并制作出精美、实用的图表。 高级配置结构 Highcharts 的配置对象通常包含以下几部分&#xff1a…...

python力扣2:两数相加

给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外&#xff0c;这两个数都不会以 0 开…...

服务器间迁移conda环境

注意&#xff1a;可使用迁移miniconda文件 or 迁移yaml文件两种方式&#xff0c;推荐前者&#xff0c;基本无bug&#xff01; 一、迁移miniconda文件&#xff1a; 拷贝旧机器的miniconda文件文件到新机器: 内网拷贝&#xff1a;scp -r mazhf192.168.1.233:~/miniconda3 ~/ 外…...

LeetCode第58题_最后一个单词的长度

LeetCode 第58题&#xff1a;最后一个单词的长度 题目描述 给你一个字符串 s&#xff0c;由若干单词组成&#xff0c;单词前后用一些空格字符隔开。返回字符串中最后一个单词的长度。 单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。 难度 简单 题目链接 点…...

Python 绘制迷宫游戏,自带最优解路线

1、需要安装pygame 2、上下左右移动&#xff0c;空格实现物体所在位置到终点的路线&#xff0c;会有虚线绘制。 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 安全服务提供者&#xff0c;是微软提供的与安全有关的函数接口&#xff0c;用户可根据自己的需求调用 SSP 接口实现高度自定义的身份验证等安全功能。攻击者注入恶意的 SSP 接口覆盖微软默认的某些安全功能&#xff0c;导致用户一旦进行身份验证&#xff0c;恶意的 SSP 将保…...

Llama 2中的Margin Loss:为何更高的Margin导致更大的Loss和梯度?

Llama 2中的Margin Loss&#xff1a;为何更高的Margin导致更大的Loss和梯度&#xff1f; 在《Llama 2: Open Foundation and Fine-Tuned Chat Models》论文中&#xff0c;作者在强化学习与人类反馈&#xff08;RLHF&#xff09;的Reward Model训练中引入了Margin Loss的概念&a…...

Python----数据分析(Numpy:安装,数组创建,切片和索引,数组的属性,数据类型,数组形状,数组的运算,基本函数)

一、 Numpy库简介 1.1、概念 NumPy(Numerical Python)是一个开源的Python科学计算库&#xff0c;旨在为Python提供 高性能的多维数组对象和一系列工具。NumPy数组是Python数据分析的基础&#xff0c;许多 其他的数据处理库&#xff08;如Pandas、SciPy&#xff09;都依赖于Num…...

Android Logcat 高效调试指南

工具概览 Logcat 是 Android SDK 提供的命令行日志工具&#xff0c;支持灵活过滤、格式定制和实时监控&#xff0c;官方文档详见 Android Developer。 基础用法 命令格式 [adb] logcat [<option>] ... [<filter-spec>] ... 执行方式 直接调用&#xff08;通过ADB守…...

Pytest之fixture的常见用法

文章目录 1.前言2.使用fixture执行前置操作3.使用conftest共享fixture4.使用yield执行后置操作 1.前言 在pytest中&#xff0c;fixture是一个非常强大和灵活的功能&#xff0c;用于为测试函数提供固定的测试数据、测试环境或执行一些前置和后置操作等&#xff0c; 与setup和te…...

如何把网络ip改为动态:全面指南

在数字化时代&#xff0c;网络IP地址作为设备在网络中的唯一标识&#xff0c;扮演着至关重要的角色。随着网络环境的不断变化&#xff0c;静态IP地址的局限性逐渐显现&#xff0c;而动态IP地址则因其灵活性和安全性受到越来越多用户的青睐。那么&#xff0c;如何把网络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月&#xff0c;教育部副部长吴岩应港澳特区政府邀请&#xff0c;率团赴港澳宣讲《教育强国建设规划纲要 (2024—2035 年)》。在港澳期间&#xff0c;吴岩阐释了教育强国目标的任务&#xff0c;并与特区政府官员交流推进人工智能人才培养的办法。这一系列行动体现出人工智…...

当我删除word文件时无法删除,提示:操作无法完成,因为已在Microsoft Word中打开

现象&#xff1a; 查看电脑桌面下方的任务栏&#xff0c;明明已经关闭了WPS和WORD软件&#xff0c;但是打开word文档时还是提示&#xff1a; 解决方法步骤&#xff1a; 1、按一下键盘上的ctrl Shift Esc 键打开任务管理器 2、在进程中找到如下&#xff1a; 快速找到的方法…...

高频面试题(含笔试高频算法整理)基本总结回顾3

目录 一、基本面试流程回顾 二、基本高频算法题展示 三、基本面试题总结回顾 &#xff08;一&#xff09;Java高频面试题整理 &#xff08;二&#xff09;JVM相关面试问题整理 &#xff08;三&#xff09;MySQL相关面试问题整理 &#xff08;四&#xff09;Redis相关面试…...

Python中字符串的常用操作

一、r原样输出 在 Python 中&#xff0c;字符串前加 r&#xff08;即 r"string" 或 rstring&#xff09;表示创建一个原始字符串&#xff08;raw string&#xff09;。下面详细介绍原始字符串的特点、使用场景及与普通字符串的对比。 特点 忽略转义字符&#xff1…...

卷积神经网络(cnn,类似lenet-1,八)

我们第一层用卷积核&#xff0c;前面已经成功&#xff0c;现在我们用两层卷积核&#xff1a; 结构如下&#xff0c;是不是很想lenet-1&#xff0c;其实我们24年就实现了sigmoid版本的&#xff1a; cnn突破九&#xff08;我们的五层卷积核bpnet网络就是lenet-1&#xff09;-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 标语&#xff1a;从想法到原型只需3分钟 介绍&#xff1a;Helix可以在几分钟内将你的创业想法变成一个准备好接受投资的原型。你可以创建功能齐全、可点击的用户界面和用户体验设计&#xff0c;完全不需要任何设计技能。 产品网站&#xff1a; 立即访问 Product H…...