Express 中文网-https://express.nodejs.cn/
使用express搭建项目
// 安装express生成器
npm install -g express-generator
express
y
pnpm i
pnpm run start
添加.gitignore文件
jsnode_modules/
public/uploads
安装本地mongobd使用nodejs链接成功
这里就不细说mongodb 默认大家都安装好了并且开启了mongodb服务
新建上图对应的文件夹
pnpm i mongoose
db/index.js
const mongoose = require("mongoose");
mongoose.connect("mongodb://127.0.0.1:27017/vue3admin", {});
const db = mongoose.connection;
db.on("error", console.error.bind(console, "connection error:"));
db.once("open", (res) => console.log("db ok"));
在app.js中添加
// 链接mongodb
...
require("./db");
...
重新启动 pnpm run start
刚好到这里 我们可以引入入 nodemon
// 安装
pnpm i nodemon
// 修改packagejson
"scripts": {
"start": "nodemon ./bin/www"
},
// 重新启动
pnpm run start
nodemon用来监视node.js应用程序中的任何更改并自动重启服务,非常适合用在开发环境中。以前,我们开发一个node后端服务时,每次更改文件,均需重启一下,服务才能生效。这使我们的开发效率降低了很多。nodemon的出现,可以随时监听文件的变更,自动重启服务,我们开发时只需关注代码即可,不再需要手动重启服务
这样就OK了
用户模块的构建
直接上代码 db/model/user.js
const mongoose = require("mongoose");
const schemaRules = {
id: { type: String }, // 用户ID,必需且唯一
username: {
type: String,
required: true,
unique: true,
minlength: 2,
maxlength: 20,
}, // 用户名,必需且唯一
password: {
type: String,
required: true,
match: /^(?=.*[a-zA-Z])(?=.*\d)[a-zA-Z\d\S]{6,}$/, // 长度至少6位,包含字母和数字或字符
}, // 密码,必需
address: {
provinceName: { type: String },
cityName: { type: String },
areaName: { type: String },
countyName: { type: String },
streetName: { type: String },
provinceCode: { type: String },
cityCode: { type: String },
areaCode: { type: String },
countyCode: { type: String },
streetCode: { type: String },
},
nickname: { type: String }, // 昵称
createdTime: { type: Date, default: Date.now }, // 创建时间,默认为当前时间
updatedTime: { type: Date, default: Date.now }, // 最后更新时间,默认为当前时间
roleIds: { type: Array }, // 角色ids
age: { type: Number }, // 年龄
region: { type: Object }, // 地区
email: { type: String }, // 邮箱
phone: { type: String }, // 手机号
description: { type: String }, // 个人简
qq: { type: String }, // QQ号
roleIds: { type: Array }, // 绑定的角色ID
status: { type: String, default: 0 }, // 是否启用,
sex: { type: String, default: 0 }, // 性别,1代表男性,0代表女性,默认为0
avatar: { type: String, default: "" }, // 头像
openid: { type: String }, // 微信扫码OpenID
// 是否是管理员
isManager: { type: Boolean, default: false },
};
// 定义用户模型
const userSchema = new mongoose.Schema(schemaRules);
// 创建用户模型
const User = mongoose.model("User", userSchema);
// 导出用户模型
module.exports = { User, schemaRules };
utils/index.js
pnpm i uuid
// 使用 UUID v4 生成全局唯一 ID
function generateUUID() {
const { v4: uuidv4 } = require("uuid");
return uuidv4();
}
module.exports = {
generateUUID,
};
在app.js中 添加
// 定义全局方法
const { generateUUID } = require("./utils");
global.$generateUUID = generateUUID;
routes/user.js
var express = require("express");
var router = express.Router();
const { User, schemaRules } = require("../db/model/user");
// 新增用户
router.post("/add", async (req, res) => {
const { body } = req;
try {
await User.create({ ...body, id: $generateUUID() }); // 创建新用户
res.send({ code: 200, message: "创建成功" });
} catch (error) {
res.send({ code: 500, message: error });
}
});
// 删除用户
router.delete("/delete", async (req, res) => {
try {
const { id, ids } = req.body;
if (id) {
await User.deleteOne({ id });
} else {
await User.deleteMany({ id: { $in: ids } });
}
res.send({ code: 200, message: "删除成功" });
} catch (error) {
res.send({ code: 500, message: error });
}
});
// 修改用户
router.put("/update", async (req, res) => {
try {
const { id } = req.body;
await User.updateOne({ id }, { ...req.body, updatedTime: Date.now() });
res.send({ code: 200, message: "更新成功" });
} catch (error) {
res.send({ code: 500, message: error });
}
});
// 查询用户列表
router.post("/list", async (req, res) => {
const { username, page = { pageSize: 10, page: 1 } } = req.body;
const query = {};
// 添加 username 模糊查询条件
if (username) {
query.username = { $regex: username };
}
try {
const users = await User.find(query)
.skip((page.page - 1) * page.pageSize)
.limit(page.pageSize)
.sort({ createdTime: -1 }); // 按创建时间倒序排序
const total = await User.countDocuments(query); // 获取符合条件的用户总数
res.send({ code: 200, data: users, page: { ...page, total } });
} catch (error) {
res.send({ code: 500, message: error });
}
});
// 用户详情
router.get("/detail", async (req, res) => {
try {
const userId = req.query.id;
const user = await User.findOne({ id: userId }); // 根据ID查询用户
if (!user) res.send({ code: 500, message: `没有ID为${userId}的用户信息` });
res.send({ code: 200, data: user });
} catch (error) {
res.send({ code: 500, message: error });
}
});
// 注册接口
// 登录接口
module.exports = router;
jsonwebtoken验证模块=》token
utils/token.js
pnpm i jsonwebtoken
const jwt = require("jsonwebtoken");
// 秘钥
const screat = "vue3admin";
//生成token
function createToken(playload) {
playload.ctime = Date.now();
playload.exps = 24 * 60 * 60 * 1000; // 手动设置过期时间 60s
return jwt.sign(playload, screat);
}
// 验证token
function verifyToken(token) {
return new Promise((resolve, reject) => {
jwt.verify(token, screat, (err, data) => {
if (!token) return reject({ code: 401, msg: "请携带token请求" });
if (err) return reject({ code: 401, msg: "token 验证失败" });
const beforeTime = data.ctime + data.exps;
const nowTime = Date.now();
if (nowTime > beforeTime) return reject({ code: 401, msg: "token 过期" }); // 比对当前时间戳 jwt创建的时间+有效期 前端收到重新获取token
resolve(data);
});
});
}
// 定义全局校验 token 的中间件
async function checkToken(req, res, next) {
// 定义不需要 token 验证的接口路径
const whiteList = [
"/user/login",
"/user/register",
"/user/get-by-token",
/^\/utils/,
]; // 使用正则表达式来匹配 /xx 开头的路径
const path = req.path;
// 如果当前请求路径在白名单内,则不需要 token 验证,直接通过
if (
whiteList.some((item) =>
item instanceof RegExp ? item.test(path) : item === path
)
) {
return next();
}
// 检查是否存在 skipToken 参数
// const skipToken = req.headers.skipToken;
// if (skipToken) {
// return next();
// }
// 否则,检查请求头是否包含 token
const token = req.headers.token;
if (!token) {
// 如果没有携带 token,则返回 401 Unauthorized 状态码
return res.json({ code: 401, message: "请先登录" });
}
try {
// 验证 token 是否有效
const data = await verifyToken(token);
// 将解析出来的用户信息挂载到 req 对象上,方便后面路由的使用
req.user = data;
next();
} catch (err) {
// token 验证失败或过期,则返回 401 Unauthorized 状态码
return res.json({ code: 401, message: err.msg });
}
}
module.exports = {
createToken,
verifyToken,
checkToken,
};
整理下app.js
var express = require("express");
var path = require("path");
var app = express();
require("./db"); // 引入数据库连接对象
app.use(express.json()); // 解析 JSON 请求体
app.use(express.urlencoded({ extended: false })); // 解析 URL 编码请求体
// 静态资源路径
app.use(express.static(path.join(__dirname, "public")));
// 设置视图模板引擎和所在目录
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "jade");
// 跨域
app.all("*", function (req, res, next) {
res.header("Access-Control-Allow-Origin", "http://localhost:5173"); // 允许的来源域名
res.header(
"Access-Control-Allow-Headers",
"Content-Type,Content-Length,Authorization,Accept,X-Requested-With,token"
);
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
res.header("Access-Control-Allow-Credentials", "true"); // 允许携带凭据
res.header("X-Powered-By", "3.2.1");
next();
});
// 定义全局方法
const { generateUUID } = require("./utils");
global.$generateUUID = generateUUID;
// 全局 token 拦截中间件
const { checkToken } = require("./utils/token");
app.use(checkToken);
// 注册路由
require("./utils/route")(app);
module.exports = app;
自动注册路由 utils/route.js
const fs = require("fs");
const path = require("path");
module.exports = function (app) {
const routesDir = path.join(__dirname, "../routes"); // 路由文件所在目录
const routeFiles = fs.readdirSync(routesDir); // 获取所有路由文件
routeFiles.forEach((file) => {
const router = require(path.join(routesDir, file));
let routerPath = `/${file.split(".")[0]}`; // 根据文件名生成访问路径
routerPath = routerPath == "/index" ? "/" : routerPath; // 将 "/index" 路径映射为根路径 "/"
app.use(routerPath, router); // 注册路由
});
};
这样的话我们就可以编写登录接口注册接口了
可以直接访问 localhost:3000
那这样我们的token拦截也成功了
登录接口
js// 登录接口
router.post("/login", async (req, res) => {
const { username, password } = req.body;
if (!username || !password)
return res.send({ code: 500, message: "用户名或密码不能为空" });
try {
const user = await User.findOne({ username, password });
if (!user) return res.send({ code: 403, message: "用户名或密码错误" });
let { id, avatar, status } = user;
if (status != 0) return res.send({ code: 403, message: "账号状态问题!" });
let token = createToken({ login: true, name: username, id, avatar });
res.send({
code: 200,
message: "登录成功",
data: { username, id, avatar, token },
});
} catch (error) {
res.send({ code: 500, message: error });
}
});
注册接口
这个接口就比较麻烦 我们先简单完成功能后续可以对接邮箱验证码辅助账号注册 目前可以先调试下新增和登录就行
到这里我们就完成了简单服务node服务搭建
vue3+vite+ts+pinia+router4搭建后台管理系统(1)搭建项目
最后
欢迎 点赞 收藏 有问题欢迎留言评论!!