node基于express+mongodb项目的整体结构搭建和逻辑抽离

news2024/12/23 17:14:28

一、为什么需要逻辑抽离

这是我用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.jsuser.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只是创建一个服务器,具体的功能我们只需要引入对于的模块就可以了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/748665.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python接口自动化(三十六)-封装与调用--流程类接口关联续集(详解)

简介 上一篇已经给大家都介绍过了流程类接口关联,但是由于博客的登录机制改变,所以没有办法给小伙伴们实战演练一下,那么这篇就按照上一篇计划的用jenkins来给小伙伴们演示一下流程类接口的封装和调用,其实很简单,就是…

RestTemplate和Sentinel整合

引入restTemplate EnableDiscoveryClient EnableFeignClients SpringBootApplication public class OrderApplication {BeanLoadBalanced//添加注解SentinelRestTemplateSentinelRestTemplatepublic RestTemplate getRestTemplate() {return new RestTemplate();}public stati…

【已解决】html元素如何使字体占据相同的元素显得整齐

本博文源于自身的亲身实践,让html的文本元素对齐,如果不让其对齐就会变得很丑陋,如下图,那么如何设置才能让元素占据相同呢? 文章目录 1、问题来源2、问题解决思路3、问题解决方案4、问题完整源码及效果 1、问题来源 …

animation.css无法显示动画效果问题解决

在使用【微信开发者工具】开发微信小程序时发现无法在开发者工具中展示出动画效果来 但是真机调试中可以正常的显示动画效果 【关于微信小程序中如何使用animation.css,参考微信小程序使用animation.css_THE WHY的博客-CSDN博客 】 同时发现在官网上点击各个动画并…

Django_POST请求的CSRF验证

目录 正常验证CSRF form表单 ajax的POST请求 关闭CSRF验证 源码等资料获取方法 django的POST接口发起请求默认清空下需要进行CSRF验证 正常验证CSRF form表单 如果form表单直接在标签之间添加{{ csrf_token }}就可以完成验证 ajax的POST请求 ajax的post需要在请求的he…

【Vue2.0源码学习】模板编译篇-模板解析阶段(整体运行流程)

文章目录 1. 前言2. 什么是模板编译3. 整体渲染流程4. 模板编译内部流程4.1 抽象语法树AST4.2 具体流程 5. 小总结6. 整体流程7. 回到源码8. 总结 1. 前言 在前几篇文章中,我们介绍了Vue中的虚拟DOM以及虚拟DOM的patch(DOM-Diff)过程,而虚拟DOM存在的必…

阿里云AliYun物联网平台使用-设备添加以及模拟设备端上云

一、前言 上一篇文章提到,我们已经申请了免费的阿里云平台,下面需要将我们的设备在阿里云上进行注册和申请,以便于我们的数据上云。 二、步骤 注册产品(设备模型) 在产品页面,点击 "创建产品" 。…

DevExpress WinForms TreeList控件,让业务数据展示更清晰!(一)

DevExpress WinForms的TreeList控件是一个功能齐全、数据感知的TreeView-ListView的混合体,它可以以树形、网格或两者结合的形式显示数据信息。无论是数据绑定模式还是非绑定模式,都具有完整的数据编辑支持。 PS:DevExpress WinForm拥有180组…

【测试开发】Junit 框架

目录 一. 认识 Junit 二. Junit 的常用注解 1. Test 2. Disabled 3. BeforeAll 4. AfterAll 5. BeforeEach 6. AfterEach 7. 执行测试 三. 参数化 1. 引入依赖 2. 单参数 3. 多参数 3.1 通过CSV实现 3.2 通过方法实现 4. 测试用例的执行顺序 四. 断言 五…

设计模式【结构型】-- 装饰者模式

装饰模式(Decorator Pattern) 定义 装饰者模式是一种结构型设计模式,它允许你动态地将新功能添加到对象中,通过将对象放入包含这些功能的特殊包装器对象中。这样一来,你可以在运行时通过组合不同的对象来扩展功能&…

用手机号注册亚马逊买家号需要注意什么问题

亚马逊平台的买家号可以用手机号注册也可以用邮箱进行注册,注册方法都是打开官网后点击注册,根据提示输入账号信息。当使用手机号注册亚马逊买家号时,有一些问题需要注意: 1、确保手机号的准确性:正确的手机号码非常重…

Android 系统的分区介绍

由于Android系统采用Linux架构,所以Android的系统分区可以类比同样采用Linux架构的操作系统(如Windows)。 Android系统分区分类 现在一般常见的Android分区方式共有三种,在不同的Android系统版本上会采用不同的分区方式。 1、传…

CentOS 7.8 Oracle 19C安装部署

CentOS 7.8 Oracle 19C安装部署 一、环境检查1、操作系统检查2、内存检查3、SWAP检查4、共享内存检查5、磁盘空间检查 二、YUM配置及RPM依赖包安装1、YUM源搭建2、 RPM依赖包安装 三、创建组、用户、目录1、创建组、用户2、创建目录 四、系统参数配置1、关闭防火墙2、配置域名解…

跟我一起从零开始学python(七)机器学习

前言 回顾之前讲了python语法编程 ,必修入门基础和网络编程,多线程/多进程/协程等方面的内容,昨天和今天讲到了数据库编程篇MySQL,Redis今天第三篇MongoDB篇,前面没看的也不用往前翻,系列文已经整理好了&a…

【Axure高保真原型】美化滚动条模板

今天和大家分享美化滚动条的原型模板,包括美化动态面板滚动条、页面滚动条、内联框架滚动条,其中内联框架滚动条是通过美化对应调用的页面的滚动条而美化,并不是直接美化内联框架的滚动条。具体效果可以观看下方视频或者打开预览地址体验&…

个人微信开发API,微信机器人。

微信个人号二次开发,基于API开发可以有很多功能模块 各种知名SCRM系统、客服平台都是根据此API二次开发的。 在这里插入图片描述 好友管理: 添加好友、 删除好友、 修改备注、 创建标签、 获取好友列表、 检测僵尸粉 设置个人头像 同意添加好友 获取好…

【面试题38】linux下面chmod和chown使用详解

文章目录 一、前言二、什么是 chmod 命令?2.1 使用方法:2.2 数值表示法:2.3 符号表示法: 三、什么是 chown 命令?3.1 使用方法:3.2 更改所有者和用户组: 四、使用示例4.1 使用 chmod 命令修改权…

想要逼疯项目经理,真的太简单了

早上好,我是老原。 最近有个小友来找我吐槽,说太崩溃了,带个项目太不容易了…… 此情此景,我已经脑补了各种抱头痛哭流涕的画面,油然升起一股同情。 其实,项目经理,听起来是个经理&#xff0…

echarts条形图动态显示2

1、实现效果,条形图自动滚动,鼠标移入停止滚动,移出继续滚动 2、代码 声明的变量:图表,图表数据与定时器 myChartArea: , dataArea: {categoryData: [],valueData: [],fullData: [], }, timeOut: null,设…

【无公网IP端口映射】远程访问本地jupyter notebook服务

文章目录 前言1. Python环境安装2. Jupyter 安装3. 启动Jupyter Notebook4. 远程访问4.1 安装配置cpolar内网穿透4.2 创建隧道映射本地端口 5. 固定公网地址 前言 Jupyter Notebook,它是一个交互式的数据科学和计算环境,支持多种编程语言,如…