1. 初始化node项目
创建一个文件夹,在这个文件夹下打开命令行窗口
// 1. 初始化一个package.json文件
npm init -y
// 2.. 安装express
pnpm i express
// 3. 安装热更新库
pnpm i nodemon
// 4. 安装mysql数据库插件
pnpm i mysql
// 5. 安装cors跨域插件
pnpm i cors
// 6. 安装生成token的jwt插件
pnpm i jsonwebtoken
// 7. 安装解析token的jwt插件
pnpm i express-jwt
// 8. 安装日期插件
pnpm i dayjs
基本目录结构

基本目录结构
2. 启动服务器
- 在根目录下创建app.js文件作为后端服务启动入口
app.js
// 导入express库
const express = require("express");
const app = express();
// 设置端口号
const port = process.env.PORT || 1800;
// 导入解析token的库
const expressjwt = require("express-jwt");
// 导入解决跨域库
const cors = require("cors");
// 导入配置文件
const config = require("./config");
// 把跨域模块注册到app实例上
app.use(cors());
// 托管静态资源
app.use(express.static("public"));
// 配置解析post数据的中间件,这个中间件只能解析application/json格式的数据
app.use(express.json());
// 配置解析post数据的中间件,这个中间件只能解析application/x-www-form-urlencoded格式的表单数据
app.use(express.urlencoded());
// 导入注册、登录路由模块
const userRouter = require("./router/user");
// 定义全局错误中间件,必须在路由之前定义
app.use((req, res, next) => {
// 在res对象上挂载一个自定义处理错误的函数,status(0:成功,1:失败)
res.myErr = (err, status = 1) => {
res.send({
status,
message: err instanceof Error ? err.message : err,
});
};
next();
});
// 一定要定义在路由之前来解析token
app.use(expressjwt.expressjwt({ secret: config.jwtKey, algorithms: ["HS256"] }).unless({ path: [/^\/api\//] }),);
// 把路由模块注册到app实例上,/api是注册登录路由模块的前缀,可以跳过身份验证
app.use("/api", userRouter);
// 定义中间件、路由、连接数据库……
app.use((err, req, res, next) => {
// 验证失败导致的错误
if (err instanceof joi.ValidationError) return res.myErr(err);
// 捕获身份认证失败的错误
if (err.name === "UnauthorizedError") return res.myErr("身份认证失败!");
// 未知错误
res.myErr(err);
});
// 监听服务器的启动
app.listen(port, () => {
console.log(port + "端口服务启动成功!! ");
});
自定义config.js文件
// 配置文件
// 导入日期解析包
const dayjs = require("dayjs");
module.exports = {
// 生成token的密钥
jwtKey: "onepiece//",
// token的过期时间
expirytime: "10000h",
// 获取系统当前时间
nowTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
};
3. 创建路由
- 在根目录router文件中,根据不同的功能,创建不同的路由文件,以注册、登录为例
router/user.js
// 首页注册、登录路由模块
// 导入express
const express = require("express");
// 实例化路由
const router = express.Router();
// 导入路由处理函数模块
const userHandler = require("../router_handler/user");
// 定义路由
// 注册用户
router.post("/register", userHandler.register);
// 登录
router.post("/login", userHandler.login);
//向外暴露路由
module.exports = router;
4. 连接mysql数据库
- 在根目录下创建db/index.js文件
db/index.js
// 导入mysql数据库模块
const mysql = require("mysql");
// 创建数据库连接对象
const db = mysql.createPool({
// 数据库连接地址
host: "127.0.0.1",
// 数据库用户名
user: "root",
// 数据库密码
password: "123456",
// 连接的数据库名,需要存在一个onepiece数据库
database: "onepiece",
});
// 向外共享db数据库连接对象
module.exports = db;
5. 开发路由逻辑
- 在router_handler文件中,创建不同模块的路由逻辑,以注册、登录为例
router_handler/user.js
/**
* 注册、登录路由处理函数模块
* @type {{}}
*/
// 导入数据库连接
const db = require("../db/index");
// 导入密码加密库
const bcrypt = require("bcryptjs");
// 导入生成token的库
const jwt = require("jsonwebtoken");
// 导入配置文件
const config = require("../config");
// 注册用户
exports.register = (req, res) => {
// 获取用户传递application/x-www-form-urlencoded的参数
const userInfo = req.body;
// 定义用户表查询sql语句
const selectSql = "select * from user where username=?";
// 判断用户是否存在用户表中
db.query(selectSql, userInfo.userName, (err, results) => {
// 查询出错
if (err) return res.myErr(err);
// 用户名存在
if (results.length > 0) return res.myErr("用户名已被占用!");
// 密码加密
userInfo.password = bcrypt.hashSync(userInfo.password, 10);
// 定义用户表插入sql语句
const insertSql = "insert into user set ?";
// 把用户信息插入到用户表中
db.query(
insertSql,
{
userName: userInfo.userName,
password: userInfo.password,
createTime: config.nowTime,
updateTime: config.nowTime,
},
(err, result) => {
// 查询出错
if (err) return res.myErr(err);
// 判断是否注册成功
if (result.affectedRows !== 1)
return res.myErr("用户注册失败,请稍后重试!");
// 注册成功
res.send({ status: 0, message: "用户注册成功!" });
},
);
});
};
// 登录
exports.login = (req, res) => {
// 获取用户传递application/x-www-form-urlencoded的参数
const userInfo = req.body;
// 定义用户表查询sql语句
const selectSql = "select * from user where username=?";
// 判断用户是否存在用户表中
db.query(selectSql, userInfo.userName, (err, results) => {
// 查询出错
if (err) return res.myErr(err);
// 用户名不存在
if (results.length !== 1) return res.myErr("用户名或密码不正确");
// 验证客户提交密码与数据库存储的密码是否一致
const passwordResult = bcrypt.compareSync(
userInfo.password,
results[0].password,
);
if (!passwordResult) return res.myErr("用户名或密码不正确");
// 使用jwt生成token,一般是用用户的id用于生成token,敏感信息不建议放在token信息中
const user = { ...results[0], password: "", userPic: "" };
// 根据用户id+token密钥+过期时间来生成token
const tokenStr = jwt.sign(user, config.jwtKey, {
expiresIn: config.expirytime,
});
res.send({ status: 0, message: "登录成功!", token: "Bearer " + tokenStr });
});
};