理解 Nodejs 中的 MVC 模式

2025-05-24

理解 Nodejs 中的 MVC 模式

这是使用 Nodejs、Express、Mongoose 和 Jest 进行测试驱动开发的第二部分。在第一部分中,我们搭建了开发环境并运行了第一个测试。在本教程中,我们将重点介绍如何使用 MVC 架构构建端点。

术语定义

MVC——模型视图控制器

模型视图控制器是一种软件架构模式,它将应用程序逻辑分为三个相互关联的元素:模型、视图和控制器。

Restful API

REST 是“表述性状态转移”的缩写,而 API 是“应用程序接口”的缩写。RESTful API 是一种使用 HTTP 请求访问和使用数据的应用程序接口 (API) 的架构风格。

我猜你对本教程涉及的术语应该很熟悉。我们开始吧。

在上一篇教程中,我们创建了一个非常基本的文件夹结构,其中包含一些依赖项。现在,让我们安装 API 开发所需的依赖项。



$ npm i --save-dev body-parser dotenv nodemon


Enter fullscreen mode Exit fullscreen mode

安装后,您的 package.json 文件应如下所示。



{
  "name": "tdd-with-nodejs",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "jest",
    "start": "nodemon index.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "body-parser": "^1.19.0",
    "dotenv": "^8.2.0",
    "express": "^4.17.1",
    "jest": "^26.6.3",
    "mongoose": "^5.11.9",
    "nodemon": "^2.0.6"
  }
}



Enter fullscreen mode Exit fullscreen mode

您注意到,我们已将初始化脚本配置为使用 nodemon 运行,nodemon 将跟踪对 index.js 文件所做的每个更改,并相应地刷新我们的应用程序。接下来,让我们设置一个服务器。在应用程序的根目录中创建一个名为 index.js 的新文件,并粘贴以下代码。



require('dotenv').config();
const mongoose =  require("mongoose");
//const articles = require("./routes/article.routes");
const bodyParser =  require("body-parser");

const app = exepress();
const port = 8000;

mongoose.connect(process.env.mongoURI, {useNewUrlParser: true, useCreateIndex: true, useUnifiedTopology: true })
.then(res => console.log(`Connection Succesful ${res}`))
.catch(err => console.log(`Error in DB connection ${err}`));

//body-parser config;
app.use(exepress.json());
app.use(bodyParser.urlencoded({extended: true }));
app.use(bodyParser.json());

app.get("/", (req, res) => {
    res.send(`<h1>Hello!</h1>`)
});

app.listen(port, () => {
    console.log(`Application is listening at port ${port}`);
});

//register the enpoints
//app.use("/api/v1/articles", articles);



Enter fullscreen mode Exit fullscreen mode

不要忘记创建一个.env文件并添加数据库 URI,如下所示:mongoURI=mongodb+srv://your-db-uri。接下来,在终端上输入以下命令来启动应用程序。



$ npm run start


Enter fullscreen mode Exit fullscreen mode

你的终端应该会收到如下响应:应用程序正在监听 8000 端口&连接成功 [object Object]。如果你打开http://localhost:8000 ,屏幕上应该也会显示“Hello!” 。

本教程旨在教您如何正确构建Nodjs应用程序以适应 MVC 模式,因此,我们将业务逻辑与控制器和路由文件分离。我们将在本系列的最后一篇教程“分层结构”教程中详细学习这一点。

构建模型(Article.js)

接下来,让我们创建模型。在项目根目录中创建一个新文件夹,导航到该文件夹​​,创建一个名为Article.js的新文件,然后复制粘贴以下代码以创建 API 的模型。



const mongoose = require("mongoose");
const Schema = mongoose.Schema;


const articleSchema = Schema({

    title:{
        type: String,
        required: true,
    },

    body:{
        type: String,
        required: true,
    },

    article_image: {
        type: String,
        required: false,
    },

    date:{
        type: Date,
        default: Date.now(),
    }

});


module.exports = Article = mongoose.model("Article", articleSchema);


Enter fullscreen mode Exit fullscreen mode

我们的模型非常基础,它包含一个titlebody一个 date对象。您可以阅读此处的官方文档,了解更多关于使用 Mongoose 构建MongoDB Schemas 的信息。

构建文章服务(ArticleService.js)

要构建ArticleService.js,您需要创建一个名为 services 的文件夹来存放我们的ArticleService.js文件。将以下代码复制粘贴到您的ArticleService.js 文件中。



const Article = require("../models/Article");

