如何将MongoDB与您的节点应用程序集成

在使用Node.js的过程中,您可能会发现自己正在开发一个存储和查询数据的项目。本教程将向您展示如何将MongoDB与现有的Node应用程序集成。此过程将涉及将用户和数据库信息添加到应用程序代码并使用Object Document Mapper Mongoose。在本教程结束时,您将拥有一个可以接受用户输入并在浏览器中显示它的工作应用程序。

介绍

在使用Node.js时 ,您可能会发现自己正在开发一个存储和查询数据的项目。 在这种情况下,您需要选择对您的应用程序的数据和查询类型有意义的数据库解决方案。

在本教程中,您将MongoDB数据库与现有Node应用程序集成。 如果您的数据要求包括可伸缩性和灵活性,那么像MongoDB这样的NoSQL数据库会很有用。 MongoDB还与Node很好地集成,因为它被设计为与JSON对象异步工作。

要将MongoDB集成到项目中,您将使用Object Document Mapper (ODM) Mongoose为应用程序数据创建模式和模型。 这将允许您按照模型 - 视图 - 控制器 (MVC)体系结构模式组织应用程序代码,该模式允许您将应用程序处理用户输入的方式与数据结构和呈现方式的逻辑分开。 使用此模式可以通过在代码库中引入关注点分离来促进未来的测试和开发。

在本教程结束时,您将获得一个有效的鲨鱼信息应用程序,该应用程序将获取用户对其最喜欢的鲨鱼的输入并在浏览器中显示结果:

鲨鱼输出

先决条件

第1步 - 创建一个Mongo用户

在我们开始使用应用程序代码之前,我们将创建一个可以访问应用程序数据库的管理用户。 该用户将拥有任何数据库的管理权限,这将使您可以根据需要灵活地切换和创建新数据库。

首先,检查MongoDB是否在您的服务器上运行:

sudo systemctl status mongodb

以下输出表明MongoDB正在运行:

● mongodb.service - An object/document-oriented database
   Loaded: loaded (/lib/systemd/system/mongodb.service; enabled; vendor preset: enabled)
   Active: active (running) since Thu 2019-01-31 21:07:25 UTC; 21min ago
...

接下来,打开Mongo shell以创建您的用户:

mongo

这会让你进入一个管理shell:

MongoDB shell version v3.6.3
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.6.3
...
>

由于您对admin数据库的访问权限不受限制,因此在打开shell时会看到一些管理警告。 您可以通过阅读如何在Ubuntu 16.04上安装和保护MongoDB来了解有关限制此访问的更多信息,以便进入生产设置。

目前,您可以使用对admin数据库的访问权限来创建具有userAdminAnyDatabase权限的用户,这将允许对应用程序数据库进行密码保护访问。

在shell中,指定您要使用admin数据库来创建用户:

use admin

接下来,通过使用db.createUser命令添加用户名和密码来创建角色和密码。 键入此命令后,shell将在每行之前添加三个点,直到命令完成。 请务必使用您自己的用户名和密码替换此处提供的用户名和密码:

db.createUser(
  {
    user: "sammy",
    pwd: "your_password",
    roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
  }
)

这将在admin数据库中为用户sammy创建一个条目。 您选择的用户名和admin数据库将作为您的用户的标识符。

整个过程的输出将如下所示,包括指示条目成功的消息:

> db.createUser(
...  {
...    user: "sammy",
...    pwd: "your_password",
...    roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
...  }
...)
Successfully added user: {
        "user" : "sammy",
        "roles" : [
                {
                        "role" : "userAdminAnyDatabase",
                        "db" : "admin"
                }
        ]
}

创建用户和密码后,您现在可以退出Mongo shell:

exit

现在您已经创建了数据库用户,您可以继续克隆入门项目代码并添加Mongoose库,这将允许您为数据库中的集合实现模式和模型。

第2步 - 将Mongoose和数据库信息添加到项目中

