介绍
当您使用 Node.js时,您可能会发现自己正在开发一个存储和查询数据的项目,在这种情况下,您需要选择一个对应用程序的数据和查询类型有意义的数据库解决方案。
在本教程中,您将与现有 Node 应用程序集成一个 MongoDB数据库。 NoSQL 数据库如 MongoDB,如果您的数据要求包括可扩展性和灵活性,则有用。
为了将 MongoDB 集成到您的项目中,您将使用 Object Document Mapper (ODM) Mongoose来创建应用程序数据的方案和模型,这将允许您按照 model-view-controller (MVC)]架构模式来组织应用程序代码,这将允许您将应用程序如何处理用户输入的逻辑与您的数据如何结构和向用户渲染分开。
在教程结束时,您将有一个工作鲨鱼信息应用程序,该应用程序将收集用户关于他们最喜欢的鲨鱼的输入,并在浏览器中显示结果:
前提条件
- 运行 Ubuntu 18.04 的本地开发机器或服务器,以及具有
sudo
特权和活跃防火墙的非根用户。 有关如何在 18.04 服务器上设置这些功能的说明,请参阅本 初始服务器设置指南。 - Node.js 和 npm 安装在您的计算机或服务器上,遵循 这些关于使用 NodeSource 管理的 PPA 安装的说明。
- MongoDB 安装在您的计算机或服务器上,遵循 如何在 Ubuntu 18.04 中安装 MongoDB 的第一步。
步骤 1 – 创建一个Mongo用户
在我们开始使用应用程序代码之前,我们将创建一个管理用户,该用户将在任何数据库上拥有管理权限,这将为您提供在需要时切换和创建新数据库的灵活性。
首先,请检查 MongoDB 是否在您的服务器上运行:
1sudo systemctl status mongodb
以下输出表示 MongoDB 正在运行:
1[secondary_label Output]
2● mongodb.service - An object/document-oriented database
3 Loaded: loaded (/lib/systemd/system/mongodb.service; enabled; vendor preset: enabled)
4 Active: active (running) since Thu 2019-01-31 21:07:25 UTC; 21min ago
5...
接下来,打开Mongo壳来创建您的用户:
1mongo
这会让你陷入一个行政壳:
1[secondary_label Output]
2MongoDB shell version v3.6.3
3connecting to: mongodb://127.0.0.1:27017
4MongoDB server version: 3.6.3
5...
6>
您将看到一些管理警告,当您打开壳,因为您无限制访问admin
数据库. 您可以了解有关限制这种访问的更多信息,阅读如何在Ubuntu 16.04上安装和保护MongoDB(https://andsky.com/tech/tutorials/how-to-install-and-secure-mongodb-on-ubuntu-16-04),当您进入生产设置。
目前,您可以使用访问admin
数据库来创建具有userAdminAnyDatabase
(https://docs.mongodb.com/manual/reference/built-in-roles/#userAdminAnyDatabase)特权的用户,这将允许密码保护的访问您的应用程序的数据库。
在壳中,指定您想要使用admin
数据库来创建您的用户:
1use admin
接下来,通过使用db.createUser
命令添加用户名和密码来创建角色和密码. 输入此命令后,壳将在每个行前预留三个点,直到命令完成。
1db.createUser(
2 {
3 user: "sammy",
4 pwd: "your_password",
5 roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
6 }
7)
这将为用户创建一个admin
数据库中的sammy
条目,您选择的用户名和admin
数据库将作为您的用户的标识符。
整个过程的输出将如下,包括说明输入成功的消息:
1[secondary_label Output]
2> db.createUser(
3... {
4... user: "sammy",
5... pwd: "your_password",
6... roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
7... }
8...)
9Successfully added user: {
10 "user" : "sammy",
11 "roles" : [
12 {
13 "role" : "userAdminAnyDatabase",
14 "db" : "admin"
15 }
16 ]
17}
通过创建您的用户和密码,您现在可以退出Mongo壳:
1exit
现在您已经创建了数据库用户,您可以继续克隆启动项目代码并添加 Mongoose 库,这将允许您在数据库中实现集合的方案和模型。
步骤 2 — 将 Mongoose 和数据库信息添加到项目
我们的下一步将是克隆应用程序启动代码,并将Mongoose和我们的MongoDB数据库信息添加到项目中。
在您的非根用户的主目录中,从 DigitalOcean Community GitHub 帐户克隆 nodejs-image-demo
存储。
将存储库克隆成名为node_project
的目录:
1git clone https://github.com/do-community/nodejs-image-demo.git node_project
转到node_project
目录:
1cd node_project
在修改项目代码之前,让我们使用树
命令来看看项目的结构。
<$>[注]
** 提示:** tree
是一个用于从命令行查看文件和目录结构的有用命令。
1sudo apt install tree
要使用它,将cd
输入给定的目录,然后键入树
。你还可以通过一个命令提供到起点的路径,如:
1tree /home/sammy/sammys-project
美元
输入以下内容以查看node_project
目录:
1tree
当前项目的结构如下:
1[secondary_label Output]
2├── Dockerfile
3├── README.md
4├── app.js
5├── package-lock.json
6├── package.json
7└── views
8 ├── css
9 │ └── styles.css
10 ├── index.html
11 └── sharks.html
当我们通过教程时,我们将添加目录,树
将是一个有用的命令,帮助我们跟踪我们的进展。
接下来,用npm install
命令将mongoose
npm 包添加到项目中:
1npm install mongoose
此命令将创建一个node_modules
目录在您的项目目录中,使用项目的package.json
文件中列出的依赖,并将mongoose
添加到该目录中,并将mongoose
添加到package.json
文件中列出的依赖。
在创建任何 Mongoose 方案或模型之前,我们将添加我们的数据库连接信息,以便我们的应用能够连接到我们的数据库。
为了尽可能地分离您的应用程序的问题,为您的数据库连接信息创建一个单独的文件,名为db.js
。
1nano db.js
首先,使用要求
函数导入mongoose
模块:
1[label ~/node_project/db.js]
2const mongoose = require('mongoose');
这将为您提供访问Mongoose的内置方法,您将使用这些方法创建与您的数据库的连接。
接下来,添加以下 常数来定义 Mongo 的连接 URI 的信息. 虽然用户名和密码是可选的,但我们将包括它们,以便我们可以要求对我们的数据库进行身份验证。
1[label ~/node_project/db.js]
2const mongoose = require('mongoose');
3
4const MONGO_USERNAME = 'sammy';
5const MONGO_PASSWORD = 'your_password';
6const MONGO_HOSTNAME = '127.0.0.1';
7const MONGO_PORT = '27017';
8const MONGO_DB = 'sharkinfo';
由于我们在本地运行我们的数据库,所以我们使用了127.0.0.1
作为主机名称,这在其他开发环境中会发生变化:例如,如果您正在使用单独的数据库服务器或在集装箱工作流中使用多个节点。
最后,为 URI 定义一个常数,并使用 mongoose.connect()
方法创建连接:
1[label ~/node_project/db.js]
2...
3const url = `mongodb://${MONGO_USERNAME}:${MONGO_PASSWORD}@${MONGO_HOSTNAME}:${MONGO_PORT}/${MONGO_DB}?authSource=admin`;
4
5mongoose.connect(url, {useNewUrlParser: true});
请注意,在 URI 中,我们已将我们的用户的authSource
指定为admin
数据库,这是必要的,因为我们已经在我们的连接字符串中指定了用户名。
保存并关闭文件,当你完成编辑。
作为最后一步,将数据库连接信息添加到app.js
文件中,以便应用程序可以使用它。
1nano app.js
文件的第一行将看起来像这样:
1[label ~/node_project/app.js]
2const express = require('express');
3const app = express();
4const router = express.Router();
5
6const path = __dirname + '/views/';
7...
在位于文件顶部附近的路由器
常数定义下方,添加以下行:
1[label ~/node_project/app.js]
2...
3const router = express.Router();
4const db = require('./db');
5
6const path = __dirname + '/views/';
7...
这告诉应用程序使用db.js
中指定的数据库连接信息。
保存并关闭文件,当你完成编辑。
有了您的数据库信息并将 Mongoose 添加到您的项目中,您已经准备好创建将塑造鲨鱼
集合中的数据的方案和模型。
步骤 3 – 创建蒙古模式和模式
我们的下一步将是思考用户将通过他们的输入在sharkinfo
数据库中创建的鲨鱼
收藏的结构。
按照这个主题,我们可以让用户添加新的鲨鱼,详细介绍他们的整体性格,这个目标将塑造我们如何创建我们的计划。
若要将您的方案和模型与应用程序的其他部分区分开来,请在当前项目目录中创建一个模型
目录:
1mkdir models
接下来,打开名为sharks.js
的文件来创建您的方案和模型:
1nano models/sharks.js
导入文件顶部的mongoose
模块:
1[label ~/node_project/models/sharks.js]
2const mongoose = require('mongoose');
下面,定义一个Schema
对象,作为你的鲨鱼计划的基础:
1[label ~/node_project/models/sharks.js]
2const mongoose = require('mongoose');
3const Schema = mongoose.Schema;
现在你可以定义你想在你的图表中包含的字段。 因为我们想要创建一个集合的个别鲨鱼和有关他们的行为的信息,让我们包括一个名称
密钥和一个字符
密钥。
1[label ~/node_project/models/sharks.js]
2...
3const Shark = new Schema ({
4 name: { type: String, required: true },
5 character: { type: String, required: true },
6});
此定义包括我们对用户所期望的输入类型(在这种情况下,一个 字符串)的信息,以及该输入是否需要。
最后,使用Mongoose的[model()]函数(https://mongoosejs.com/docs/api.html#mongoose_Mongoose-model)创建Shark
模型,此模型将允许您从您的收藏中查询文档并验证新文档。
1[label ~/node_project/models/sharks.js]
2...
3module.exports = mongoose.model('Shark', Shark)
此最后一行使我们的Shark
模型可用作为一个模块,使用module.exports
属性(https://nodejs.org/api/modules.html#modules_exports_shortcut)。
已完成的「models/sharks.js」檔案看起來如下:
1[label ~/node_project/models/sharks.js]
2const mongoose = require('mongoose');
3const Schema = mongoose.Schema;
4
5const Shark = new Schema ({
6 name: { type: String, required: true },
7 character: { type: String, required: true },
8});
9
10module.exports = mongoose.model('Shark', Shark)
保存并关闭文件,当你完成编辑。
有了Shark
方案和模型,您可以开始工作,这将决定您的应用程序如何处理用户输入的逻辑。
步骤4:创建控制器
我们的下一步将是创建控制器组件,该组件将确定用户输入如何存储到我们的数据库并返回用户。
首先,为控制器创建一个目录:
1mkdir controllers
接下来,打开该文件夹中的一个名为sharks.js
的文件:
1nano controllers/sharks.js
在文件的顶部,我们将导入模块与我们的Shark
模型,以便我们可以在我们的控制器的逻辑中使用它。
将以下需要
函数添加到文件的开始:
1[label ~/node_project/controllers/sharks.js]
2const path = require('path');
3const Shark = require('../models/sharks');
接下来,我们将写出一个函数序列,我们将使用 Node 的 exports
缩写来导出控制器模块,这些函数将包括与我们用户的鲨鱼数据相关的三个任务:
- 向用户发送鲨鱼输入表格.
- 创建新的鲨鱼输入。
首先,创建一个索引
函数,以显示与输入表单的鲨鱼页面。
1[label ~/node_project/controllers/sharks.js]
2...
3exports.index = function (req, res) {
4 res.sendFile(path.resolve('views/sharks.html'));
5};
接下来,在索引
函数下方,添加一个名为创建
的函数,在你的鲨鱼
集合中创建一个新的鲨鱼条目:
1[label ~/node_project/controllers/sharks.js]
2...
3exports.create = function (req, res) {
4 var newShark = new Shark(req.body);
5 console.log(req.body);
6 newShark.save(function (err) {
7 if(err) {
8 res.status(400).send('Unable to save shark to database');
9 } else {
10 res.redirect('/sharks/getshark');
11 }
12 });
13 };
此函数将被调用当用户发布鲨鱼数据到sharks.html
页面上的表单时。在我们创建应用程序路线时,我们将在教程中稍后创建此POST终端的路线。使用POST请求的身体
,我们的创建
函数将创建一个新的鲨鱼文档对象,这里称为newShark
,使用我们已导入的Shark
模型。我们添加了一种console.log
方法(https://developer.mozilla.org/en-US/docs/Web/API/Console/log)来输出鲨鱼输入到控制台,以检查我们的POST方法是否按预期工作,但如果您喜欢的话,您可以放心放弃。
使用newShark
对象,创建
函数将随后调用Mongoose的model.save()
方法(https://mongoosejs.com/docs/api.html#model_Model-save)来创建一个新的鲨鱼文件,使用您在Shark
模型中定义的密钥。此 回调函数遵循 标准节点回调模式:回调(错误,结果)
。在出现错误的情况下,我们将向用户发送一个报告错误的消息,在成功的情况下,我们将使用res
redirect()`方法(https://expressjs.com/en/api.html#res.redirect)将用户发送到终端点,将其鲨鱼信息返回浏览器中。
最后,列表
函数将向用户显示收藏的内容,然后在创建
函数下方添加以下代码:
1[label ~/node_project/controllers/sharks.js]
2...
3exports.list = function (req, res) {
4 Shark.find({}).exec(function (err, sharks) {
5 if (err) {
6 return res.send(500, err);
7 }
8 res.render('getshark', {
9 sharks: sharks
10 });
11 });
12};
此函数使用 Mongoose 的 model.find() 方法](https://mongoosejs.com/docs/api.html#model_Model.find) 以
Shark 模型返回已输入到
sharks 集合的鲨鱼. 它通过返回查询对象 - 在这种情况下,在
sharks 集合中的所有条目 - 作为承诺,使用 Mongoose 的 [
exec() 函数 。
返回的鲨鱼
集合的查询对象将在鲨鱼
页面中渲染,我们将在下一步使用 EJS模板语言创建。
完成的文件将看起来像这样:
1[label ~/node_project/controllers/sharks.js]
2const path = require('path');
3const Shark = require('../models/sharks');
4
5exports.index = function (req, res) {
6 res.sendFile(path.resolve('views/sharks.html'));
7};
8
9exports.create = function (req, res) {
10 var newShark = new Shark(req.body);
11 console.log(req.body);
12 newShark.save(function (err) {
13 if(err) {
14 res.status(400).send('Unable to save shark to database');
15 } else {
16 res.redirect('/sharks/getshark');
17 }
18 });
19 };
20
21exports.list = function (req, res) {
22 Shark.find({}).exec(function (err, sharks) {
23 if (err) {
24 return res.send(500, err);
25 }
26 res.render('getshark', {
27 sharks: sharks
28 });
29 });
30};
请记住,虽然我们在这里不使用 箭头函数,但您可能希望在自己开发过程中重复这个代码时将其纳入其中。
保存并关闭文件,当你完成编辑。
在继续到下一步之前,您可以从您的node_project
目录中再次运行tree
,以查看该项目的结构,此时,为了简化,我们会告诉tree
使用I
选项将node_modules
目录省略:
1tree -I node_modules
有了您所做的添加,您的项目的结构将看起来像这样:
1[secondary_label Output]
2├── Dockerfile
3├── README.md
4├── app.js
5├── controllers
6│ └── sharks.js
7├── db.js
8├── models
9│ └── sharks.js
10├── package-lock.json
11├── package.json
12└── views
13 ├── css
14 │ └── styles.css
15 ├── index.html
16 └── sharks.html
现在你有一个控制器组件来指导用户输入是如何保存和返回给用户的,你可以继续创建将执行控制器的逻辑的视图。
步骤 5 – 使用 EJS 和 Express Middleware 来收集和渲染数据
为了使我们的应用程序能够使用用户数据,我们会做两件事:首先,我们将包括内置的Express中间软件功能,即urlencoded()
,这将使我们的应用程序能够分析用户输入的数据。
要使用 Express 的 urlencoded()
函数,请先打开您的 app.js
文件:
1nano app.js
在您的 express.static()
函数上面,添加以下行:
1[label ~/node_project/app.js]
2...
3app.use(express.urlencoded({ extended: true }));
4app.use(express.static(path));
5...
添加此功能将允许访问从我们的鲨鱼信息表格分析的 POST 数据,我们正在指定真
与扩展
选项,以便在我们的应用程序将分析的数据类型中提供更大的灵活性(包括嵌入对象等)。
保存并关闭文件,当你完成编辑。
接下来,我们将添加模板功能到我们的视图. 首先,安装 ejs
包与 npm install
:
1npm install ejs
接下来,在视图
文件夹中打开sharks.html
文件:
1nano views/sharks.html
在步骤3中,我们查看了这个页面,以确定我们应该如何写我们的蒙古式方案和模型:
现在,而不是有一个两个列(LINK0),我们将引入第三个列,其中有一个表格,用户可以输入关于鲨鱼的信息。
作为第一步,将现有列的尺寸更改为4
,以创建三个相同尺寸的列。 请注意,您需要在当前读到<div class="col-lg-6">
的两个行上进行此更改。
1[label ~/node_project/views/sharks.html]
2...
3<div class="container">
4 <div class="row">
5 <div class="col-lg-4">
6 <p>
7 <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.
8 </div>
9 <img src="https://cdn.jsdelivr.net/gh/andsky/tutorials-images/assets/docker_node_image/sawshark.jpg" alt="Sawshark">
10 </p>
11 </div>
12 <div class="col-lg-4">
13 <p>
14 <div class="caption">Other sharks are known to be friendly and welcoming!</div>
15 <img src="https://cdn.jsdelivr.net/gh/andsky/tutorials-images/assets/docker_node_image/sammy.png" alt="Sammy the Shark">
16 </p>
17 </div>
18 </div>
19 </div>
20
21 </html>
有关 Bootstrap 网格系统的介绍,包括其行和列布局,请参阅此 Bootstrap 介绍。
接下来,添加另一个列,其中包含用户的鲨鱼数据和将捕获该数据的 EJS 模板标签的 POST 请求的命名终端点。 此列将位于前列的关闭标签</p>
和</div>
下方,以及行、容器和HTML 文档的关闭标签上。
1[label ~/node_project/views/sharks.html]
2...
3 </p> <!-- closing p from previous column -->
4 </div> <!-- closing div from previous column -->
5<div class="col-lg-4">
6 <p>
7 <form action="/sharks/addshark" method="post">
8 <div class="caption">Enter Your Shark</div>
9 <input type="text" placeholder="Shark Name" name="name" <%=sharks[i].name; %>
10 <input type="text" placeholder="Shark Character" name="character" <%=sharks[i].character; %>
11 <button type="submit">Submit</button>
12 </form>
13 </p>
14 </div>
15 </div> <!-- closing div for row -->
16</div> <!-- closing div for container -->
17
18</html> <!-- closing html tag -->
在表格
标签中,您正在为用户的鲨鱼数据添加一个/sharks/addshark
终端点,并指定POST方法来提交它。
要将用户输入添加到您的鲨鱼
集合中,您正在使用 EJS 模板标签 (<%=
, %>
) 和 JavaScript 语法来将用户的输入绘制到新创建的文档中的相应字段。 有关 JavaScript 对象的更多信息,请参阅我们关于 [理解 JavaScript 对象] 的文章(https://andsky.com/tech/tutorials/understanding-objects-in-javascript)。
所有三个列的整个容器,包括您的鲨鱼输入表格的列,完成后将看起来如下:
1[label ~/node_project/views/sharks.html]
2...
3<div class="container">
4 <div class="row">
5 <div class="col-lg-4">
6 <p>
7 <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.
8 </div>
9 <img src="https://cdn.jsdelivr.net/gh/andsky/tutorials-images/assets/docker_node_image/sawshark.jpg" alt="Sawshark">
10 </p>
11 </div>
12 <div class="col-lg-4">
13 <p>
14 <div class="caption">Other sharks are known to be friendly and welcoming!</div>
15 <img src="https://cdn.jsdelivr.net/gh/andsky/tutorials-images/assets/docker_node_image/sammy.png" alt="Sammy the Shark">
16 </p>
17 </div>
18 <div class="col-lg-4">
19 <p>
20 <form action="/sharks/addshark" method="post">
21 <div class="caption">Enter Your Shark</div>
22 <input type="text" placeholder="Shark Name" name="name" <%=sharks[i].name; %>
23 <input type="text" placeholder="Shark Character" name="character" <%=sharks[i].character; %>
24 <button type="submit">Submit</button>
25 </form>
26 </p>
27 </div>
28 </div>
29 </div>
30
31</html>
保存并关闭文件,当你完成编辑。
现在,您有方法收集用户的输入,您可以创建一个终端点,以显示返回的鲨鱼及其相关字符信息。
将新修改的 sharks.html
文件复制到名为 getshark.html
的文件:
1cp views/sharks.html views/getshark.html
打开getshark.html
:
1nano views/getshark.html
在文件中,我们将修改我们创建鲨鱼输入表格时使用的列,将其替换为将鲨鱼显示在我们鲨鱼
集合中的列。 再次,您的代码将从前列现有的</p>
和</div>
标签和行,容器和HTML文档的关闭标签之间进行。
1[label ~/node_project/views/getshark.html]
2...
3 </p> <!-- closing p from previous column -->
4 </div> <!-- closing div from previous column -->
5<div class="col-lg-4">
6 <p>
7 <div class="caption">Your Sharks</div>
8 <ul>
9 <% sharks.forEach(function(shark) { %>
10 <p>Name: <%= shark.name %></p>
11 <p>Character: <%= shark.character %></p>
12 <% }); %>
13 </ul>
14 </p>
15 </div>
16 </div> <!-- closing div for row -->
17</div> <!-- closing div for container -->
18
19</html> <!-- closing html tag -->
在这里,您正在使用 EJS 模板标签和 forEach()
方法来输出鲨鱼
集合中的每个值,包括最近添加的鲨鱼的信息。
所有三个列的整个容器,包括你的鲨鱼
收藏的列,完成后将看起来像这样:
1[label ~/node_project/views/getshark.html]
2...
3<div class="container">
4 <div class="row">
5 <div class="col-lg-4">
6 <p>
7 <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.
8 </div>
9 <img src="https://cdn.jsdelivr.net/gh/andsky/tutorials-images/assets/docker_node_image/sawshark.jpg" alt="Sawshark">
10 </p>
11 </div>
12 <div class="col-lg-4">
13 <p>
14 <div class="caption">Other sharks are known to be friendly and welcoming!</div>
15 <img src="https://cdn.jsdelivr.net/gh/andsky/tutorials-images/assets/docker_node_image/sammy.png" alt="Sammy the Shark">
16 </p>
17 </div>
18 <div class="col-lg-4">
19 <p>
20 <div class="caption">Your Sharks</div>
21 <ul>
22 <% sharks.forEach(function(shark) { %>
23 <p>Name: <%= shark.name %></p>
24 <p>Character: <%= shark.character %></p>
25 <% }); %>
26 </ul>
27 </p>
28 </div>
29 </div>
30 </div>
31
32</html>
保存并关闭文件,当你完成编辑。
为了让应用程序使用您创建的模板,您需要将几个行添加到您的 app.js
文件中。
1nano app.js
在您添加express.urlencoded()
函数的地方,添加以下行:
1[label ~/node_project/app.js]
2...
3app.engine('html', require('ejs').renderFile);
4app.set('view engine', 'html');
5app.use(express.urlencoded({ extended: true }));
6app.use(express.static(path));
7
8...
app.engine
的方法告诉应用程序将 EJS 模板引擎映射到 HTML 文件中,而 app.set
则定义了默认视图引擎。
您的app.js
文件现在应该是这样的:
1[label ~/node_project/app.js]
2const express = require('express');
3const app = express();
4const router = express.Router();
5const db = require('./db');
6
7const path = __dirname + '/views/';
8const port = 8080;
9
10router.use(function (req,res,next) {
11 console.log('/' + req.method);
12 next();
13});
14
15router.get('/',function(req,res){
16 res.sendFile(path + 'index.html');
17});
18
19router.get('/sharks',function(req,res){
20 res.sendFile(path + 'sharks.html');
21});
22
23app.engine('html', require('ejs').renderFile);
24app.set('view engine', 'html');
25app.use(express.urlencoded({ extended: true }));
26app.use(express.static(path));
27app.use('/', router);
28
29app.listen(port, function () {
30 console.log('Example app listening on port 8080!')
31})
现在您已经创建了可以动态地与用户数据工作的视图,现在是时候创建项目的路径,将视图和控制器逻辑聚合在一起。
步骤6 - 创建路线
在将应用程序的组件聚集在一起的最后一步将是创建路线,我们将根据功能分离我们的路线,包括一条路线到我们的应用程序的登陆页面和另一条路线到我们的鲨鱼页面。
首先,创建一个路线
目录:
1mkdir routes
接下来,在这个目录中打开名为 index.js 的文件:
1nano routes/index.js
此文件将首先导入快递
、路由器
和路径
对象,使我们能够定义我们希望使用路由器
对象导出的路径,并使我们能够动态地使用文件路径工作。
1[label ~/node_project/routes/index.js]
2const express = require('express');
3const router = express.Router();
4const path = require('path');
接下来,添加以下router.use
函数,该函数会加载一个 middleware 函数,该函数会记录路由器的请求并将其传送到应用程序的路线:
1[label ~/node_project/routes/index.js]
2...
3
4router.use (function (req,res,next) {
5 console.log('/' + req.method);
6 next();
7});
请求到我们的应用程序的根将首先被引导到这里,从这里用户将被引导到我们的应用程序的目的地页面,我们将定义的路线下一步. 在router.use
函数下方添加以下代码来定义路线到目的地页面:
1[label ~/node_project/routes/index.js]
2...
3
4router.get('/',function(req,res){
5 res.sendFile(path.resolve('views/index.html'));
6});
当用户访问我们的应用程序时,我们想要发送他们的第一个地方是我们在我们的视图
目录中的index.html
定位页。
最后,为了使这些路径作为应用程序中的其他地方可导入的模块可访问,在文件末尾添加一个关闭表达式来导出路由器
对象:
1[label ~/node_project/routes/index.js]
2...
3
4module.exports = router;
完成的文件将看起来像这样:
1[label ~/node_project/routes/index.js]
2const express = require('express');
3const router = express.Router();
4const path = require('path');
5
6router.use (function (req,res,next) {
7 console.log('/' + req.method);
8 next();
9});
10
11router.get('/',function(req,res){
12 res.sendFile(path.resolve('views/index.html'));
13});
14
15module.exports = router;
保存并关闭此文件,当你完成编辑。
接下来,打开名为sharks.js
的文件来定义应用程序应该如何使用我们创建的不同端点和视图以与用户的鲨鱼输入工作:
1nano routes/sharks.js
在文件的顶部,导入快递
和路由器
对象:
1[label ~/node_project/routes/sharks.js]
2const express = require('express');
3const router = express.Router();
接下来,导入一个名为鲨鱼
的模块,允许您使用控制器定义的导出函数工作:
1[label ~/node_project/routes/sharks.js]
2const express = require('express');
3const router = express.Router();
4const shark = require('../controllers/sharks');
现在你可以使用你在你的鲨鱼
控制器文件中定义的索引
、创建
和列表
函数创建路线,每个路线都将与适当的HTTP方法相关联:在渲染主要鲨鱼信息登陆页时GET,并将鲨鱼列表返回用户,在创建新的鲨鱼条目时POST:
1[label ~/node_project/routes/sharks.js]
2...
3
4router.get('/', function(req, res){
5 shark.index(req,res);
6});
7
8router.post('/addshark', function(req, res) {
9 shark.create(req,res);
10});
11
12router.get('/getshark', function(req, res) {
13 shark.list(req,res);
14});
每个路径都使用了controlers/sharks.js
中的相关函数,因为我们通过将该模块导入到该文件的顶部,使该模块可以访问。
最后,通过将这些路径附加到路由器
对象并导出它们来关闭文件:
1[label ~/node_project/routes/index.js]
2...
3
4module.exports = router;
完成的文件将看起来像这样:
1[label ~/node_project/routes/sharks.js]
2const express = require('express');
3const router = express.Router();
4const shark = require('../controllers/sharks');
5
6router.get('/', function(req, res){
7 shark.index(req,res);
8});
9
10router.post('/addshark', function(req, res) {
11 shark.create(req,res);
12});
13
14router.get('/getshark', function(req, res) {
15 shark.list(req,res);
16});
17
18module.exports = router;
保存并关闭文件,当你完成编辑。
使这些路径可用于您的应用程序的最后一步将是将它们添加到app.js
。
1nano app.js
在你的db
常数下方,为你的路线添加以下进口:
1[label ~/node_project/app.js]
2...
3const db = require('./db');
4const sharks = require('./routes/sharks');
接下来,用以下行代替当前安装您的路由器
对象的app.use
函数,该函数将安装鲨鱼
路由器模块:
1[label ~/node_project/app.js]
2...
3app.use(express.static(path));
4app.use('/sharks', sharks);
5
6app.listen(port, function () {
7 console.log("Example app listening on port 8080!")
8})
您现在可以删除此文件中以前定义的路由,因为您正在使用鲨鱼
路由器模块导入应用程序的路由器。
您的app.js
文件的最终版本将看起来如下:
1[label ~/node_project/app.js]
2const express = require('express');
3const app = express();
4const router = express.Router();
5const db = require('./db');
6const sharks = require('./routes/sharks');
7
8const path = __dirname + '/views/';
9const port = 8080;
10
11app.engine('html', require('ejs').renderFile);
12app.set('view engine', 'html');
13app.use(express.urlencoded({ extended: true }));
14app.use(express.static(path));
15app.use('/sharks', sharks);
16
17app.listen(port, function () {
18 console.log('Example app listening on port 8080!')
19})
保存并关闭文件,当你完成编辑。
您现在可以再次运行树
,查看项目的最终结构:
1tree -I node_modules
您的项目结构现在将看起来像这样:
1[secondary_label Output]
2├── Dockerfile
3├── README.md
4├── app.js
5├── controllers
6│ └── sharks.js
7├── db.js
8├── models
9│ └── sharks.js
10├── package-lock.json
11├── package.json
12├── routes
13│ ├── index.js
14│ └── sharks.js
15└── views
16 ├── css
17 │ └── styles.css
18 ├── getshark.html
19 ├── index.html
20 └── sharks.html
有了所有应用程序组件的创建并投入使用,您现在已经准备好将测试鲨鱼添加到您的数据库中!
如果您在前提条件中遵循了初始服务器设置教程,则需要修改防火墙,因为它目前只允许SSH流量。
1sudo ufw allow 8080
启动应用:
1node app.js
接下来,导航您的浏览器到 http://your_server_ip:8080
. 您将看到以下目的地页面:
点击获取鲨鱼信息
按钮,您将看到以下信息页面,并添加鲨鱼输入表格:
在表格中,添加您所选择的鲨鱼. 为此演示的目的,我们将Megalodon Shark
添加到 Shark Name字段,Ancient
添加到 Shark Character字段:
点击提交
按钮,您将看到一个页面,其中有这些鲨鱼信息向您显示:
您还会在控制台中看到输出,表示鲨鱼已被添加到您的收藏中:
1[secondary_label Output]
2Example app listening on port 8080!
3{ name: 'Megalodon Shark', character: 'Ancient' }
如果您想创建一个新的鲨鱼条目,请返回 Sharks页面,并重复添加鲨鱼的过程。
你现在有一个工作鲨鱼信息应用程序,允许用户添加有关他们最喜欢的鲨鱼的信息。
结论
在本教程中,您通过集成 MongoDB 数据库并使用 MVC 架构模式重写应用程序的逻辑来构建一个 Node 应用程序。
有关 MVC 模式在其他场合的更多资源,请参阅我们的 Django 开发系列或 [如何在 Ubuntu 18.04 上构建现代 Web 应用程序以管理 Django 客户信息并响应(https://andsky.com/tech/tutorials/how-to-build-a-modern-web-application-to-manage-customer-information-with-django-and-react-on-ubuntu-18-04))。
有关与 MongoDB 合作的更多信息,请参阅我们的图书馆 MongoDB 教程。