Введение
При работе с Node.js вы можете столкнуться с ситуацией, когда вы разрабатываете проект, который будет сохранять и запрашивать данные. В данном случае вам нужно будет выбрать решение для базы данных, которое будет отвечать характеристикам данных приложения и типов запросов.
В этом обучающем руководстве вы будете интегрировать базу данных MongoDB с существующим приложением Node. NoSQL базы данных, такие как MongoDB, могут быть полезными, если список ваших требований для данных включают масштабируемость и гибкость. MongoDB отлично интегрируется с Node, поскольку она предназначена для асинхронной работы с объектами JSON.
Для интеграции MongoDB с вашим проектом вы будете использовать Object Document Mapper (ODM) Mongoose для создания схем и моделей данных вашего приложения. Это позволит вам организовать код приложения в соответствии с архитектурным шаблоном модель-представление-контроллер (MVC), который позволяет отделить логику обработки вводимых пользователей данных и логику структурирования данных и их отображения для пользователя. Использование такого шаблона может упрощать будущие тестирование и разработку, реализуя разделение проблем в базе кода.
После прохождения руководства у вас будет рабочее приложение с информацией об акулах, которое будет принимать вводимые пользователем данные об их любимых акулах и отображать результаты в браузере:
Предварительные требования
Шаг 1 — Создание пользователя Mongo
Прежде чем мы начнем работу с кодом приложения, нам нужно будет создать административного пользователя, который будет иметь доступ к базе данных приложения. Этот пользователь будет иметь административные права в любой базе данных, что предоставит вам необходимую гибкость при переключении и создании новых баз данных при необходимости.
Во-первых, проверьте, что MongoDB запущена на вашем сервере:
- sudo systemctl status mongodb
Следующий вывод показывает, что MongoDB запущена:
Output
● 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 для создания вашего пользователя:
После этого вы будете должны попасть в командную строку администратора:
Output
MongoDB shell version v3.6.3
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.6.3
...
>
При открытии командной строки вы увидите ряд административных предупреждений о том, что вам предоставляется неограниченный доступ к базе данных admin
. Дополнительную информацию об ограничении такого доступа см. в руководстве «Установка и обеспечение безопасности MongoDB на Ubuntu 16.04», которая будет полезна вам при переходе к финальной настройке.
А сейчас вы можете воспользоваться своим доступом к базе данных admin
для создания пользователя с привилегиями userAdminAnyDatabase
, которые позволят получать защищенный паролем доступ к базам данных вашего приложения.
в командной строке укажите, что вы хотите использовать базу данных admin
для создания вашего пользователя:
Далее создайте роль и пароль, добавив имя пользователя и пароль с помощью команды db.createUser
. Когда вы введете эту команду, командная строка будет добавлять три точки перед каждой строкой, пока работа команды не будет завершена. Обязательно замените пользователя и пароль, предоставленные здесь, на ваши имя пользователя и пароль:
- db.createUser(
- {
- user: "sammy",
- pwd: "your_password",
- roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
- }
- )
В результате этих действий будет создана запись для пользователя sammy
в базе данных admin
. Имя пользователя, которое вы выбрали, и база данных admin
будут служить идентификаторами для вашего пользователя.
Вывод для всего процесса будет выглядеть следующим образом, включая сообщение о том, что ввод был выполнен успешно:
Output
> db.createUser(
... {
... user: "sammy",
... pwd: "your_password",
... roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
... }
...)
Successfully added user: {
"user" : "sammy",
"roles" : [
{
"role" : "userAdminAnyDatabase",
"db" : "admin"
}
]
}
После создания вашего пользователя и пароля вы можете закрыть командную строку Mongo:
Теперь, когда вы создали пользователя для базы данных, вы можете перейти к клонированию кода начального проекта и добавлению библиотеки Mongoose, которая позволит вам реализовать схемы и модели для коллекций в ваших базах данных.
Шаг 2 — Добавление информации о Mongoose и базе данных в проект
Нашими следующими действия будут клонирование начального кода приложения и добавление в проект информации о Mongoose и нашей базе данных MongoDB.
В корневой директории пользователя без прав root клонируйте репозиторий nodejs-image-demo
из учетной записи DigitalOcean на GitHub. Этот репозиторий содержит код настройки, описанной в руководстве Сборка приложения Node.js с помощью Docker.
Клонируйте репозиторий в директорию с именем node_project
:
- git clone https://github.com/do-community/nodejs-image-demo.git node_project
Перейдите в директорию node_project
:
Прежде чем изменить код проекта, давайте посмотрим на структуру проекта с помощью команды tree
.
Подсказка: tree
— это полезная команда для просмотра структур файлов и каталогов из командной строки. Для установки вы можете использовать следующую команду:
Для ее использования перейдите в заданную директорию с помощью команды cd
и введите tree
. Также вы можете указать путь для начальной точки с помощью команды:
- tree /home/sammy/sammys-project
Введите следующее для просмотра директории node_project
:
Структура текущего проекта выглядит следующим образом:
Output
├── Dockerfile
├── README.md
├── app.js
├── package-lock.json
├── package.json
└── views
├── css
│ └── styles.css
├── index.html
└── sharks.html
Мы будем добавлять директории в этот проект по мере прохождения руководства, и команда tree
будет полезна для оценки нашего прогресса.
Далее добавьте в проект пакет mongoose
npm с помощью команды npm install
:
Эта команда создаст директорию node_modules
в директории вашего проекта, используя зависимости, перечисленные в файле package.json
проекта, и добавит mongoose
в эту директорию. Также она добавит mongoose
в зависимости, перечисленные в файле package.json
. Более подробную информацию о файле package.json
см. в шаге 1 руководства по сборке приложения Node.js с помощью Docker.
Перед созданием любых схем или моделей мы добавим информацию о подключении базы данных, чтобы наше приложение смогло подключиться к нашей базе данных.
Чтобы максимально разделить интересы вашего приложения, создайте отдельный файл для информации о подключении базы данных с именем db.js
. Откройте файл в nano
или вашем любимом редакторе:
Во-первых, импортируйте модуль mongoose
с помощью функции require
:
~/node_project/db.js
const mongoose = require('mongoose');
Это позволит вам получить доступ к встроенным методам Mongoose, которые вы будете использовать для создания подключения к вашей базе данных.
Далее добавьте следующие константы для определения информации для URI подключения к Mongo. Хотя использование имени пользователя и пароля не является обязательным, мы добавим их, чтобы с их помощью можно было запрашивать аутентификацию для нашей базы данных. Обязательно замените имя пользователя и пароль, представленные ниже, на ваши собственные. Также вы можете назвать базу данных как-то иначе, чем «^>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()
мы указали, что хотим использовать новый парсер URL-адресов Mongo.
Сохраните и закройте файл после завершения редактирования.
В качестве заключительного шага добавьте информацию о подключении базы данных в файл app.js
, чтобы приложение могло использовать ее. Откройте 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
Нашим следующим шагом будет изучение структуры коллекции sharks
, которую будут создавать пользователи в базе данных sharkinfo
с помощью ввода данных. Какую структуру должны иметь создаваемые нами документы? Страница информации об акуле в нашем текущем приложении содержит некоторые сведения о разных акулах и их поведении:
В соответствии с этой темой мы можем попросить пользователей добавлять новых акул с общими данными о них. Эта цель будет определять то, как мы создадим нашу схему.
Чтобы обеспечить отличие ваших схем и моделей от других частей приложения, создайте директорию models
в текущей директории проекта:
Далее откройте файл sharks.js
для создания вашей схемы и модели:
Импортируйте модуль mongoose
в верхней части файла:
~/node_project/models/sharks.js
const mongoose = require('mongoose');
Ниже определите объект Schema
для использования в качестве основы для вашей схемы акулы:
~/node_project/models/sharks.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
Теперь вы можете определить поля, которые хотите включить в свою схему. Поскольку мы хотим создать коллекцию с отдельными акулами и информацией об их поведении, давайте добавим ключ name
и ключ character
. Добавьте следующую схему Shark
под определениями ваших констант:
~/node_project/models/sharks.js
...
const Shark = new Schema ({
name: { type: String, required: true },
character: { type: String, required: true },
});
Это определение включает информацию о том, какой тип ввода мы ожидаем от пользователей, в данном случае string, а также о том, обязательно ли вводить эти данные.
Наконец, создайте модель Shark
с помощью функции model()
в Mongoose. Эта модель позволит запрашивать документы из вашей коллекции и выполнять валидацию новых документов. Добавьте следующую строку внизу файла:
~/node_project/models/sharks.js
...
module.exports = mongoose.model('Shark', Shark)
Эта последняя строка делает нашу модель Shark
доступной для использования в качестве модуля с помощью свойства module.exports
. Это свойство определяет значения, которые модуль будет экспортировать, делая их доступными для использования в любом месте приложения.
Итоговый файл models/sharks.js
выглядит следующим образом:
~/node_project/models/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 — Создание контроллеров
На следующем шаге мы сможем создать компонент контроллера, который будет определять, как вводимые пользователем данные будут сохраняться в нашей базе данных и извлекаться из нее.
Во-первых, создайте директорию для контроллера:
Далее откройте в этой папке файл sharks.js
:
- nano controllers/sharks.js
Сверху файла мы импортируем модуль в нашу модель Shark
, чтобы мы могли использовать его в логике нашего контроллера. Также мы импортируем модуль path
для доступа к утилитам, которые позволят нам задать путь к форме, куда пользователи будут вводить данные об акулах.
Добавьте следующие обязательные
функции в начало файла:
~/node_project/controllers/sharks.js
const path = require('path');
const Shark = require('../models/sharks');
Далее мы напишем последовательность функций, которые мы будем экспортировать в модуль контроллера с помощью сочетания клавиш exports
. Эти функции будут включать три задачи, связанные с данными об акулах нашего пользователя:
- Отправка пользователям формы ввода акулы.
- Создание новой записи акулы.
- Отображение акул для пользователей.
Для начала создайте функцию index
для отображения страницы с акулами с формой ввода. Добавьте эту функцию под импортами:
~/node_project/controllers/sharks.js
...
exports.index = function (req, res) {
res.sendFile(path.resolve('views/sharks.html'));
};
Затем под функцией index
добавьте функцию с именем create
для создания новой записи акулы в коллекции sharks
:
~/node_project/controllers/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');
}
});
};
Эта функция будет вызываться, когда пользователь публикует данные об акуле в форме на странице sharks.html
. Мы создадим маршрут с конечной точкой POST позже в этом руководстве, когда мы будем создавать маршруты нашего приложения. Используя body
запроса POST, наша функция create
будет создавать новый объект документа акулы, который называется здесь newShark
с помощью модели Shark
, которую мы импортировали. Мы добавили метод console.log
для вывода записи акулы в консоль, чтобы убедиться, что наш метод POST работает надлежащим образом, но вы можете пропустить этот шаг, если хотите.
Используя объект newShark
, функция create
будет вызывать метод model.save()
Mongoose для создания нового документа акулы, используя ключ, который вы определили в модели Shark
. Эта функция обратного вызова соответствует стандартной схеме обратного вызова Node: callback(error, results)
. В случае ошибки мы будем отправлять сообщение об ошибке нашим пользователям, а в случае успеха мы будем использовать метод res.redirect()
для отправки пользователей в конечную точку, которая будет возвращать им информацию об акуле в браузере.
Наконец, функция list
будет отображать содержимое коллекции для пользователя. Добавьте следующий код под функцией create
:
~/node_project/controllers/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
с методом model.find()
Mongoose для возврата акул, которые были добавлены в коллекцию sharks
. Она выполняет эту задачу, возвращая объект запроса — в данном случае это все записи в коллекции sharks
— в качестве обеспечения, используя функцию exec()
Mongoose. В случае ошибки функция обратного вызова будет отправлять ошибку с кодом 500.
Возвращаемый объект запроса с коллекцией sharks
будет отображаться на странице getshark
, которую мы создадим на следующем шаге с помощью языка шаблонов EJS.
Итоговый файл будет выглядеть примерно так:
~/node_project/controllers/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
});
});
};
Обязательно учитывайте, что мы не будем использовать здесь стрелочные функции, вы можете включить их в этот код, если будете использовать этот код в собственной разработке.
Сохраните и закройте файл после завершения редактирования.
Перед переходом к следующему шагу вы снова можете запустить tree
из директории node_project
для просмотра структуры проекта на данный момент. На этот раз для лаконичности мы будем использовать tree
, чтобы пропустить node_modules
, используя параметр -I:
После внесения этих изменений ваш проект будет выглядеть следующим образом:
Output
├── 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()
, которая позволит нашему приложению парсить вводимые пользователем данные. А затем мы добавим теги шаблона в наши представления, чтобы активировать динамическое взаимодействие с данными пользователя в нашем коде.
Для работы с функцией urlencoded()
Express откройте ваш файл app.js
:
Над функцией express.static()
добавьте следующую строку:
~/node_project/app.js
...
app.use(express.urlencoded({ extended: true }));
app.use(express.static(path));
...
Добавление этой функции позволит получить доступ к распарсенным данным POST из нашей формы информации об акуле. Мы укажем значение true
параметра extended
для обеспечения большей гибкости в отношении типа данных, который будет парсить ваше приложение (включая такие вещи как вложенные объекты). Дополнительную информацию о параметрах см. в документации для функции.
Сохраните и закройте файл после завершения редактирования.
Далее мы добавим функциональность шаблона для наших представлений. Во-первых, установите пакет ejs
с помощью команды npm install
:
Далее откройте файл sharks.html
в папке views
:
На шаге 3 мы просматривали эту страницу для определения того, как мы должны записать нашу схему и модель Mongoose:
Теперь, вместо того, чтобы использовать дизайн с двумя столбцами, мы добавим третий столбец с формой, где пользователи смогут вводить информацию об акулах.
В качестве первого шага укажите размеры 4
для существующих столбцов, чтобы создать три столбца одинакового размера. Обратите внимание, что вам нужно внести эти изменения в двух строках, которые сейчас выглядят следующим образом: <div class="col-lg-6">
. Укажите значения <div class="col-lg-4">
:
~/node_project/views/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://assets.digitalocean.com/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://assets.digitalocean.com/articles/docker_node_image/sammy.png" alt="Sammy the Shark">
</p>
</div>
</div>
</div>
</html>
Чтобы познакомиться с системой Bootstrap, включая схемы столбцов и рядов, см. Введение в Bootstrap.
Далее добавьте другой столбец, который включает конечную точку для запроса POST с пользовательскими данными об акуле и тегами шаблона EJS, который будут получать эти данные. Этот столбец будет располагаться под закрывающими тегами </p>
и </div>
предыдущего столбца и над закрывающими тегами для ряда, контейнера и HTML документа. Эти закрывающие теги уже есть в коде; они также обозначены ниже комментариями. Оставьте их на месте, когда вы добавите следующий код для создания нового столбца:
~/node_project/views/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/views/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://assets.digitalocean.com/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://assets.digitalocean.com/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
:
Внутри файла мы изменим столбец, который мы использовали для создания нашей формы ввода акул, заменив его на столбец, который будет отображать акул в нашей коллекции sharks
. Ваш код будет размещаться между существующими тегами </p>
и </div>
из предыдущего столбца и закрывающими тегами для ряда, контейнера и HTML документа. Обязательно оставьте эти теги на месте, когда вы будете добавлять следующий код для создания столбца:
~/node_project/views/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/views/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://assets.digitalocean.com/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://assets.digitalocean.com/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
. Откройте его снова:
Над местом, куда вы добавили функцию 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
:
Далее откройте в этой директории файл с именем index.js
:
Этот файл будет импортировать объекты express
, router
и path
, позволяющие нам определить маршруты, которые мы хотим экспортировать с объектом router
, и делая возможной динамическую работу с путем файла. Добавьте следующую строку вверху файла:
~/node_project/routes/index.js
const express = require('express');
const router = express.Router();
const path = require('path');
Далее добавьте следующую функцию router.use
, которая загружает промежуточную функцию, которая будет регистрировать запросы маршрутизатора и передавать их на маршрут приложения:
~/node_project/routes/index.js
...
router.use (function (req,res,next) {
console.log('/' + req.method);
next();
});
Запросы к корню нашего приложения будут направляться сначала сюда, а уже отсюда пользователи будут направляться на начальную страницу нашего приложения согласно маршруту, который мы определим здесь. Добавьте следующий код под функцией router.use
для определения маршрута к начальной странице:
~/node_project/routes/index.js
...
router.get('/',function(req,res){
res.sendFile(path.resolve('views/index.html'));
});
Когда пользователи будут посещать наше приложение, первым местом, куда мы будем направлять их, будет начальная страница index.html
, которую мы разместили в директории views
.
Наконец, чтобы сделать эти маршруты доступными в качестве импортируемого модуля в любом месте приложения, добавьте закрывающее выражение в конце файла для экспорта объекта router
:
~/node_project/routes/index.js
...
module.exports = router;
Итоговый файл будет выглядеть примерно так:
~/node_project/routes/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
для определения того, как приложение будет использовать различные конечные точки и представления, которые мы создали для работы с пользовательским вводом данных об акулах:
Вверху файла импортируйте объекты express
и router
:
~/node_project/routes/sharks.js
const express = require('express');
const router = express.Router();
Далее импортируйте модуль с именем sharks
, который позволит нам работать с экспортируемыми функциями, определенными с помощью контроллера:
~/node_project/routes/sharks.js
const express = require('express');
const router = express.Router();
const shark = require('../controllers/sharks');
Теперь вы можете создавать маршруты с помощью функций index
, create
и list
, определенных в файле контроллера sharks
. Каждый маршрут будет ассоциироваться с соответствующим методом HTTP: GET в случае отображения главной страницы с информацией об акулах и возврата списка акул пользователю, и POST в случае создания новой записи акулы:
~/node_project/routes/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/routes/index.js
...
module.exports = router;
Итоговый файл будет выглядеть примерно так:
~/node_project/routes/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
. Откройте этот файл снова:
Под вашей константой db
добавьте следующий импорт для ваших маршрутов:
~/node_project/app.js
...
const db = require('./db');
const sharks = require('./routes/sharks');
Далее замените функцию app.use
, которая в настоящее время монтирует ваш объект router
, на следующую строку, которая будет монтировать модуль маршрута 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
для просмотра окончательной структуры вашего проекта:
Теперь структура проекта будет выглядеть следующим образом:
Output
├── 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
После создания и добавления всех компонентов вашего приложения вы можете добавить тестовую акулу в базу данных!
Если вы следовали указаниям руководства по начальной настройке сервера из предварительных требований, вам нужно будет изменить ваш брандмауэр, поскольку в настоящее время он пропускает только трафик SSH. Чтобы разрешить трафик на порт 8080
, выполните команду:
Запустите приложение:
Откройте в браузере адрес http://your_server_ip:8080
. Вы увидите следующую начальную страницу:
Нажмите кнопку Get Shark Info (Получить информацию об акулах). Вы увидите следующую информационную страницу с добавленной формой ввода акулы:
В этой форме добавьте акулу по вашему выбору. В демонстрационных целях мы добавим Megalodon Shark
в поле Shark Name (Имя акулы) и Ancient
в поле Shark Character (Тип акулы):
Нажмите кнопку Submit (Отправить). Вы увидите страницу с информацией об акуле, отображаемая для вас:
Также вы увидите вывод в консоли, указывающий, что акула добавлена в вашу коллекцию:
Output
Example app listening on port 8080!
{ name: 'Megalodon Shark', character: 'Ancient' }
Если вы хотите создать новую запись акулы, вернитесь на страницу Sharks и повторите процесс добавления акулы.
Теперь у вас есть рабочее приложение с информацией об акулах, позволяющее пользователям добавить информацию о своих любимых акулах.
Заключение
В этом обучающем руководстве вы создали приложение Node, выполнив интеграцию с базой данных MongoDB и переписав логику приложения с помощью шаблона архитектуры MVC. Это приложение может выступать в качестве хорошей начальной точки для полномасштабного CRUD приложения.
Дополнительную информацию по использованию шаблонов MVC в другом контексте см. в нашей серии о разработке Django или руководстве Создание современного веб-приложения для управления данными клиента с помощью Django и React в Ubuntu 18.04.
Дополнительную информацию о работе с MongoDB см. в нашей библиотеке обучающих материалов для MongoDB.