Monk.Node — простой и лёгкий MVC-фреймворк для Node.JS
Monk.Node – это бесплатный, открытый исходный код, быстрый и простой объектно-ориентированный легковесный фреймворк для разработки на Node.JS. Monk.Node был создан для быстрой разработки веб-приложений и упрощения разработки корпоративных приложений. С момента своего создания Monk.Node придерживается принципов простоты и практичности в дизайне. Сохраняя отличную производительность и минимизируя код, Monk.Node также уделяет внимание простоте использования. Распространяется по лицензии MIT, что позволяет бесплатно использовать Monk.Node и даже разрешать распространение или продажу приложений, основанных на Monk.Node.
Версия Monk.Node 2.x представляет собой революционную и переработанную версию, использующую совершенно новую архитектуру и включающую в себя множество новых функций Node.JS, оптимизированную ядро и уменьшенную зависимость, реализуя истинную ленивую загрузку, поддерживая npm и делая значительные улучшения в области веб-разработки, включая маршрутизацию, логирование, обработку исключений, модели, базы данных, шаблонизаторы и валидацию. Это идеальный выбор для новых проектов, будь то веб или API разработка.
Monk.Node продолжает активно добавлять новые функции и возможности, следите за обновлениями проекта.
Monk.Node основан на Express.js, но предлагает больше возможностей, чем сам Express.js! Великие проекты стоят на плечах гигантов!
2.2.9
, 6 февраля 2017 года.
============ 2017.02.06 V2.2.9 ============
- [Новое] log4js компонент журнала
- [Новое] config/log4js.json файл конфигурации журнала
- [Новое] utils/log4js.js инструмент регистрации класса
- [Исправлено] проблема с отсутствием папки журналов при записи журналов
- [Обновлённое] README.md документ
- [Обновлённый] package.json модуль зависимости
============ 2017.01.24 V2.2.8 ============
- [Обновлённое] README.md документ
- [Обновлённый] пакет. json модуль зависимости
============ 2017.01.12 V2.2.7 ============
- [Обновлённый] модуль зависимости package.json
============ 2016.12.23 V2.2.6 ============
- [Обновлённое] приложение. md документ
- [Обновлённый] модуль зависимости package.json
============ 2016.12.22 V2.2.5 ============
- [Обновлённое] приложение. md документ
- [Обновлённый] модуль зависимости package.json
============ 2016.12.20 V2.2.3 ============
- [Новое] папка locals, определение глобальных данных инъекции, аналогично ASP.NET MVC ViewData данные
- [Новое] utils/locals.js модуль, глобальная инъекция ядра модуля
- [Обновлённое] ядро приложения. js код, поддержка глобальной инъекции данных
- [Обновлённая] утилита/маршрут. js модель, поддержка локальной инъекции данных
- [Использование] документация
- [Обновление] модуль sequelize
- [Обновление] отладка модуля
- [Оптимизация] утилиты/маршрута. код js
- [Исправленное] проблема невозможности получения данных формы enctype="multipart/form-data"
============ 2016.12.16 V2.2.1 ============
- [Новое] модуль капчи, и написание библиотеки классов капчи: utils/captcha.js
- [Новая] демонстрация капчи, http://localhost:3000/backend/
- [Удалено] все активы ресурсов в папке core
- [Перемещено] core файл, db.js и route.js перемещены в папку utils
- [Обновлённые] страницы ошибок, отображающие больше информации об ошибках
- [Обновлённое] корневой каталог public как ресурс, совместимый с express.js (важное обновление)
- [Обновлённое] core/db.js код загрузки модуля, добавлена настраиваемая загрузка
- [Обновлённое] базовое руководство
- [Обновлённое] статические ресурсы документа
============ 2016.12.15 V2.1.2 ============
- [Новое] глобальный объект базы данных db, нет необходимости проходить через require (основное обновление)
- [Новое] utils/gmodels/js модуль
- [Новое] облегчённая библиотека изображений, поддерживает обработку изображений, включая водяные знаки, изменение размера и т. д.
- [Новое] node-schedule модуль запланированных задач
- [Новое] nodemailer модуль отправки электронной почты
- [Новое] lodash модуль, предоставляющий очень удобный инструмент JavaScript
- [Новые] видеоуроки
- [Оптимизированное] ядро класса маршрутизации
- [Обновлённое] отладочный модуль
- [Обновлённое] метод сохранения ошибок приложения. js, сохранение по дням
- [Обновлённое] основное руководство
- [Обновлённая] документация ORM
============ 2016.12.14 V2.1.1 ============
- [Оптимизированная] полная оптимизация приложения. код js
- [Новый] глобальный фильтр маршрута
- [Реструктурированная] реструктуризация express.js одностраничного движка, реализация многостраничного движка
- [Обновлённая] структура каталогов, удаление активов и папок представлений из корневого каталога, добавление папки share
- [Обновлённая] версия postgres
- [Обновлённая] версия socket.io
- [Обновлённая] документация по использованию
- [Устранённая] ошибка, из-за которой сеанс и cookie не действуют
- [Устранённое] неправильное использование core/db.js для загрузки модели
============ 2016.12.13 V2.0.1 ============
- [Поддержка] cors междоменная поддержка
- [Поддержка] защита от атак csurf, предоставление более безопасной среды разработки
- [Поддержка] typescript, возможность разработки модулей node.js с помощью typescript **logs/access** и **logs/error** используются для сохранения записей журнала.
* [Новое] — функция записи в журнал доступа.
* [Новое] — функция записи в журнал ошибок.
* [Новое] — функция разделения журналов.
* [Новое] — поддержка функций записи журналов в файл и записи в базу данных.
* [Новое] — зависимость модуля package.json от file-stream-rotator.
* [Оптимизация] — повышение производительности доступа к файлу app.js, который является файлом входа.
* [Обновление] — вывод журнала консоли на комбинированный уровень (предыдущий уровень — dev).
* [Обновление] — добавление примера предотвращения атаки CSRF в новую документацию.
============ 2016.12.10 V2.0.0 ============
* [Новое] — настройка приложения по умолчанию через файл app.js.
* [Новое] — возможность настройки контроллера по умолчанию и действия по умолчанию.
* [Новое] — каталог областей поддерживает разработку многоузловых проектов и включает backend (бэкенд) и frontend (фронтенд) по умолчанию.
* [Новое] — перемещение модуля models/index.js в core/db.js.
* [Настройка] — изменение имени общедоступного каталога на assets, который по умолчанию содержит backend (бэкэнд), frontend (фронтенд), vendor (сторонние плагины).
* [Настройка] — настройка подкаталога views, который по умолчанию включает backend (бэкенд), frontend (фронтенд).
* [Настройка] — переименование utils/socketServer.js в utils/socket.js.
* [Оптимизация] — оптимизация кода файла app.js для поддержки только настройки области по умолчанию, контроллера по умолчанию и действий по умолчанию.
* [Удаление] — удаление модуля express-controller и реализация более мощных функций.
============ 2016.12.08 V1.0.2 ============
* [Новое] — пример чата и мгновенных сообщений (рекомендуется).
* [Новое] — поддержка socket.io.
* [Новое] — поддержка redis.
* [Новое] — поддержка multer для загрузки файлов.
* [Новое] — создание папки uploads.
* [Оптимизация] — улучшение производительности загрузки файла app.js путём оптимизации порта и статических файлов, а также кода для обработки загруженных файлов пользователями.
* [Оптимизация] — улучшение структуры комментариев и кода.
* [Исправление] — исправление ошибки в файле package.json с зависимостью mysql.
============ 2016.12.07 V1.0.1 ============
* [Новое] — демонстрационный сайт.
* [Новое] — контроллер по умолчанию Home и действие по умолчанию Index.
* [Новое] — генератор кода модели.
* [Новое] — файл package.json с зависимостями sequelize-auto.
* [Оптимизация] — деконструкция каталогов.
* [Исправление] — устранение ошибки в файле app.js.
============ 2016.12.06 V1.0.0 ============
* [Выпуск] — версия v1.0.0. **Настройка области, контроллера и каталога действий и маршрутов**
// Настройка каталога файлов контроллера и привязка к маршруту resolve .setRouteDirectory({ areaDirectory: __dirname + '/areas', controllerDirname: 'controllers', defautController: 'home', defautAction: 'index' }) .bind(router);
- **Настройка обработки ошибок 404 и 500**
// Обработка ошибок // 404 обработка app.use(function (req, res, next) { var err = new Error('Not Found'); err.status = 404; next(err); }); // Обработка ошибки или исключения сервера 500 app.use(function (err, req, res, next) { var error = (req.app.get('env') === 'development') ? err : {}; //Запись в журнал ошибок var errorMes = '[' + Date() + ']' + req.url + '\n' + '[' + error.stack + ']' + '\n'; errorLogStream.write(errorMes); var status = err.status || 500; res.status(status); res.send('
' + status + ' ' + err.message + '\n' + errorMes + ''); });
- **Установка порта прослушивания веб-сайта, по умолчанию — 3000**
app.set('port', process.env.PORT || 3000);
- **Запуск WebSocket и настройка логики обработки на стороне сервера**
require(path.join(__dirname, 'utils', 'socket')).listen(server);
### Области
> Область представляет собой высокоуровневую организацию для веб-сайтов и кода, например, фронтэнд и бэкэнд. В настоящее время область поддерживает только написание логики контроллера.
- Добавление области
Просто создайте папку в каталоге `areas` и создайте каталог `controllers` в этой папке. Например: `areas/api/controllers`.
По умолчанию уже существуют две области: `backend` (бэкэнд) и `frontend` (фронтэнд).
- Доступ к области, по умолчанию доступ к контроллеру `homeController` и действию `get_index`.
http://localhost:3000/backend/
http://localhost:3000/frontend/
### Контроллеры
> Контроллер является основной единицей, которая позволяет всему фреймворку правильно работать в браузере, можно сказать, что это душа. Обратите внимание: контроллер с именем `homeController`, является контроллером по умолчанию, а действие `get_index` в этом контроллере является действием по умолчанию. Этот контроллер может содержать только одно действие, то есть `get_index`.
- Создание контроллера, имя файла контроллера должно заканчиваться на `Controller`. Например, в области `frontend` добавьте `controllers/aboutController.js`.
module.exports={
};
- В контроллере создайте действие, которое также является маршрутом, следуя формату `method_action`. В `aboutController.js` определите:
module.exports={ // Доступный адрес: http://localhost:3000/frontend/about/ get_index:function(req,res){ res.send("ok"); },
// Адрес отправки: http://localhost:3000/frontend/about/create
post_create:function(req,res){
res.send("ok");
},
// Доступный адрес: http://localhost:3000/frontend/about/company/baisoft
get_company_baisoft:function(req,res){
res.send("ok");
},
// Доступный адрес: http://localhost:3000/frontend/about/company/10
get_company_id:function(req,res,id){
res.send("ok");
},
// Доступный адрес: http://localhost:3000/frontend/about/company/10/百小僧
get_company_id_name:function(req,res,id,name){
res.send("ok");
},
// Доступный адрес: http://localhost:3000/frontend/about/百小僧/company
get_name_company:function(req,res,name){
res.send("ok");
},
// Фильтр
get_admin:[function(req,res,next){
if(未登录){
res.redirect("登录页面");
}
else{
next();
}
},function(req,res){
res.send("ok");
}],
// Несколько фильтров
get_admin:[function(req,res,next){
console.log("日志记录");
next();
},function(req,res,next){
if(未登录){
res.redirect("登录页面");
}
else{
next();
}
},function(req,res){
res.send("ok");
}],
};
### Шаблоны представлений
> Шаблоны представлений используют механизм шаблонов `ejs`, а каталог шаблонов по умолчанию находится в папке `views` под областью. [Подробная документация ejs](https://www.npmjs.com/package/ejs)
- Базовый синтаксис
<% if (user) { %>
```module.exports={
get_index:function(req,res){
res.render("frontend/about/index");
},
get_about:function(req,res){
res.render("frontend/about/index",{
user:{
name:"百小僧"
}
});
}
};
<%- include("header") %>
<%- include("footer") %>
// Передача параметров
<%- include("header",{
name:"百小僧"
}) %>
<%- include("footer",{
name:"百小僧"
}) %>
Каталог статических ресурсов по умолчанию -
public
в корневом каталоге.
<img src="/imgs/logo.png" />
<link res="stylesheet" href="/css/style.css" />
<script type="text/javascript" src="/js/script.js"></script>
Модели в основном размещаются в файле
models
member.js
module.exports = function(sequelize, DataTypes) {
return sequelize.define('member', {
id: {
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true
},
name: { **Тип:** DataTypes.STRING,
allowNull: false
}, {
tableName: 'member',
timestamps: false,
freezeTableName: true
});
};
Поскольку создание модели занимает много времени и содержит много повторяющегося кода, в данном фреймворке предусмотрен инструмент для генерации моделей данных. С его помощью можно быстро создать модель без необходимости ручного вмешательства.
**Перед генерацией необходимо настроить файл конфигурации config/db.json**. Обычно требуется указать только информацию о базе данных.
http://localhost:3000/tools/generate/models
### База данных CURD
Для операций с базой данных используется мощный ORM-фреймворк Sequelize.js, который поддерживает все основные базы данных. Подробные сведения доступны в документации (http://docs.sequelizejs.com/en/v3/).
*Информация о конфигурации базы данных находится в файле config/db.json.*
{ // 开发环境 "development": { "username": "sa", // 数据库用户名 "password": "000000", // 密码 "database": "monk_node", // имя базы данных "host": "MONKSOUL", // адрес сервера "dialect": "mssql", // тип базы данных ('mysql'|'mariadb'|'sqlite'|'postgres'|'mssql') "output": "../models", // каталог для сохранения моделей "additional": { // дополнительные параметры "timestamps": false, "freezeTableName": true } }, // 测试环境 "test": { "username": "sa", "password": "000000", "database": "monk_soul", "host": "localhost", "dialect": "mysql", "output": "../models", "additional": { "timestamps": false, "freezeTableName": true } }, // 生产环境 "production": { "username": "sa", "password": "000000", "database": "monk_node", "host": "MONKSOUL", "dialect": "mssql", "output": "../models", "additional": { "timestamps": false, "freezeTableName": true } } }
- CURD:
module.exports={ // 新增 post_create:function(req,res){ db.member.create({name:"百小僧"}).then(function(msg){ // 新增成功 console.log(msg); }); }, // 删除操作 post_delete:function(req,res){ db.member.destroy().then(function(msg){ // 删除成功 console.log(msg); }); }, // 根据条件删除 post_delete:function(req,res){ db.member.destroy({ where:{ id:10 } }).then(function(msg){ // 删除成功 console.log(msg); }); }, // 更新操作 post_update:function(req,res){ db.member.update({name:'新生帝'},{ where:{ id:10 } }).then(function(msg){ // 更新成功 console.log(msg); }); }, // 查询一条数据 по id get_id:function(req,res){ db.member.findById(10).then(function(data){ // 查询成功 console.log(data); }); }, // 查询一条数据 по условию get_one:function(req,res){ db.member.findOne({ where:{ name:"百小僧" } }}).then(function(data){ // 查询成功 console.log(data); }); }, // 查询所有 get_all:function(req,res){ db.member.findAll().then(function(data){ // 查询成功 console.log(data); }); }, // 查询指定条件 get_all:function(req,res){ db.member.findAll({ where:{ id:{ $gt:2 } } }).then(function(data){ // 查询成功 console.log(data); }); }, // 分页查询 get_all:function(req,res){ db.member.findAll({ offset: 10, limit: 2, where:{ isDel:false } }).then(function(data){ // 查询成功 console.log(data); }); } };
### Session,Cookies
> Session、Cookies используются для хранения информации о клиентских сеансах, обычно для проверки входа.
- Использование Session:
module.exports={ get_index:function(req,res){ // Проверяем наличие поля isVisit в session if(req.session.isVisit) { req.session.isVisit++; res.send('
Вы посетили эту страницу ' + req.session.isVisit + ' раз
'); } else { req.session.isVisit = 1; res.send("Добро пожаловать на первую страницу"); console.log(req.session); } } }
- Использование Cookies:
module.exports={
// 如果请求中的 cookie 存在 isVisit, 则输出 cookie
// 否则,设置 cookie 字段 isVisit, и устанавливаем срок действия в 1 минуту
if (req.cookies.isVisit) {
console.log(req.cookies);
res.send("再次欢迎访问");
} else {
res.cookie('isVisit', 1, {maxAge: 60 * 1000});
res.send("欢迎第一次访问");
}
}
Фильтры и промежуточное ПО
Фильтры и промежуточное программное обеспечение в основном используются для фильтрации запросов.
get_admin: [function (req, res, next) {
if (!loggedIn) {
res.redirect("登录页面");
} else {
next();
}
}, function (req, res) {
res.send("ok");
}]
};
module.exports = function (req, res, next) {
if(!loggedIn){
res.redirect("登录页面");
}else{
next();
}
};
В контроллере используем следующим образом:
module.exports={
get_admin:[loginFilter,function(req,res){
res.send("ok");
}]
}
get_admin: [
function (req, res, next) {
console.log("日志记录");
next();
},
function (req, res, next) {
if (!loggedIn) {
res.redirect("登录页面");
} else {
next();
}
},
function (req, res) {
res.send("ok");
}
]
};
Отправка формы
<form action="/backend/home/form1" method="post">
<input type="text" name="name" />
<input type="submit" value="提交">
</form>
<h3>表单(不带文件上传,带: enctype="multipart/form-data"):</h3>
<form action="/backend/home/form2" method="post" enctype="multipart/form-data">
<input type="text" name="name" />
<input type="submit" value="提交">
</form>
<h3>表单(带单个文件上传,带: enctype="multipart/form-data"):</h3>
<form action="/backend/home/form3" method="post" enctype="multipart/form-data">
<input type="file" name="file1">
<input type="text" name="name" />
<input type="submit" value="提交">
</form>
<h3>表单(带多个文件上传,带: enctype="multipart/form-data"):</h3>
<form action="/backend/home/form4" method="post" enctype="multipart/form-data">
<input type="file" name="file1">
<input type="file" name="file2">
<input type="text" name="name" />
<input type="submit" value="提交">
</form>
<h3>表单(带多个文件上传,上传表单名称 不一样(file1,file2,...),带: enctype="multipart/form-data"):</h3>
<form action="/backend/home/form5" method="post" enctype="multipart/form-data">
<input type="file" name="file1">
<input type="file" name="file2">
<input type="text" name="name" />
<input type="submit" value="提交">
</form>`
module.exports = {
// 表单(不带文件上传,不带: enctype="multipart/form-data")
post_form1: function (req, res) {
res.json(req.body);
},
// 表单(不带文件上传,带: enctype="multipart/form-data"):
post_form2: [multer().array(), function (req, res) {
res.json(req.body);
}],
// 表单(带单个文件上传,带: enctype="multipart/form-data"):
post_form3: [multer().single('file1'), function (req, res) {
res.send(
"文件:" + JSON.stringify(req.file) + "<br />表单" + JSON.stringify(req.body)
);
}],
// 表单(带多个文件上传,带: enctype="multipart/form-data"):
post_form4: [multer().array('file1'), function (req, res) {
res.send(
"文件:" + JSON.stringify(req.files) + "<br />表单" + JSON.stringify(req.body)
);
}],
// 表单(带多个文件上传,上传表单名称 不一样(file1,file2,...),带: enctype="multipart/form-data"):
post_form5: [multer().fields([{ name: "file1" }, { name: "file2" }]), function (
req,
res
) {
res.send(
"文件:" + JSON.stringify(req.files) + "<br />表单" + JSON.stringify(req.body)
);
}]
};
Подробная документация доступна по ссылке: multer 文档.
Загрузка файлов
Файлы загружаются с помощью мощного компонента multer. Подробная документация доступна на сайте npmjs.com.
<input type="file" name="logo">
<input>``` **Перевод текста на русский язык:**
**Отправка**
</form>
var path = require('path');
var fs = require('fs');
var multer = require('multer');
var upload = multer({ dest: 'uploads/' });
module.exports = {
post_upload: [upload.single('logo'), function(req, res, next) {
var file = req.file;
var ext = path.extname(file.originalname);
fs.rename(file.path, file.path + ext, function(err) {
if (err) {
res.send(JSON.stringify(err));
}
next();
});
}, function(req, res) {
res.send("Загрузка прошла успешно");
}]
}
Интегрирован модуль
redis
, документация.
var redis = require("redis"),
client = redis.createClient();
// если вы хотите выбрать базу данных 3 вместо 0 (по умолчанию), вызовите
// client.select(3, function() { /* ... */ });
client.on("error", function (err) {
console.log("Ошибка " + err);
});
client.set("строковый ключ", "строковое значение", redis.print);
client.hset("хеш-ключ", "hashtest 1", "некоторое значение", redis.print);
client.hset(["хеш-ключ", "hashtest 2", "другое значение"], redis.print);
client.hkeys("хеш-ключ", function (ошибка, ответы) {
console.log(количество ответов + " ответов:");
ответы.forEach(функция (ответ, i) {
console.log(" " + i + ": " + ответ);
});
клиент.quit();
});
В фреймворк уже интегрирован socket.io, можно разрабатывать приложения для реального времени, чата и т. д., подробная документация.
utils/socket.js
var io = require('socket.io')();
// socket.io базовое использование, прослушивание запросов на подключение
io.on('connection', function (socket) {
console.log("Соединение клиента успешно установлено~~");
// прослушивание событий от клиента
socket.on('send', function (data) {
// вызвать событие receive у клиента и передать data
io.emit('receive', data);
});
// здесь можно написать различные события прослушивания,
// через socket.on("") прослушивать события от клиента, через io.emit("") запускать все события от клиентов, socket.emit("") запускать события для конкретного клиента
});
exports.listen = function (server) {
return io.listen(server);
};
<!-- Импорт клиентского скрипта -->
<script src="/vendors/socket.io/socket.io.js"></script>
<script>
// Подключение к серверу
var socket = io.connect('http://localhost:3000/');
window.onload=function(){
var send=document.getElementById("send");
send.onclick=function(){
var name=document.getElementById("name").value;
var msg=document.getElementById("msg").value;
// Отправка сообщения
socket.emit('send', { data:name+":"+msg });
};
// Прослушивание сообщений от сервера
socket.on('receive', function (data) {
console.log(data);
var list = document.getElementById("list");
// Запись в список чата
list.innerHTML=list.innerHTML+"<br />"+data.data;
// Очистить msg
document.getElementById("msg").value="";
});
};
</script>
var csrf = require('csurf');
var csrfProtection = csrf({ cookie: true });
module.exports={
post_login:[csrfProtection,function(req,res){
res.send("ok",{ csrfToken: req.csrfToken() });
}]
};
<form action="/process" method="POST">
<input type="hidden" name="_csrf" value="{{csrfToken}}">
Любимый цвет: <input type="text" name="favoriteColor">
<button type="submit">Отправить</button>
</form>
$ npm install pm2 -g |
$ pm2 start app.js
$ npm install pm2-windows-startup -g
$ pm2-startup install
$ pm2 save
Если вы считаете Monk.Node ценным для вас и готовы поддержать его развитие, вы можете внести свой вклад в этот проект и поддержать автора.
Если вам нравится Monk.Node, вы можете нажать кнопку «star» в правом верхнем углу, чтобы следить за прогрессом в реальном времени, или нажать «watch».
Наконец, спасибо каждому другу, который предлагает идеи, использует или жертвует! Благодаря вам мы можем продолжать! И благодаря вам будущее станет ещё лучше!
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.