我们接下来的步骤是克隆应用程序入门代码并将Mongoose和MongoDB数据库信息添加到项目中。

在非root用户的主目录中,从DigitalOcean Community GitHub帐户克隆nodejs-image-demo存储库 此存储库包含如何使用Docker构建Node.js应用程序中描述的设置中的代码。

将存储node_project到名为node_project的目录中:

git clone https://github.com/do-community/nodejs-image-demo.git node_project

切换到node_project目录:

cd  node_project

在修改项目代码之前,让我们使用tree命令查看项目的结构。

提示: tree是从命令行查看文件和目录结构的有用命令。 您可以使用以下命令安装它:

sudo apt install tree

要使用它,请cd到给定目录并键入tree 您还可以使用以下命令提供起点的路径:

tree /home/sammy/sammys-project

键入以下内容以查看node_project目录:

tree

当前项目的结构如下所示:

├── Dockerfile
├── README.md
├── app.js
├── package-lock.json
├── package.json
└── views
    ├── css
    │   └── styles.css
    ├── index.html
    └── sharks.html

在我们浏览教程时,我们将向该项目添加目录, tree将是一个有用的命令,可以帮助我们跟踪我们的进度。

接下来,使用npm install命令将npm install npm包添加到项目中:

npm install mongoose

此命令将使用项目的package.json文件中列出的依赖项在项目目录中创建node_modules目录,并将node_modules添加到该目录。 它还会为你的package.json文件中列出的依赖项添加mongoose 有关package.json的更详细讨论,请参阅如何使用Docker构建Node.js应用程序中的 第1步

在创建任何Mongoose模式或模型之前,我们将添加数据库连接信息,以便我们的应用程序能够连接到我们的数据库。

为了尽可能地分离应用程序的问题,请为数据库连接信息创建一个名为db.js的单独文件。 您可以使用nano或您喜欢的编辑器打开此文件:

nano db.js

首先,使用require函数导入mongoose 模块

〜/ node_project / db.js
const mongoose = require('mongoose');

这将使您可以访问Mongoose的内置方法,您将使用这些方法创建与数据库的连接。

接下来,添加以下常量以定义Mongo的连接URI的信息。 虽然用户名和密码是可选的,但我们会将它们包括在内,以便我们可以要求对数据库进行身份验证。 请务必使用您自己的信息替换下面列出的用户名和密码,如果您愿意,可以随时拨打' sharkinfo '以外的数据库:

〜/ node_project / db.js
const mongoose = require('mongoose');

const MONGO_USERNAME = 'sammy';
const MONGO_PASSWORD = 'your_password';
const MONGO_HOSTNAME = '127.0.0.1';
const MONGO_PORT = '27017';
const MONGO_DB = 'sharkinfo';

因为我们在本地运行数据库,所以我们使用127.0.0.1作为主机名。 这将在其他开发环境中发生变化:例如,如果您使用单独的数据库服务器或在容器化工作流程中使用多个节点。

最后,为URI定义一个常量,并使用mongoose.connect()方法创建连接:

〜/ node_project / db.js
...
const url = `mongodb://${MONGO_USERNAME}:${MONGO_PASSWORD}@${MONGO_HOSTNAME}:${MONGO_PORT}/${MONGO_DB}?authSource=admin`;

mongoose.connect(url, {useNewUrlParser: true});

请注意,在URI中,我们为用户指定了authSource作为admin数据库。 这是必要的,因为我们在连接字符串中指定了用户名。 使用useNewUrlParser mongoose.connect()useNewUrlParser标志指定我们要使用Mongo的新URL解析器

完成编辑后保存并关闭文件。

最后一步,将数据库连接信息添加到app.js文件中,以便应用程序可以使用它。 打开app.js

nano app.js

该文件的第一行将如下所示:

〜/ node_project / app.js
const express = require('express');
const app = express();
const router = express.Router();

const path = __dirname + '/views/';
...

