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

一、为什么需要逻辑抽离

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【云原生】k8s之Ingress

1.Ingress的相关知识 1.1 Ingress的简介 service的作用体现在两个方面,对集群内部,它不断跟踪pod的变化,更新endpoint中对应pod的对象,提供了ip不断变化的pod的服务发现机制;对集群外部,他类似负载均衡器…

【剧前爆米花--web】HTTP协议格式详解以及构造

作者:困了电视剧 专栏:《JavaEE初阶》 文章分布:这是一篇关于HTTP协议的文章,在这篇文章中我会说明HTTP协议格式以及相关的构造,希望对你有所帮助! 目录 HTTP协议 HTTP协议格式 HTTP请求 HTTP响应详情…

前端基本功 用 React Hooks + Antd 实现一个 Todo-List

背景 使用 React Hooks 以及组件库 Antd 来实现一个可以 增删 标记是否完成 的 todo-list 思路 要实现一个 todo-list 首先想到用 useState 维护一个状态数组来保存当前 list ,还要用一个状态维护添加框中的内容 const [todos, setTodos] useState(initialValu…

如何用双指针法解决力扣“反转单词前缀”问题

本篇博客会讲解力扣“2000. 反转单词前缀”的解题思路,这是题目链接。 本题的思路是:先调用strchr函数,在字符串word中查找字符ch,若找到了,则会返回一个非空指针p,指向ch在word中的位置。为了反转从word到…

【UE4 塔防游戏系列】10-防御塔升级

目录 效果 步骤 一、根据防御塔等级修改子弹伤害 二、根据防御塔等级修改子弹速度 三、根据防御塔等级修改检测半径 四、根据防御塔等级修改子弹颜色 五、根据防御塔等级修改换弹时间 效果 步骤 一、根据防御塔等级修改子弹伤害 1. 打开“TowerBaseBullet_Child”&…

搭建Redis分片集群

说明:单体Redis有许多问题,可通过Redis数据持久化、搭建主从集群、哨兵和Redis分片集群解决单体Redis数据丢失、高并发、数据恢复和海量数据存储的问题。前三个参考http://t.csdn.cn/6pp2F、http://t.csdn.cn/o9u0S,本问介绍如何创建Redis分片…

http连接处理(下)(四)

1.结合代码分析请求报文响应 下面我们将介绍服务器如何响应请求报文,并将该报文发送给浏览器端。首先介绍一些基础API,然后结合流程图和代码对服务器响应请求报文进行详解。 基础API部分,介绍stat、mmap、iovec、writev。 流程图部分&…

数据结构--时间复杂度与空间复杂度

数据结构–时间复杂度与空间复杂度 文章目录 数据结构--时间复杂度与空间复杂度时间复杂度一、什么是时间复杂度二、具体实例1.大O的渐进表示法2.二分查找的时间复杂度 空间复杂度一、什么是空间复杂度二、具体实例总结 时间复杂度 一、什么是时间复杂度 在计算机科学中&…

微信小程序-地图上的图标计算旋转值朝向经纬度计算

废话不多说,开整 // 参数为寄件人经纬度和收件人经纬度 // 根据寄收件人经纬度弧度π进行rotate旋转计算 const getRotate (po1, po2) > {if (!(po1 && po2)) return 0const lng_a po1.longitudeconst lat_a po1.latitudeconst lng_b po2.longitud…

238. 除自身以外数组的乘积

题目描述&#xff1a; 主要思路&#xff1a; 正逆各扫一遍&#xff0c;利用数组存储当前数左边和右边的乘积。 class Solution { public:vector<int> productExceptSelf(vector<int>& nums) {int nnums.size();vector<int> ans;int l[n1],r[n1];l[0]1,…

Stable Diffusion - 图像反推 (Interrogate) 提示词算法 (BLIP DeepBooru)

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/131817599 图像反推 (Interrogate) 功能&#xff0c;是指根据给定的图像生成一个或多个文本提示&#xff0c;这些提示可以描述图像的内容、风格、…

【C++杂货铺】构造函数和析构函数

文章目录 一、类的六个默认成员函数二、构造函数三、析构函数 一、类的六个默认成员函数 &#x1f4d6;默认成员函数 用户没有显式实现&#xff0c;编译器会自动生成的成员函数&#xff0c;称为默认成员函数。 构造函数&#xff1a;完成对象的初始化工作。析构函数&#xff…

前端笔记_OAuth规则机制下实现个人站点接入qq三方登录

文章目录 ⭐前言⭐qq三方登录流程&#x1f496;qq互联中心创建网页应用&#x1f496;配置回调地址redirect_uri&#x1f496;流程分析 ⭐思路分解⭐技术选型实现&#x1f496;技术选型&#xff1a;&#x1f496;实现 ⭐结束 ⭐前言 大家好&#xff0c;我是yma16&#xff0c;本…

Vue2计算属性如何传参

Vue2官网并没解释计算属性应该怎么传值&#xff0c;但是呢&#xff0c;通过闭包的方式(使用箭头表达式)实际上是可以给计算属性传参的&#xff08;当然&#xff0c;多个参数也是可行的&#xff09;。 以下是本人项目开发使用自己基于ElementUI封装的集信息采集与文件上传功能的…

微信小程序基于Promise封装发起网络请求

1.创建一个request.js // 相当于域名 const baseURL ***************; // 暴露一个request函数 export function request(parms) {// 路径拼接const url baseURL parms.url;// 请求体&#xff0c;默认为{}const data parms.data || {};// 请求方式&#xff0c;默认为GETco…

攻防世界-web-easytornado

题目描述&#xff1a;Tornado 框架。打开链接是一个简单的界面 1. 思路分析 看到有个/flag.txt&#xff0c;我们点击进去看下 发现传入了两个参数&#xff0c;一个是filename&#xff0c;还有一个是filehash 看到里面的内容&#xff0c;提示我们真正的flag在 /flllllllllllla…

curl操作

下载路径&#xff1a;https://curl.se/windows/ 参考&#xff1a;https://blog.csdn.net/weixin_45191386/article/details/130652821 操作&#xff1a; curl http://localhost:8085/api/v1/aaa/bbbb/?ccc 652781344055627776

docker在arm64架构ubuntu系统的安装

卸载可能存在的旧版本 sudo apt remove docker docker-engine docker-ce docker-io安装依赖使apt可通过HTTPS下载包 sudo apt update && apt install -y apt-tranport-https ca-certificates curl software-properties-commonapt-transport-https用于支持通过HTTPS协…

能源监测系统:实时监控+数据可视化

能源监测系统是应用物联网技术&#xff0c;对水、电、气、热等能源进行实时监测的系统&#xff0c;能够对各种设备数据进行智能化标准化的管理&#xff0c;从而建立起统一的管理优化平台&#xff0c;是积极响应国家节能降耗政策的典型模范&#xff0c;也是企业建设节能型工厂的…

自动化测试工具比传统测试工具的优势体现在哪里?

随着软件行业的快速发展和扩张&#xff0c;自动化测试工具在提高测试效率和质量方面起到了不可或缺的作用&#xff0c;那你知道自动化测试工具比传统测试工具的优势体现在哪里吗&#xff1f; 首先&#xff0c;自动化测试工具能够大大缩短测试周期。相比于传统手动测试&#xff…