一、为什么需要逻辑抽离
这是我用express实现的一个缩减版的注册功能,如下:
- app.js
const express = require("express");
const app = express();
// 连接数据库
const mongoose = require("mongoose");
// 连接数据库myTest
mongoose
.connect("mongodb://localhost:27017/myTest", { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => {
console.log("数据库连接成功");
})
.catch((err) => {
console.log(err, "数据库连接失败");
});
// 创建集合规则
const userSchema = new mongoose.Schema({
userName: {
type: String,
required: true,
},
passWord: {
type: String,
required: true,
},
});
// 创建Users集合
const User = mongoose.model("User", userSchema);
const cors = require("cors");
// 解决跨域
app.use(cors());
// 支持json格式的请求体数据
app.use(express.json());
// 支持urlencoded格式的请求体数据
app.use(express.urlencoded({ extended: true }));
// 注册接口
app.post("/register", async (req, res) => {
const userModel = new User(req.body);
// 将用户注册的信息保存到数据库中
const dbBack = await userModel.save();
user = dbBack.toJSON();
// 以json格式返回给客户端
res.status(201).json({
code: 201,
msg: "注册成功",
user,
});
});
// 监听3000端口
app.listen(3000, () => {
console.log("server is running at http://localhost:3000");
});
目录结构如下:
可以看到的是所有的逻辑,创建服务器、链接数据库、创建集合、注册都在app.js文件中,这只是一个简单的注册功能,可能看上去还不是很乱,但是当我们后面项目越来越大,所做的功能越来越多,显然,将所有的逻辑功能都集中在app.js中是不行的,这样既不利用开发,也不利于后期维护,所以对逻辑的抽离,和整体项目结构的划分是很有必要的。
二、项目结构的搭建
1. 路由模块的抽离
这里我们先不考虑注册功能是否能实现了,只是单纯的做个逻辑划分,看抽离完成之后的路由是否在客户端可以访问到就可以了。
新建router
文件夹,在router
文件夹下新建index.js
和user.js
文件,如图:
- index.js
const express = require('express');
const router = express.Router();
router.use('/user', require('./user'));
module.exports = router;
- user.js
const express = require("express");
const router = express.Router();
router.post("/register", (req, res) => {
console.log(req.body);
res.send("register");
});
module.exports = router;
然后我们去app.js
中引入router/index.js
- app.js
const express = require("express");
const app = express();
app.use(express.json());
const router = require("./router");
app.use('/api/v1', router);
// 监听3000端口
app.listen(3000, () => {
console.log("server is running at http://localhost:3000");
});
经过这样的抽离以后我们再访问user/register
接口,就需要加上/api/v1
前缀,如图:
到这里,我们看app.js
文件中的代码逻辑是不是很清晰了,我们只是用express
创建了一个web
服务器,然后引入了一个路由文件,就实现了接口访问的逻辑。
那么接着看看user.js
文件
这里的注册逻辑,我没有具体实现,但是后期我们实现的时候,这里逻辑肯定比这复杂,还有就是,user模块,肯定也不止这一个注册功能,比如还有登录、修改密码、修改头像等等,这时如果还是将接口的具体实现都集中在user.js中,最后的这个效果就和我们开始分析的app.js文件一养,逻辑太过复杂,导致user.js
文件太过臃肿,不利于维护,所以,我们将user.js
文件中的接口具体实现也单独抽离出来
新建一个controller
文件夹,controller
文件夹下新增一个userController.js
文件
- userController.js
// 用户注册
exports.register =(req, res) => {
console.log(req.body);
res.send("register");
}
修改user.js
文件
const express = require("express");
const router = express.Router();
const userController = require("../controller/userController");
router.post("/register", userController.register);
module.exports = router;
这样比如我们要加个登录的功能,只需要在user中加一行代码就可以了,例如:
const express = require("express");
const router = express.Router();
const userController = require("../controller/userController");
router.post("/register", userController.register);
router.post("/login", userController.login);
module.exports = router;
而具体的登录逻辑,我们可以在userController
中实现。
好啦,到这里我们的路由的抽离基本就可以了,接下来我们来具体实现一下开始的在app.js中的那个注册功能。
2. 数据库操作部分抽离
基于上面的路由抽离,要实现注册功能,我们可以在userController
中来加上数据方面的操作,如下:
- userController.js
// 连接数据库
const mongoose = require("mongoose");
// 连接数据库myTest
mongoose
.connect("mongodb://localhost:27017/myTest", { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => {
console.log("数据库连接成功");
})
.catch((err) => {
console.log(err, "数据库连接失败");
});
// 创建集合规则
const userSchema = new mongoose.Schema({
userName: {
type: String,
required: true,
},
passWord: {
type: String,
required: true,
},
});
// 创建Users集合
const User = mongoose.model("User", userSchema);
// 用户注册
exports.register = async (req, res) => {
const userModel = new User(req.body);
// 将用户注册的信息保存到数据库中
const dbBack = await userModel.save();
user = dbBack.toJSON();
// 以json格式返回给客户端
res.status(201).json({
code: 201,
msg: "注册成功",
user,
});
};
此时我们在访问注册接口:
可以看到数据库users
集合中成功添加了一条数据,说明我们的注册功能是实现了。但是,我们在回头看看userController.js
,此时的数据库连接操作,创建集合都集中在了这里,就算我们创建users集合放在userController.js中合理,但是数据库连接呢?
我们的整个项目肯定不止涉及一个集合,每当新建个controller
时,我们都要连接数据库,所以这个连接数据库的操作显然是一个可复用的功能,所以我们先把这一块的逻辑抽离出来。
新建一个model/index.js
文件
- model/index.js
const mongoose = require("mongoose");
mongoose
.connect("mongodb://localhost:27017/myTest")
.then((res) => {
console.log("mongo链接成功");
})
.catch((err) => {
console.log(err);
console.log("mongo链接失败");
});
module.exports = mongoose;
修改userController.js
const mongoose = require("../model/index");
// 创建集合规则
const userSchema = new mongoose.Schema({
userName: {
type: String,
required: true,
},
passWord: {
type: String,
required: true,
},
});
// 创建Users集合
const User = mongoose.model("User", userSchema);
// 用户注册
exports.register = async (req, res) => {
const userModel = new User(req.body);
// 将用户注册的信息保存到数据库中
const dbBack = await userModel.save();
user = dbBack.toJSON();
// 以json格式返回给客户端
res.status(201).json({
code: 201,
msg: "注册成功",
user,
});
};
但是我们的userController
中应该只注重接口的的具体实现,集合的规则和创建也应该单独抽离出来
新建model/userModel.js
- model/userModel.js
const mongoose = require("mongoose");
// 创建集合规则
const userSchema = new mongoose.Schema({
userName: {
type: String,
required: true,
},
passWord: {
type: String,
required: true,
},
});
module.exports = userSchema;
修改model/index
导出
- model/index.js
const mongoose = require("mongoose");
const { mongopath } = require("../config/config.default");
mongoose
.connect(mongopath)
.then((res) => {
console.log("mongo链接成功");
})
.catch((err) => {
console.log(err);
console.log("mongo链接失败");
});
module.exports = {
User: mongoose.model("User", require("./userModel")),
};
修改userController.js
- userController.js
const { User } = require("../model/index");
// 用户注册
exports.register = async (req, res) => {
const userModel = new User(req.body);
// 将用户注册的信息保存到数据库中
const dbBack = await userModel.save();
user = dbBack.toJSON();
// 以json格式返回给客户端
res.status(201).json({
code: 201,
msg: "注册成功",
user,
});
};
至此我们实现了controller功能的单一性,也将数据操作都抽离到了model文件夹下,这时我们在用postman访问一下register接口,如下:
成功访问!
至此呢我们项目的基本架构就算完成啦。
整体目录结构如下:
将路由相关访问抽离到router文件夹下,接口逻辑的具体实现抽离到controller文件夹下,数据库集合相关操作抽离到model文件夹下,一些配置文件抽离到config文件夹下,我们的入口文件app.js只是创建一个服务器,具体的功能我们只需要引入对于的模块就可以了