附录3-大事件项目后端-项目准备工作,config.js,一些库的简易用法,main.js

news2024/11/24 14:40:13

目录

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
  • 后端代码链接 链接:百度网盘 请输入提取码 提取码:wd4n

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
    })

    // 判断token
    if (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端口启动

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

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

相关文章

【CSAPP】浮点数

文章目录小数表示练习1练习2IEEE浮点表示数字示例练习1练习2练习3舍人练习1练习2练习3浮点运算C语言中的浮点数练习1练习2浮点数对形如Vx∗2yVx*2^yVx∗2y的有理数进行编码。它对表示非常大的数(∣V∣>>0|V|>>0∣V∣>>0)、非常接近 0的…

单链表详解

单链表一.概念二.一些类型的创建三.尾插四.头插五.头删尾删六.打印链表七.单链表查找,任意位置插入,任意位置删除八.源代码一.概念 该篇链表博客是按照工程项目的格式来记录的,与平常的算法链表有些许不同,注意区分。 二.一些类型的创建 三.尾…

Hbuilder+uniapp 从零开始创建一个小程序

当你看到这篇博客的时候,那~说明~我的这篇博客写完了……哈哈哈哈哈哈哈哈。好的,清耐心往下看哈。如果有需要的,可以关注一下小作,后面还有小程序的云开发嗷~一、申请一个小程序账号(已经有账号的小可爱可以跳过&…

CEC2020:鱼鹰优化算法(Osprey optimization algorithm,OOA)求解CEC2020(提供MATLAB代码

一、鱼鹰优化算法简介 鱼鹰优化算法(Osprey optimization algorithm,OOA)由Mohammad Dehghani 和 Pavel Trojovsk于2023年提出,其模拟鱼鹰的捕食行为。 鱼鹰是鹰形目、鹗科、鹗属的仅有的一种中型猛禽。雌雄相似。体长51-64厘米…

巾帼绽芬芳 一起向未来(中篇)

编者按:为了隆重纪念纪念“三八”国际妇女节113周年,快来与你全方位、多层次分享交流“三八”国际妇女节的前世今生。分上篇(节日简介、节日发展和节日意义)、中篇(节日活动宗旨和世界各国庆祝方式)和下篇&…

mybatis的增删改查运用

目录 一、总览图 二、运用 一、总览图 代码总览图 数据库总览图 二、运用 数据库的一张表对应一个封装类,一个mapper接口,一个mapper.xml文件, 一个实现类。表中的增删改查都在里面编写 但是配置xml文件整个数据库只要一个就好了 1.…

路由器与交换机的区别(基础知识)

文章目录交换机路由器路由器和交换机的区别(1)工作层次不同(2)数据转发所依据的对象不同(3)传统的交换机只能分割冲突域,不能分割广播域;而路由器可以分割广播域(4&#…

软件大战升级,通用汽车与Qt达成合作,增强车内体验

从智能汽车产业现状来看,围绕软件而展开的争夺战已经打响。 英伟达首席执行官黄仁勋曾预测,未来四年内新车以成本价销售将不再是“天方夜谭”,因为利润将来自软件。 比如,英伟达与奔驰的合作,就将首次采用功能订阅的…

docker安装及命令使用

目录 1. Docker版本介绍 2. 创建Docker存储库 3. 安装docker软件包 4. Docker命令补全 6.Docker命令介绍 7. Docker镜像管理 7.1 列出本地镜像 7.2 搜索镜像 7.3 下载镜像 7.4 查看镜像 7.5 删除镜像 7.6 导出镜像 7.7 导入镜像 7.8 镜像改名 8. 容器管理 8.1 容…

再学C语言41:变长数组(VLA)

处理二维数组的函数&#xff1a;数组的行可以在函数调用时传递&#xff0c;但是数组的列只能被预置在函数内部 示例代码&#xff1a; #define COLS 4 int sum(int arr[][COLS], int rows) {int r;int c;int temp 0;for(r 0; r < rows; r){for(c 0; c < COLS; c){tem…

每个Android开发都应需知的性能指标~

无论你是发布一个新的 Android 应用&#xff0c;还是希望提高现有应用的性能&#xff0c;你都可以使用 Android 应用性能指标来帮助你。 在这篇文章中&#xff0c;我将解释什么是 Android 应用性能指标&#xff0c;并列出8个需要考虑跟踪的维度和建议的基线。 什么是 Android…

【LEAP模型】能源环境发展、碳排放建模

本次内容突出与实例结合&#xff0c;紧密结合国家能源统计制度及《省级温室气体排放编制指南》&#xff0c;深入浅出地介绍针对不同级别研究对象时如何根据数据结构、可获取性、研究目的&#xff0c;构建合适的能源生产、转换、消费、温室气体排放&#xff08;以碳排放为主&…

【NLP相关】深度学习领域不同编程IDE对比

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️&#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

死锁相关介绍【内含哲学家就餐问题】

死锁 死锁是这样一种情形&#xff1a;多个线程同时被阻塞&#xff0c;它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞&#xff0c;因此程序不可能正常终止。 场景1&#xff1a;一个线程&#xff0c;一把锁 一个线程&#xff0c;一把锁&#xff0c;线程…

【Linux】孤儿进程

在Linux中&#xff0c;如果子进程运行时&#xff0c;父进程因为某些原因先行终止&#xff0c;就称该子进程为孤儿进程。 我们编写如下代码&#xff1a; 子进程一直在运行&#xff0c;父进程运行一段时间后自动终止。运行该程序观察现象&#xff1a; 最开始时&#xff0c;子进程…

Unity 命令行发Android包

unity.exe 只允许存在一个 如果开了ide 或者之前的没关掉 就不能运行了 C: cd C:\Program Files\Unity\Editor\2021.3.6f1c1\Editor\ Unity.exe ^ -quit ^ -batchmode ^ -projectPath E:\puerts\UnityJenkins ^ -executeMethod Main.BuildC#代码放到任意Editor目录里 using S…

【linux】进程信号——信号的产生

进程信号一、信号概念1.1 信号理解二、产生信号2.1 通过键盘产生信号2.2 捕捉信号自定义signal2.3 系统调用接口产生信号2.3.1 向任意进程发送任意信号kill2.3.2 给自己发送任意信号raise2.3.3 给自己发送指定信号abort2.3.4 理解2.4 硬件异常产生信号2.4.1 除0异常2.4.2 野指针…

ACM-大一训练第三周(Floyd算法+并查集算法专题训练)

&#x1f680;write in front&#x1f680; &#x1f4dd;个人主页&#xff1a;认真写博客的夏目浅石.CSDN &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​ &#x1f4e3;系列专栏&#xff1a;ACM周训练题目合集.CSDN &#x1f4ac;总结&#xff1a…

五、Bean的作用域

1 singleton 默认情况下&#xff0c;Spring的IoC容器创建的Bean对象是单例的。测试&#xff1a; package com.power.spring6.bean;public class SpringBean {public SpringBean() {System.out.println("无参数构造方法执行了");} }<?xml version"1.0"…

Ubuntu中使用Synaptic进行包管理

Synaptic概况 Synaptic 是一个轻量级的 apt 软件包管理器系统的 GUI 前端&#xff0c;所有你可以在终端中使用 apt-get 命令来做的事&#xff0c;都可以通过 Synaptic 来实现。优势 图形化安装界面&#xff0c;同时可以安装配置相关依赖&#xff0c;避免由于依赖问题导致的各类…