router常量定义下方,位于文件顶部附近,添加以下行:

〜/ node_project / app.js
...
const router = express.Router();
const db = require('./db');

const path = __dirname + '/views/';
...

这告诉应用程序使用db.js指定的数据库连接信息。

完成编辑后保存并关闭文件。

有了您的数据库信息并将Mongoose添加到您的项目中,您就可以创建模式和模型来塑造sharks集合中的数据。

第3步 - 创建Mongoose模式和模型

我们的下一步将是考虑用户将在sharkinfo数据库中创建的sharks集合的结构及其输入。 我们希望这些创建的文档具有哪些结构? 我们当前应用程序的鲨鱼信息页面包含有关不同鲨鱼及其行为的一些细节:

鲨鱼信息页

为了与这个主题保持一致,我们可以让用户添加新的鲨鱼,其中包含有关其整体特征的详细信息。 这个目标将决定我们如何创建架构。

要使模式和模型与应用程序的其他部分不同,请在当前项目目录中创建models目录:

mkdir models

接下来,打开一个名为sharks.js的文件来创建模式和模型:

nano models/sharks.js

导入文件顶部的mongoose模块:

〜/ node_project /模型/ sharks.js
const mongoose = require('mongoose');

在此下方,定义一个Schema对象,用作shark架构的基础:

〜/ node_project /模型/ sharks.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;

您现在可以定义要包含在架构中的字段。 因为我们想要创建一个包含单个鲨鱼的集合以及有关其行为的信息,所以我们要包含一个name 和一个character键。 在常量定义下添加以下Shark模式:

〜/ node_project /模型/ sharks.js
...
const Shark = new Schema ({
        name: { type: String, required: true },
        character: { type: String, required: true },
});

此定义包括有关我们期望用户输入类型的信息 - 在本例中为字符串 - 以及是否需要该输入。

最后,使用Mongoose的model()函数创建Shark模型。 此模型将允许您查询集合中的文档并验证新文档。 在文件底部添加以下行:

〜/ node_project /模型/ sharks.js
...
module.exports = mongoose.model('Shark', Shark)

最后一module.exports我们的Shark模型可以作为模块使用module.exports属性 此属性定义模块将导出的值,使其可用于应用程序中的其他位置。

完成的models/sharks.js文件如下所示:

〜/ node_project /模型/ sharks.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const Shark = new Schema ({
        name: { type: String, required: true },
        character: { type: String, required: true },
});

module.exports = mongoose.model('Shark', Shark)

完成编辑后保存并关闭文件。

使用Shark架构和模型,您可以开始处理将确定应用程序如何处理用户输入的逻辑。

第4步 - 创建控制器

我们的下一步将是创建控制器组件,该组件将确定用户输入如何保存到我们的数据库并返回给用户。

首先,为控制器创建一个目录:

mkdir controllers

接下来,在名为sharks.js的文件夹中打开一个文件:

nano controllers/sharks.js

在文件的顶部,我们将使用我们的Shark模型导入模块,以便我们可以在控制器的逻辑中使用它。 我们还将导入path模块以访问实用程序,这些实用程序将允许我们设置用户将输入其鲨鱼的表单的路径。

将以下require函数添加到文件的开头:

〜/ node_project /控制器/ sharks.js
const path = require('path');
const Shark = require('../models/sharks');

接下来,我们将使用Node的exports快捷方式编写一系列函数,我们将使用控制器模块导出这些函数。 这些功能将包括与用户的鲨鱼数据相关的三个任务:

  • 向用户发送鲨鱼输入表单。
  • 创建一个新的鲨鱼条目。
  • 将鲨鱼显示给用户。

首先,创建一个index函数以显示带有输入表单的sharks页面。 在您的导入下方添加此功能:

〜/ node_project /控制器/ sharks.js
...
exports.index = function (req, res) {
    res.sendFile(path.resolve('views/sharks.html'));
};

