附录3-大事件项目后端-项目准备工作,config.js,一些库的简易用法,main.js
目录
1 一些注意
2 创建数据库
3 项目结构
4 配置文件 config.js
5 参数规则包 @hapi/joi与@escook/express-joi
5.1 安装
5.2 文档中的demo
5.2.1 定义规则
5.2.2 使用规则
5.3 项目中的使用
5.3.1 定义信息规则
5.3.2 使用规则
6 密码加密包 bcrypt.js
6.1 加密
6.2 对比
7 处理form-data数据包 multer
7.1 安装
7.2 项目中的使用
8 入口文件 main.js
8.1 约束一些请求
8.2 注册所有路由模块
8.3 处理请求体
1 一些注意
- 不要认为接口中的message没什么用就不写了,写上在排错与前端调用的时候都比较方便
- 这里面记录了该项目后端的详细实现方式 api_server_ev 在这个链接中关于文章列表后面几个视图没有写
- 如果只看接口文档可以看这个 ShowDoc
- 在实际开发的时候express有时会出现错误后服务就断掉,且与其他模块可能会出现协同性的问题(不是一家开发的,比如mysql出现了问题,给express错误处理中间件服务也会断掉)
- 实际开发中应该将路由与视图不在同一个文件写符合模块化开发的要求,我这里就写在一起了,因为对于一个小项目来讲,一共就十几个url,摊到每个模块也就四五个url,你过度封装反而会导致你维护的时候不好找,一会儿点开这个一会儿点开那个。分开写的原因是当路由多的时候可以一个人搞路由一个人搞视图,分开写的缺点是从主函数到视图函数会出现多级的调用,对于单人开发就显得不是很友好
- 大事件项目后端视频 07.项目-初始化项目_哔哩哔哩_bilibili P77-P96
2 创建数据库
数据库使用的是mysql,数据表有三个,分别是 用户信息数据表,文章分类数据表,文章内容数据表
三个数据表的这些信息都是一样的
用户信息数据表,其中user_pic是用户头像,要求为base64字符串,我们的Datatype可以写为TEXT
文章信息数据表
文章分类数据表
三张表都是没有外键的,我们让用户在上传文章的时候要上传用户id(后端根据token自动添加参数),然后显示的时候根据用户id进行筛选(后端根据token自动筛选),从而用户只会看到自己的文章
文章分类没有给author_id,实际上也可以再加一个author_id,让每一个用户都有自己专属的分类
3 项目结构
项目结构如下,最上面的uploads放前端传过来的文章封面,config.js中有一些配置,main.js是入口文件,运行的时候node main.js
router是四个模块的路由
4 配置文件 config.js
我使用了一个config.js文件作为配置文件,里面有很多的全局变量,config文件内容没有做导出,在使用的时候直接引入config就行了
config.js中有需要导入的库,token密钥,数据库配置,文章封面存放的文件夹,以及一些验证规则
// 需要导入的库
joi = require('joi')
mysql = require('mysql')
express = require('express')
jsonwebtoken = require('jsonwebtoken')
bcryptjs = require('bcryptjs')
expressJoi = require('@escook/express-joi')
cors = require('cors')
multer = require('multer')
path = require('path')// token密钥
secretKey = 'xifgnmuioherawbt'// 数据库
db = mysql.createPool({host:'127.0.0.1',user:'root',password:'12345678',database:'big_things'
})// 文章封面存放的文件夹
uploads = multer({dest:path.join(__dirname,'../uploads')})// id的验证规则都是相同的,所以可以统一来写
id_rule = joi.number().integer().min(1).required()
// 用户信息表 验证规则
userinfo_username_rule = joi.string().alphanum().min(1).max(10).required()
userinfo_password_rule = joi.string().pattern(/^[\S]{6,12}$/)userinfo_nickname_rule = joi.string().required()
userinfo_email_rule = joi.string().email().required()
userinfo_avatar_rule = joi.string().dataUri().required()// 文章分类表 验证规则
category_name_rule = joi.string().required()
category_alias_rule = joi.string().alphanum().required()// 文章列表 验证规则
article_title_rule = joi.string().required()
article_content_rule = joi.string().required().allow('')
// 分类id与状态 有的时候需要必选,有的时候不需要必选,所以在总的规则中取消了required(),需要的时候你再加上就行了
article_cate_id_rule = joi.number().integer().min(1)
article_state_rule = joi.string().valid('已发布', '草稿')
// 文章列表要做分页,pagenum是要看第几页
article_pagenum_rule = joi.number().integer().min(1).required()
// pagesize是每页显示多少条数据
article_pagesize_rule = joi.number().integer().min(1).required()
简单看一下导入的库
- joi与express-joi 前端传入信息规则验证
- mysql 数据库
- express 后端框架
- jsonwebtoken 做token的,用于前后端跨域信息验证
- bcryptjs 密码加密
- cors 做跨域的
- multer 处理前端传入的form-data数据的
- path 路径拼接
其中 mysql在这里有具体用法 8.mysql模块_Suyuoa的博客-CSDN博客
express,jsonwebtoken,cors在这里有具体用法 7.Express模块基础用法_express 引入模块_Suyuoa的博客-CSDN博客
5 参数规则包 @hapi/joi与@escook/express-joi
后端是一定要加数据验证的,不要因为前端做了验证后端就不做了,宁可多做不要少做
我们如果每个验证都写if else那样的话代码量较多,维护起来比较麻烦,我们可以借助一些第三方的包来搞
如果规则较简单的时候也可以不用,轮子太多也不利于项目的维护,有时候搞来搞去发现轮子不好用,最好还有查轮子的文档,比如我就遇到了这个问题,还得在网上查一下怎么搞定这个错误 【node.js】报错Cannot mix different versions of joi schemas解决方法_前端小二哥的博客-CSDN博客
@hapi/joi 是定义规则用的,@escook/express-joi 是验证规则用的
@hapi/joi是@escook/express-joi的依赖,在导入的时候要先导入@hapi/joi再导入@escook/express-joi
5.1 安装
5.2 文档中的demo
在npm官网上搜索@escook/express-joi会出现它的简易demo
5.2.1 定义规则
我们看userSchema这个对象,其中有body,query,params,分别的意思就是req.body,req.query,req.params
有什么写什么就行,比如只验证req.body,就只写body就行
body,query,params这三个名称固定
下面看body中的内容,里面username这些是参数名,后面跟的是验证规则。可以给验证规则自己定义一个变量方便复用
验证规则的名字一般我们保持与接收的参数名一致就行,如果不一致你就需要这样写
- 实则还是遵循键值的格式
Joi.string()是先让其变成字符串形式,Joi.number().integer()是让其先变成数字型然后变为整形
alphanum()表示这个字符串中只能包含 a-z A-Z 0-9
min()与max()是字符串的最小,最大长度,如果类型是数字那么就代表最大值最小值
required()表示是必选参数
patter()内加正则表达式用于验证规则
repassword这个就是重新输入密码的参数名,joi.ref('password')的意思是必须与password保持一致
只有写在body中的内容才会被接收,如果你多给了是存不到req.body中的,比如上面我给了id,nickname.email,如果你再多给一个password,最后你查req.body中是没有password的
5.2.2 使用规则
userSchema是我们刚刚定义的规则,如果在路由中出现了验证不通过的情况就会抛出一个错误,抛出错误后下面定义一个错误级别中间件,这个错误级别中间件会把错误的信息返回给客户端
5.3 项目中的使用
5.3.1 定义信息规则
我们下面看一下传入信息的规则,规则都放在config.js中,搞的全局变量,后面在验证的时候直接使用这个全局变量就好
- number() 必须为数字
- integer() 必须为整形
- min(1) 当值为数字时,最小值为1,当值为字符时,最小长度为1
- required() 必须传入
- string() 必须为字符串
- alphanum() 只能包含 a-z,A-Z,0-9
- max(10) 当值为数字时,最大值为10,当值为字符时,最大长度为10
- pattern(/^[\S]{6,12}$/) pattern中是正则的用法,这里是6-12位非空字符串
- email() 必须为邮箱格式
- dataUri() 比如是dataUri格式,比如 'data:image/png;base64,VE9PTUFOWVNFQ1JFVFM=' 项目中用其处理base64图像字符串
- allow('') 允许为空
- valid('已发布', '草稿') 值只能为 已发布 或 草稿
5.3.2 使用规则
首先定义一个对象,如果是get的查询字符串传递就写query
如果是post就写body,form-data与xxx-www-form-urlencoded都用body
如果是拼接路由就用params
当有不符合规则的信息时,在main.js中加入一个中间件,提示客户端错误信息
6 密码加密包 bcrypt.js
可以通过 beryptjs 来对密码部分进行加密,首先定义一个密钥,这个密钥就随便写就行,密码会根据这个密钥进行加密与解密,我在config.js中定义了一个全局变量secretKey
6.1 加密
在注册的时候,加密后存储数据库,加密方法为 bcryptjs.hashSync(),第一个参数为加密的内容,第二个参数是哈希烟的长度
- 即使是相同的密码也会得到不同的加密结果
6.2 对比
使用bcyptjs.compareSync()将传入的密码与数据库中存储的真实密码进行比对
7 处理form-data数据包 multer
multer是处理 multipart/form-data 表单上传的数据用的(Multer 不会处理任何非 multipart/form-data 类型的表单数据)
7.1 安装
7.2 项目中的使用
我们先看几个关于multer的信息
传上来的文件被存储在uploads文件夹中,每一次成功传输会生成一个这样的文件
在mysql中会存储文件的路径
下面我们来看使用
在config.js中,我们指定了一个文件夹用来放文章封面,dest这个键就是放在那个位置的意思
- 这里只是管把文件存在哪个实际的地方,和数据库中的数据无关
使用single()方法,参数为传递的文件参数名,single()方法会让cover_img存在req.file中,我们打印出 req.file.filename 看一下
打印出来的结果只有文件名
下面用path.join()只和数据库中的信息有关,和实际文件存在哪里无关
8 入口文件 main.js
const config = require('./config.js')const login_register_router = require('./router/login_register.js')
const personal_center_router = require('./router/personal_center.js')
const article_category_management_router = require('./router/article_category_management.js')
const article_list_management_router = require('./router/article_list_management.js')const { expressjwt: jwt } = require("express-jwt")const app = express()app.use(function (req, res, next) {res.setTimeout(5*1000, function () {res.send("请求超时")});next();
});
app.use(jwt({secret: secretKey,algorithms: ["HS256"],}).unless({ path: [/^\/api\//] })
)
app.use(cors())
app.use(express.urlencoded({extended:false}))app.use(login_register_router)
app.use(personal_center_router)
app.use(article_category_management_router)
app.use(article_list_management_router)app.use((err,req,res,next) => {// 判断用户提交的信息if (err instanceof joi.ValidationError) return res.send({status:1,message:err.message})// 判断tokenif (err.name === 'UnauthorizedError') {return res.send({status:1,message:'无效的token'})}// 其他错误return res.send({status:1,message:err.message})
})app.listen(80,() => {console.log('服务在80端口启动')
})
首先引入配置文件和所有的路由模块
引入jwt,只有在main.js中需要,所以就在这里引入了,而且这个库的引入方式有一点奇特,不方便在config.js中引入
初始化一个app
8.1 约束一些请求
放一个中间件,当请求时间超过5秒时,返回请求超时
放一个中间件,只有使用/api开头的路由不需要token,其余均需要token
支持跨域
支持前端post发送一些信息
8.2 注册所有路由模块
8.3 处理请求体
第一个if用来处理用户提交的信息(我们上面用joi定义的那些规则),第二个if用来判断token
在80端口启动
相关文章:

附录3-大事件项目后端-项目准备工作,config.js,一些库的简易用法,main.js
目录 1 一些注意 2 创建数据库 3 项目结构 4 配置文件 config.js 5 参数规则包 hapi/joi与escook/express-joi 5.1 安装 5.2 文档中的demo 5.2.1 定义规则 5.2.2 使用规则 5.3 项目中的使用 5.3.1 定义信息规则 5.3.2 使用规则 6 密码加密包 bcrypt.…...
并发编程-线程
并发编程-线程 一个进程是操作系统中运行的一个任务,进程独立拥有CPU、内存等资源一个线程是一个进程中运行的一个任务,线程之间共享CPU、内存等资源,进程里的每一个任务都是线程。 线程创建 创建线程:使用threading模块中的Th…...

图解LeetCode——剑指 Offer 34. 二叉树中和为某一值的路径
一、题目 给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。叶子节点 是指没有子节点的节点。 二、示例 2.1> 示例 1: 【输入】root [5,4,8,11,null,13,4,7,2,null,null,5,1], t…...

使用Python免费试用最新Openai API
一、背景介绍 3月2日凌晨,OpenAI放出了真正的ChatGPT API,不是背后的GPT-3.5大模型,是ChatGPT的本体模型!ChatGPT API价格为1k tokens/$0.002,等于每输出100万个单词,价格才2.7美金(约18元人民…...

04、启动 SVN 服务器端程序
启动 SVN 服务器端程序1 概述2 用命令行单项目启动2.1 采用 svnserve 命令2.2 验证服务是否启动2.3 命令行方式的缺陷3 注册Windows服务3.1 注册服务的命令3.2 命令说明3.3 启动服务1 概述 SVN 服务器和 Tomcat 服务器,Nexus 服务器一样, 必须处于运行状态才能响应…...

jsp船舶引航计费网站Myeclipse开发mysql数据库web结构java编程计算机网页项目
一、源码特点 JSP船舶引航计费网站是一套完善的java web信息管理系统,对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发,数据库为Mysql5.0&…...

Allegro如何画半圆形的线操作指导
Allegro如何画半圆形的线操作指导 在用Allegro设计PCB的时候,在某些应用场合会需要画半圆形,如下图 如何画半圆形,具体操作如下 点击Add点击Arc w/Radius...

【强烈建议收藏:MySQL面试必问系列之SQL语句执行专题】
一.知识回顾 之前的文章我们一起学习了MySQL面试必问系列之事务专题、锁专题,没有学习的小伙伴可以直接通过该链接地址直接访问,MYSQL你真的了解吗专栏的文章,接下来我们就一起来学习一下MySQL中SQL语句的执行流程,看看你掌握的怎…...
详解Linux下的环境变量以及C++库文件和头文件、python库的配置
目录 Linux环境变量配置基本步骤 1.查看环境变量 2.设置环境变量 3.永久性设置环境变量 4.使用环境变量 C 库文件和头文件环境变量配置 1.配置so库文件的环境变量 2.配置头文件的环境变量 Python库环境变量配置 Linux配置执行文件环境变量 我们都习惯在Windows 上配置…...

企业级分布式数据库 - GaussDB介绍
目录 什么是GaussDB 简介 应用场景 产品架构 产品优势 安全 责任共担 身份认证与访问控制 数据保护技术 审计与日志 监控安全风险 故障恢复 认证证书 GaussDB与其他服务的关系 约束与限制 计费模式 什么是GaussDB …...

Linux I2C 驱动实验
目录 一、Linux I2C 驱动简介 1、I2C 总线驱动 2、I2C 设备驱动 1、 i2c_client 结构体 2、 i2c_driver 结构体 二、硬件分析 三、设备树编写 1、pinctrl_i2c1 2、在 i2c1 节点追加 ap3216c 子节点 3、验证 四、 代码编写 1、makefile 2、ap3216c.h 3、ap3216c.c …...

DC-DC模块电源隔离直流升压高压稳压输出5v12v24v转60v100v110v150v220v250v300v400v500v
特点效率高达80%以上1*1英寸标准封装单电压输出稳压输出工作温度: -40℃~85℃阻燃封装,满足UL94-V0 要求温度特性好可直接焊在PCB 上应用HRB 0.2~10W 系列模块电源是一种DC-DC升压变换器。该模块电源的输入电压分为:4.5~9V、9~18V、及18~36VDC标准&#…...
EF有几种模式,EF的三种模式分别是什么?
EF有几种模式,EF的三种模式分别是什么? 第一种:DataBase First DataBase First传统的表驱动方式创建EDM,然后通过EDM生成模型和数据层代码。除生成实体模型和自跟踪实现模型,还支持生成轻型DbContext。 解释…...

数据可视化展示:打工人常见职业病,颈腰椎病占比最高达66.51%
身体健康才是一切的根本。只有身体健健康康才能更好的去享受世间的美好,无论是谁都应当注重身体健康,而不是无度的挥霍它! 良好的身体,释放给工作,健壮的体魄,享受美好生活,良好的心态ÿ…...

【食品图像识别】Large Scale Visual Food Recognition
1 引言 视觉智能部与中科院计算所于2020-2021年度展开了《细粒度菜品图像识别和检索》科研课题合作,本文系双方联合在IEEE T-PAMI2023发布论文《Large Scale Visual Food Recognition》 (Weiqing Min, Zhiling Wang, Yuxin Liu, Mengjiang Luo, Liping Kang, Xiaom…...

RAN-in-the-Cloud:为 5G RAN 提供云经济性
RAN-in-the-Cloud:为 5G RAN 提供云经济性 5G 部署在全球范围内一直在加速。 许多电信运营商已经推出了5G服务并正在快速扩张。 除了电信运营商之外,企业也对使用 5G 建立私有网络产生了浓厚的兴趣,这些私有网络利用了更高的带宽、更低的延迟…...
vector、list、queue
引用:windows程序员面试指南 vector vector 类似于C语言中的数组 vector 支持随机访问,访问某个元素的时间复杂度 O(1) vector 插入和删除元素效率较低,时间复杂度O(n) vector 是连续存储,没有内存碎片,空间利用率高…...
操作系统面经
进程与线程区别 1.进程是资源分配的最小单位,线程是程序执行的最小单位(资源调度的最小单位) 2.进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数…...

一天约了4个面试,复盘一下面试题和薪资福利
除了最新的面经分享,还有字节大佬的求职面试答疑,告诉你关键问题是什么?少走弯路。**另外本文也汇总了6份大厂面试题:字节、腾讯、小米、腾讯云、滴滴、小米游戏。**希望对大家有帮助。 前言 昨天我的交流群里,有位宝…...

详解单链表(内有精美图示哦)
全文目录引言链表链表的定义与结构链表的分类单链表的实现及对数据的操作单链表的创建与销毁创建销毁单链表的打印单链表的头插与头删头插头删单链表的尾插与尾删尾插尾删单链表的查找单链表在pos位置后插入/删除插入删除单链表在pos位置插入/删除插入删除总结引言 在上一篇文…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...

MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...

Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
Xen Server服务器释放磁盘空间
disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...

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

C/C++ 中附加包含目录、附加库目录与附加依赖项详解
在 C/C 编程的编译和链接过程中,附加包含目录、附加库目录和附加依赖项是三个至关重要的设置,它们相互配合,确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中,这些概念容易让人混淆,但深入理解它们的作用和联…...

vulnyx Blogger writeup
信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...