module.exports = class ArticleService{
    static async getAllArticles(){
        try {
            const allArticles = await  Article.find();
            return allArticles;
        } catch (error) {
            console.log(`Could not fetch articles ${error}`)
        }
    }

    static async createArticle(data){
        try {

            const newArticle = {
                title: data.title,
                body: data.body,
                article_image: data.article_image
            }
           const response = await new Article(newArticle).save();
           return response;
        } catch (error) {
            console.log(error);
        } 

    }
    static async getArticlebyId(articleId){
        try {
            const singleArticleResponse =  await Article.findById({_id: articleId});
            return singleArticleResponse;
        } catch (error) {
            console.log(`Article not found. ${error}`)
        }
    }

    static async updateArticle(title, body, articleImage){
            try {
                const updateResponse =  await Article.updateOne(
                    {title, body, articleImage}, 
                    {$set: {date: new Date.now()}});

                    return updateResponse;
            } catch (error) {
                console.log(`Could not update Article ${error}` );

        }
    }

    static async deleteArticle(articleId){
        try {
            const deletedResponse = await Article.findOneAndDelete(articleId);
            return deletedResponse;
        } catch (error) {
            console.log(`Could  ot delete article ${error}`);
        }

    }
}


Enter fullscreen mode Exit fullscreen mode

构建控制器(article.controller.js)

接下来,让我们开始编写 API 端点,在根目录中创建一个名为controllers的新文件夹,导航到该文件夹​​,然后创建一个名为article.controller.js的新文件。复制粘贴以下代码。



const ArticleService = require("../services/ArticleService");

module.exports = class Article{

   static async apiGetAllArticles(req, res, next){
       try {
         const articles = await ArticleService.getAllArticles();
         if(!articles){
            res.status(404).json("There are no article published yet!")
         }
         res.json(articles);
       } catch (error) {
          res.status(500).json({error: error})
       }

   }

   static async apiGetArticleById(req, res, next){
      try {
         let id = req.params.id || {};
         const article = await ArticleService.getArticlebyId(id);
         res.json(article);
      } catch (error) {
         res.status(500).json({error: error})
      }
   }

   static async apiCreateArticle(req, res, next){
      try {
         const createdArticle =  await ArticleService.createArticle(req.body);
         res.json(createdArticle);
      } catch (error) {
         res.status(500).json({error: error});
      }
   }

   static async apiUpdateArticle(req, res, next){
      try {
         const comment = {}
         comment.title        = req.body.title;
         comment.body         = req.body.body;
         comment.articleImage = req.body.article_image

         const updatedArticle = await ArticleService.updateArticle(comment);

         if(updatedArticle.modifiedCount === 0){
            throw new Error("Unable to update article, error occord");
         }

         res.json(updatedArticle);

      } catch (error) {
         res.status(500).json({error: error});
      }
   }

   static async apiDeleteArticle(req, res, next){
         try {
            const articleId = req.params.id;
            const deleteResponse =  await ArticleService.deleteArticle(articleId)
            res.json(deleteResponse);
         } catch (error) {
            res.status(500).json({error: error})
         }
   }

}



Enter fullscreen mode Exit fullscreen mode

构建路线(article.routes.js)

为了与我们的端点通信,我们需要设置相应的路由和请求。创建一个名为routes的新文件夹,并在其中创建一个名为article.routes.js的新文件。您可以随意命名文件夹,但最好保持目录和文件名有意义。



const  express =  require("express");
const router = express.Router();
const ArticleCtrl = require("../controllers/article.controller");


router.get("/", ArticleCtrl.apiGetAllArticles);
router.post("/", ArticleCtrl.apiCreateArticle);
router.get("/article/:id", ArticleCtrl.apiGetArticleById);
router.put("/article/:id", ArticleCtrl.apiUpdateArticle);
router.delete("/article/:id", ArticleCtrl.apiDeleteArticle);

module.exports =  router;


Enter fullscreen mode Exit fullscreen mode

如果您已经按照本教程进行了到目前为止的操作,那么您的文件夹结构实际上应该像下面的代码片段一样。



├── tdd-with-nodejs
├── controllers
├── article.controller.js
├── models
├── Article.js
├── routes
├── article.routes.js
├── services
├── articleService.js
├── test

Enter fullscreen mode Exit fullscreen mode




整合起来

使用 MVC 模式时,务必遵循关注点分离 (SoC) 技术。关注点分离 (SoC) 是一种设计原则,用于将软件应用程序划分为不同的部分,以便每个部分分别处理一个关注点。关注点是一组影响软件应用程序代码的信息。我们将在下一篇教程(也是本系列的最后一篇)中深入探讨这个主题。

在结束之前,让我们先测试一下其中一个端点。使用您选择的 API 测试工具向/api/v1/articles端点发送一个POST请求。在我的例子中,我们使用了Postman。您应该会收到一个响应对象,作为您新创建的文章的响应,类似于下面的代码片段。

截图 2021-01-06 18.25.03.png

本教程到此结束。恭喜你完成了本系列的学习。下篇教程再见。

文章来源:https://dev.to/eetukudo_/understanding-mvc-pattern-in-nodejs-2bdn
PREV
不要只为自己开发——开发人员无障碍检查清单
NEXT
哪些软件技术能为您带来最高薪资?我应该先学哪种编程语言?接下来应该学哪种编程语言?前端开发人员:学完 JavaScript 之后我应该学什么?探索这些框架和库 提升您的技能 找到适合您的数据库管理系统 云端开发 移动操作系统:Android 和 iOS 结论 下一步是什么?