接下来,在index函数下面,添加一个名为create函数,在sharks集合中create一个新的shark条目:

〜/ node_project /控制器/ sharks.js
...
exports.create = function (req, res) {
    var newShark = new Shark(req.body);
    console.log(req.body);
    newShark.save(function (err) {
            if(err) {
            res.status(400).send('Unable to save shark to database');
        } else {
            res.redirect('/sharks/getshark');
        }
  });
               };

当用户将shark数据发布到sharks.html页面上的表单时,将调用此函数。 当我们创建应用程序的路由时,我们将在本教程后面的这个POST端点创建路径。 使用POST请求的body ,我们的create函数将使用我们导入的Shark模型create一个新的shark文档对象,这里称为newShark 我们添加了一个console.log方法来将shark条目输出到控制台,以检查我们的POST方法是否按预期工作,但如果您愿意,可以随意省略。

使用newShark对象, create函数将调用Mongoose的model.save()方法 ,使用您在Shark模型中定义的键创建新的shark文档。 回调函数遵循标准节点回调模式callback(error, results) 如果出现错误,我们会向用户发送报告错误的消息,如果成功,我们将使用res.redirect()方法将用户发送到端点,该端点将其鲨鱼信息呈现给他们在浏览器中。

最后, list函数将把集合的内容显示给用户。 create function下面添加以下代码:

〜/ node_project /控制器/ sharks.js
...
exports.list = function (req, res) {
        Shark.find({}).exec(function (err, sharks) {
                if (err) {
                        return res.send(500, err);
                }
                res.render('getshark', {
                        sharks: sharks
             });
        });
};

此函数使用Shark模型和Mongoose的model.find()方法返回已输入到sharks集合中的sharks 它通过使用Mongoose的exec()函数返回查询对象(在本例中为sharks集合中的所有条目)作为承诺来实现此目的。 如果出现错误,回调函数将发送500错误。

带有sharks集合的返回查询对象将在getshark页面中呈现,我们将使用EJS模板语言在下一步中创建该页面。

完成的文件如下所示:

〜/ node_project /控制器/ sharks.js
const path = require('path');
const Shark = require('../models/sharks');

exports.index = function (req, res) {
    res.sendFile(path.resolve('views/sharks.html'));
};

exports.create = function (req, res) {
    var newShark = new Shark(req.body);
    console.log(req.body);
    newShark.save(function (err) {
            if(err) {
            res.status(400).send('Unable to save shark to database');
        } else {
            res.redirect('/sharks/getshark');
        }
  });
               };

exports.list = function (req, res) {
        Shark.find({}).exec(function (err, sharks) {
                if (err) {
                        return res.send(500, err);
                }
                res.render('getshark', {
                        sharks: sharks
             });
        });
};

请记住,尽管我们在这里没有使用箭头函数 ,但您可能希望在自己的开发过程中迭代此代码时包含它们。

完成编辑后保存并关闭文件。

在继续下一步之前,您可以再次从node_project目录运行tree以查看项目的结构。 这一次,为了简洁起见,我们将告诉tree使用-I选项省略node_modules目录:

tree -I node_modules

通过添加,您的项目结构将如下所示:

├── Dockerfile
├── README.md
├── app.js
├── controllers
│   └── sharks.js
├── db.js
├── models
│   └── sharks.js
├── package-lock.json
├── package.json
└── views
    ├── css
    │   └── styles.css
    ├── index.html
    └── sharks.html

既然您有一个控制器组件来指导用户输入如何保存并返回给用户,您可以继续创建将实现控制器逻辑的视图。

第5步 - 使用EJS和Express中间件收集和呈现数据

为了使我们的应用程序能够处理用户数据,我们将做两件事:首先,我们将包含一个内置的Express中间件函数urlencoded() ,它将使我们的应用程序能够解析用户输入的数据。 其次,我们将向视图添加模板标记,以便在代码中实现与用户数据的动态交互。

