【Node.js项目】大事件项目:后台架构图(含具体技术栈)、典型代码
项目学习自:https://www.bilibili.com/video/BV1a34y167AZ
文章目录
- 1 项目后台架构图(含具体技术栈)
- 2 项目目录结构
- 3 项目典型代码
- config/config.js
- app.js
- schema/user.js
- router/user.js
- router_handler/user.js
- db/index.js
1 项目后台架构图(含具体技术栈)
2 项目目录结构
上图是之前在 ProcessOn 中画的,原图文件被删了,但是项目目录又有了一些小改动,这里直接文字说明一下:
- 配置目录 config:存放 jwt 的密钥以及过期时间
- 参数校验目录 schema :存放入参校验规则,配合 router 目录下的路由文件进行校验规则的绑定
3 项目典型代码
各功能的代码都是类似的,这里除了必要的目录文件外,功能部分只写一下用户模块的代码
config/config.js
module.exports = {
jwtSecretKey: "itheima No1. ^_^",
expiresIn: "72h",
};
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");
});
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,
},
};
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;
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,
};
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;