• 【Node.js项目】大事件项目:后台架构图(含具体技术栈)、典型代码


    项目学习自:https://www.bilibili.com/video/BV1a34y167AZ

    1 项目后台架构图(含具体技术栈)

    在这里插入图片描述

    2 项目目录结构

    上图是之前在 ProcessOn 中画的,原图文件被删了,但是项目目录又有了一些小改动,这里直接文字说明一下:

    • 配置目录 config:存放 jwt 的密钥以及过期时间
    • 参数校验目录 schema :存放入参校验规则,配合 router 目录下的路由文件进行校验规则的绑定

    在这里插入图片描述

    3 项目典型代码

    各功能的代码都是类似的,这里除了必要的目录文件外,功能部分只写一下用户模块的代码

    config/config.js

    module.exports = {
      jwtSecretKey: "itheima No1. ^_^",
      expiresIn: "72h",
    };
    
    • 1
    • 2
    • 3
    • 4

    app.js

    const express = require("express");
    const app = express();
    const cors = require("cors");
    const joi = require("@hapi/joi");
    
    const config = require("./config/config");
    const userRouter = require("./router/user");
    const userInfoRouter = require("./router/userInfo");
    const articleRouter = require("./router/article");
    
    // 解析 token 的中间件
    const expressJWT = require("express-jwt");
    
    
    app.use((req, res, next) => {
      res.cc = (err, status = 1) => {
        res.send({ status, msg: err instanceof Error ? err.message : err });
      };
      next();
    });
    
    // 使用 .unless({ path: [/^\/api\//] }) 指定哪些接口不需要进行 Token 的身份认证
    app.use(expressJWT({ secret: config.jwtSecretKey }).unless({ path: [/^\/api\//] }));
    
    // 配置 cors 跨域
    app.use(cors());
    // 配置解析表单数据的中间件;
    app.use(express.urlencoded({ extended: false }));
    
    app.use("/api", userRouter);
    app.use("/user", userInfoRouter);
    app.use("/article", articleRouter);
    
    // 错误中间件
    app.use((err, req, res, next) => {
      // 表单校验错误
      if (err instanceof joi.ValidationError) return res.cc(err);
      // 捕获身份认证失败的错误
      if (err.name === "UnauthorizedError") return res.cc("身份认证失败!");
      // 未知错误
      res.cc(err);
    });
    
    app.listen(3007, () => {
      console.log("api server running at http://127.0.0.1:3007");
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    schema/user.js

    const joi = require("@hapi/joi");
    
    const username = joi.string().alphanum().min(1).max(10).required();
    const password = joi
      .string()
      .pattern(/^[\S]{6,12}$/)
      .required();
    
    const id = joi.number().integer().min(1).required();
    const nickname = joi.string().required();
    const email = joi.string().email().required();
    const avatar = joi.string().dataUri().required();
    
    exports.reg_login_schema = {
      // 表示需要对 req.body 中的数据进行验证
      body: {
        username,
        password,
      },
    };
    // 验证规则对象 - 更新用户基本信息
    exports.update_userInfo_schema = {
      body: {
        id,
        nickname,
        email,
      },
    };
    // 验证规则对象 - 重置密码
    exports.update_password_schema = {
      body: {
        oldPwd: password,
        newPwd: joi.not(joi.ref("oldPwd")).concat(password),
      },
    };
    // 验证规则对象 - 更新头像
    exports.update_avatar_schema = {
      body: {
        avatar,
      },
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    router/user.js

    const express = require("express");
    
    const userHandler = require("../router_handler/user");
    const expressJoi = require("@escook/express-joi");
    // 2. 导入需要的验证规则对象
    const { reg_login_schema } = require("../schema/user");
    
    const router = express.Router();
    
    // 注册新用户
    router.post("/reguser", expressJoi(reg_login_schema), userHandler.regUser);
    
    // 登录
    router.post("/login", expressJoi(reg_login_schema), userHandler.login);
    
    // 将路由对象共享出去
    module.exports = router;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    router_handler/user.js

    这里的 sql 处理也可以移至 db 模块

    const db = require("../db/index");
    
    // 加密密码
    const bcrypt = require("bcryptjs");
    // 用这个包来生成 Token 字符串
    const jwt = require("jsonwebtoken");
    // 导入配置文件
    const config = require("../config/config");
    const { expiresIn } = require("../config/config");
    
    // 注册用户处理函数
    const regUser = (req, res) => {
      const userInfo = req.body;
      if (!userInfo.username || !userInfo.password) return res.send({ status: 1, msg: "用户名或密码不能为空!" });
    
      const sql = "SELECT * FROM ev_users WHERE username =?";
      db.query(sql, [userInfo.username], (err, results) => {
        if (err) return res.cc(err);
        if (results.length > 0) return res.cc("用户名被占用,请更换其他用户名!");
    
        // 对用户的密码,进行 bcrype 加密,返回值是加密之后的密码字符串
        // userInfo.password = bcrypt.hashSync(userInfo.password, 10);
    
        const sql = "INSERT INTO ev_users set ?";
        db.query(sql, { username: userInfo.username, password: userInfo.password }, (err, results) => {
          if (err) return res.send({ status: 1, message: err.message });
          if (results.affectedRows !== 1) return res.send({ status: 1, message: "注册用户失败,请稍后再试!" });
    
          // 注册成功
          res.send({ status: 0, message: "注册成功!" });
        });
      });
    };
    
    // 登录处理函数
    const login = (req, res) => {
      const userInfo = req.body;
      const sql = "SELECT * FROM ev_users WHERE username =?";
      db.query(sql, userInfo.username, (err, results) => {
        if (err) return res.cc(err);
        if (results.length !== 1) return res.cc("用户不存在!");
        if (userInfo.password !== results[0].password) return res.cc("密码错误!");
    
        const userStr = { ...results[0], password: null, user_pic: null };
        // 生成token字符串
        const tokenStr = jwt.sign(userStr, config.jwtSecretKey, { expiresIn: config.expiresIn });
        res.send({ status: 0, msg: "登录成功", token: "Bearer " + tokenStr });
      });
    };
    
    module.exports = {
      regUser,
      login,
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    db/index.js

    const mysql = require("mysql");
    
    const db = mysql.createPool({
      host: "127.0.0.1",
      user: "root",
      password: "267845967",
      database: "my_db_01",
    });
    
    module.exports = db;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
  • 相关阅读:
    计算机基础
    ESLint自动修复代码规范错误
    3.3.OpenCV技能树--二值图像处理--图像形态学操作
    PostgreSQL源码分析——常量表达式化简
    echarts 多toolti同时触发图表实现
    SpringBoot SpringBoot 开发实用篇 4 数据层解决方案 4.5 SpringBoot 整合 Redis
    ICDE‘22推荐系统论文梳理之Industry篇
    酷早报:10月20日全球Web3加密行业重大资讯大汇总
    k大异或和(线性基)
    go语言 | 图解反射(二)
  • 原文地址:https://blog.csdn.net/m0_46360532/article/details/126686932