要使用Express的urlencoded()函数,首先打开app.js文件:

nano app.js

express.static()函数上方,添加以下行:

〜/ node_project / app.js
...
app.use(express.urlencoded({ extended: true }));
app.use(express.static(path));
...

添加此功能将允许从我们的鲨鱼信息表单中访问已解析的POST数据。 我们使用extended选项指定true ,以便为应用程序将解析的数据类型(包括嵌套对象等)提供更大的灵活性。 有关选项的更多信息,请参阅功能文档

完成编辑后保存并关闭文件。

接下来,我们将向视图添加模板功能。 首先,使用npm install ejs

npm install ejs

接下来,打开sharks.html文件夹中的sharks.html文件:

nano views/sharks.html

在第3步中,我们查看了此页面以确定我们应该如何编写Mongoose模式和模型:

鲨鱼信息页

现在,我们将介绍第三列,其中包含一个表单,用户可以输入有关鲨鱼的信息,而不是采用两列布局

首先,将现有列的尺寸更改为4以创建三个大小相等的列。 请注意,您需要在当前读取的两行上进行此更改<div class="col-lg-6"> 这些都将成为<div class="col-lg- 4 ">

〜/ node_project /视图/ sharks.html
...
<div class="container">
    <div class="row">
        <div class="col-lg-4">
            <p>
                <div class="caption">Some sharks are known to be dangerous to humans, though many more are not. The sawshark, for example, is not considered a threat to humans.
                </div>
                <img src="https://www.howtoing.com/wp-content/uploads/articles/docker_node_image/sawshark.jpg" alt="Sawshark">
            </p>
        </div>
        <div class="col-lg-4">
            <p>
                <div class="caption">Other sharks are known to be friendly and welcoming!</div>
                <img src="https://www.howtoing.com/wp-content/uploads/articles/docker_node_image/sammy.png" alt="Sammy the Shark">
            </p>
        </div>
    </div>
  </div>

 </html> 

有关Bootstrap网格系统的介绍,包括其行和列布局,请参阅Bootstrap的这个介绍

接下来,添加包含POST请求的命名端点的另一列,其中包含用户的shark数据和将捕获该数据的EJS模板标记。 此列将位于前一列的结束</p></div>标记之下,以及行,容器和HTML文档的结束标记之上。 这些结束标记已经存在于您的代码中; 它们也在下面标有评论。 在添加以下代码以创建新列时将它们保留在原位:

〜/ node_project /视图/ sharks.html
...
       </p> <!-- closing p from previous column -->
   </div> <!-- closing div from previous column -->
<div class="col-lg-4">
            <p>
                <form action="/sharks/addshark" method="post">
                    <div class="caption">Enter Your Shark</div>
                    <input type="text" placeholder="Shark Name" name="name" <%=sharks[i].name; %>
                    <input type="text" placeholder="Shark Character" name="character" <%=sharks[i].character; %>
                    <button type="submit">Submit</button>
                </form>
            </p>
        </div> 
    </div> <!-- closing div for row -->
</div> <!-- closing div for container -->

</html> <!-- closing html tag -->

form标记中,您要为用户的鲨鱼数据添加"/sharks/addshark"端点,并指定要提交它的POST方法。 在输入字段中,您指定"Shark Name""Shark Character"字段,与您之前定义的Shark模型对齐。

要将用户输入添加到sharks集合,您将使用EJS模板标记( <%=%> )以及JavaScript语法将用户的条目映射到新创建的文档中的相应字段。 有关JavaScript对象的更多信息,请参阅有关了解JavaScript对象的文章。 有关EJS模板标签的更多信息,请参阅EJS文档

包含所有三列的整个容器(包括带有鲨鱼输入形式的列)在完成时将如下所示:

〜/ node_project /视图/ sharks.html
...
<div class="container">
    <div class="row">
        <div class="col-lg-4">
            <p>
                <div class="caption">Some sharks are known to be dangerous to humans, though many more are not. The sawshark, for example, is not considered a threat to humans.
                </div>
                <img src="https://www.howtoing.com/wp-content/uploads/articles/docker_node_image/sawshark.jpg" alt="Sawshark">
            </p>
        </div>
        <div class="col-lg-4">
            <p>
                <div class="caption">Other sharks are known to be friendly and welcoming!</div>
                <img src="https://www.howtoing.com/wp-content/uploads/articles/docker_node_image/sammy.png" alt="Sammy the Shark">
            </p>
        </div>
    <div class="col-lg-4">
            <p>
                <form action="/sharks/addshark" method="post">
                    <div class="caption">Enter Your Shark</div>
                    <input type="text" placeholder="Shark Name" name="name" <%=sharks[i].name; %>
                    <input type="text" placeholder="Shark Character" name="character" <%=sharks[i].character; %>
                    <button type="submit">Submit</button>
                </form>
            </p>
        </div>
    </div>
  </div>

</html>

完成编辑后保存并关闭文件。

既然您有办法收集用户的输入,您可以创建一个端点来显示返回的鲨鱼及其相关的角色信息。

将新修改的sharks.html文件复制到名为getshark.html的文件中:

cp views/sharks.html views/getshark.html

打开getshark.html

nano views/getshark.html

在文件中,我们将修改用于创建鲨鱼输入表单的列,方法是将其替换为将在我们的sharks集合中显示鲨鱼的列。 同样,您的代码将介于前一列的现有</p></div>标记以及行,容器和HTML文档的结束标记之间。 在添加以下代码以创建列时,请记住保留这些标记:

〜/ node_project /视图/ getshark.html
...
       </p> <!-- closing p from previous column -->
   </div> <!-- closing div from previous column -->
<div class="col-lg-4">
           <p>
              <div class="caption">Your Sharks</div>
                  <ul>
                     <% sharks.forEach(function(shark) { %>
                        <p>Name: <%= shark.name %></p>
                        <p>Character: <%= shark.character %></p>
                     <% }); %>
                  </ul>
            </p>
        </div>
    </div> <!-- closing div for row -->
</div> <!-- closing div for container -->

</html> <!-- closing html tag -->

在这里,您使用EJS模板标签和forEach()方法输出sharks集合中的每个值,包括有关最近添加的鲨鱼的信息。

包含所有三列的整个容器(包括带有sharks集合的列)在完成后将如下所示:

〜/ node_project /视图/ getshark.html
...
<div class="container">
    <div class="row">
        <div class="col-lg-4">
            <p>
                <div class="caption">Some sharks are known to be dangerous to humans, though many more are not. The sawshark, for example, is not considered a threat to humans.
                </div>
                <img src="https://www.howtoing.com/wp-content/uploads/articles/docker_node_image/sawshark.jpg" alt="Sawshark">
            </p>
        </div>
        <div class="col-lg-4">
            <p>
                <div class="caption">Other sharks are known to be friendly and welcoming!</div>
                <img src="https://www.howtoing.com/wp-content/uploads/articles/docker_node_image/sammy.png" alt="Sammy the Shark">
            </p>
        </div>
    <div class="col-lg-4">
            <p>
              <div class="caption">Your Sharks</div>
                  <ul>
                     <% sharks.forEach(function(shark) { %>
                        <p>Name: <%= shark.name %></p>
                        <p>Character: <%= shark.character %></p>
                     <% }); %>
                  </ul>
            </p>
        </div>
    </div>
  </div>

</html>

完成编辑后保存并关闭文件。

为了让应用程序使用您创建的模板,您需要在app.js文件中添加几行。 再次打开它:

nano app.js

在您添加express.urlencoded()函数的位置上方,添加以下行:

〜/ node_project / app.js
...
app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
app.use(express.urlencoded({ extended: true }));
app.use(express.static(path));

...

app.engine方法告诉应用程序将EJS模板引擎映射到HTML文件,而app.set定义默认视图引擎。

您的app.js文件现在应该如下所示:

〜/ node_project / app.js
const express = require('express');
const app = express();
const router = express.Router();
const db = require('./db');

const path = __dirname + '/views/';
const port = 8080;

router.use(function (req,res,next) {
  console.log('/' + req.method);
  next();
});

router.get('/',function(req,res){
  res.sendFile(path + 'index.html');
});

router.get('/sharks',function(req,res){
  res.sendFile(path + 'sharks.html');
});

app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
app.use(express.urlencoded({ extended: true }));
app.use(express.static(path));
app.use('/', router);

app.listen(port, function () {
  console.log('Example app listening on port 8080!')
})

现在您已经创建了可以与用户数据动态协同工作的视图,现在是时候创建项目的路由以将视图和控制器逻辑结合在一起。

第6步 - 创建路由

将应用程序组件组合在一起的最后一步是创建路由。 我们将按功能分离我们的路线,包括到我们的应用程序的登陆页面的路线和到我们的鲨鱼页面的另一条路线。 我们的sharks路线将我们将控制器的逻辑与我们在上一步中创建的视图集成在一起。

首先,创建一个routes目录:

mkdir routes

接下来,在此目录中打开一个名为index.js的文件:

nano routes/index.js

该文件将首先导入expressrouterpath对象,允许我们使用router对象定义要导出的router ,并使其可以与文件路径一起动态工作。 在文件顶部添加以下代码:

〜/ node_project /路线/ index.js
const express = require('express');
const router = express.Router();
const path = require('path');

接下来,添加以下router.use函数,该函数加载一个中间件函数,该函数将记录路由器的请求并将它们传递给应用程序的路由:

〜/ node_project /路线/ index.js
...

router.use (function (req,res,next) {
  console.log('/' + req.method);
  next();
});

对我们的应用程序根目录的请求将首先在此处引导,并且从这里用户将被引导到我们的应用程序的登录页面,我们将在下一步定义该路线。 router.use函数下面添加以下代码以定义到登录页面的路由:

〜/ node_project /路线/ index.js
...

router.get('/',function(req,res){
  res.sendFile(path.resolve('views/index.html'));
});

当用户访问我们的应用程序时,我们要发送它们的第一个地方是我们在views目录中的index.html登录页面。

最后,要使这些路由可以作为应用程序中其他位置的可导入模块进行访问,请在文件末尾添加一个闭合表达式以导出router对象:

〜/ node_project /路线/ index.js
...

module.exports = router;

完成的文件如下所示:

〜/ node_project /路线/ index.js
const express = require('express');
const router = express.Router();
const path = require('path');

router.use (function (req,res,next) {
  console.log('/' + req.method);
  next();
});

router.get('/',function(req,res){
  res.sendFile(path.resolve('views/index.html'));
});

module.exports = router;

完成编辑后,保存并关闭此文件。

接下来,打开一个名为sharks.js的文件来定义应用程序应该如何使用我们创建的不同端点和视图来处理用户的鲨鱼输入:

nano routes/sharks.js

在文件的顶部,导入expressrouter对象:

〜/ node_project /路线/ sharks.js
const express = require('express');
const router = express.Router();

接下来,导入一个名为shark的模块,该模块允许您使用您使用控制器定义的导出函数:

〜/ node_project /路线/ sharks.js
const express = require('express');
const router = express.Router();
const shark = require('../controllers/sharks');

现在,您可以使用在sharks控制器文件中定义的indexcreatelist函数创建路径。 每条路线都将与相应的HTTP方法相关联:在呈现主鲨鱼信息登陆页面并将鲨鱼列表返回给用户的情况下获取GET,在创建新鲨鱼条目的情况下返回POST:

〜/ node_project /路线/ sharks.js
...

router.get('/', function(req, res){
    shark.index(req,res);
});

router.post('/addshark', function(req, res) {
    shark.create(req,res);
});

router.get('/getshark', function(req, res) {
    shark.list(req,res);
});

每个路由都使用controllers/sharks.js中的相关函数,因为我们通过在该文件的顶部导入该模块来使其可访问。

最后,通过将这些路由附加到router对象并导出它们来关闭文件:

〜/ node_project /路线/ index.js
...

module.exports = router;

完成的文件如下所示:

〜/ node_project /路线/ sharks.js
const express = require('express');
const router = express.Router();
const shark = require('../controllers/sharks');

router.get('/', function(req, res){
    shark.index(req,res);
});

router.post('/addshark', function(req, res) {
    shark.create(req,res);
});

router.get('/getshark', function(req, res) {
    shark.list(req,res);
});

module.exports = router;

完成编辑后保存并关闭文件。

使应用程序可以访问这些路径的最后一步是将它们添加到app.js 再次打开该文件:

nano app.js

db常量下面,为您的路由添加以下导入:

〜/ node_project / app.js
...
const db = require('./db');
const sharks = require('./routes/sharks');

接下来, 当前安装router对象的app.use函数替换为以下行,该行将安装sharks路由器模块:

〜/ node_project / app.js
...
app.use(express.static(path));
app.use('/sharks', sharks);

app.listen(port, function () {
        console.log("Example app listening on port 8080!")
})

您现在可以删除先前在此文件中定义的路由,因为您使用sharks路由器模块导入应用程序的路由。

app.js文件的最终版本如下所示:

〜/ node_project / app.js
const express = require('express');
const app = express();
const router = express.Router();
const db = require('./db');
const sharks = require('./routes/sharks');

const path = __dirname + '/views/';
const port = 8080;

app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
app.use(express.urlencoded({ extended: true }));
app.use(express.static(path));
app.use('/sharks', sharks);

app.listen(port, function () {
  console.log('Example app listening on port 8080!')
})

完成编辑后保存并关闭文件。

您现在可以再次运行tree以查看项目的最终结构:

tree -I node_modules

您的项目结构现在看起来像这样:

├── Dockerfile
├── README.md
├── app.js
├── controllers
│   └── sharks.js
├── db.js
├── models
│   └── sharks.js
├── package-lock.json
├── package.json
├── routes
│   ├── index.js
│   └── sharks.js
└── views
    ├── css
    │   └── styles.css
    ├── getshark.html
    ├── index.html
    └── sharks.html

创建并准备好所有应用程序组件后,您就可以在数据库中添加测试鲨鱼!

If you followed the initial server setup tutorial in the prerequisites, you will need to modify your firewall, since it currently only allows SSH traffic. To permit traffic to port 8080 run:

sudo ufw allow 8080

Start the application:

node app.js

Next, navigate your browser to http:// your_server_ip :8080 . You will see the following landing page:

Application Landing Page

Click on the Get Shark Info button. You will see the following information page, with the shark input form added:

Shark Info Form

In the form, add a shark of your choosing. For the purpose of this demonstration, we will add Megalodon Shark to the Shark Name field, and Ancient to the Shark Character field:

Filled Shark Form

Click on the Submit button. You will see a page with this shark information displayed back to you:

Shark Output

You will also see output in your console indicating that the shark has been added to your collection:

Example app listening on port 8080!
{ name: 'Megalodon Shark', character: 'Ancient' }

If you would like to create a new shark entry, head back to the Sharks page and repeat the process of adding a shark.

You now have a working shark information application that allows users to add information about their favorite sharks.

结论

In this tutorial, you built out a Node application by integrating a MongoDB database and rewriting the application's logic using the MVC architectural pattern. This application can act as a good starting point for a fully-fledged CRUD application.

For more resources on the MVC pattern in other contexts, please see our Django Development series or How To Build a Modern Web Application to Manage Customer Information with Django and React on Ubuntu 18.04 .

For more information on working with MongoDB, please see our library of tutorials on MongoDB .