- egg
- 提供基于 Egg 定制上层框架的能力
- 高度可扩展的插件机制
- 内置多进程管理
- 基于 Koa 开发,性能优异
- 框架稳定,测试覆盖率高
- 渐进式开发
cnpm i egg -S
cnpm i egg-bin -S -D
egg-bin dev
项目运行是会自动创建public文件夹,用来存放静态文件
利用nunjucks模板引擎,egg-view-nunjucks是egg的插件
cnpm install egg-view-nunjucks --save
egg的文件夹名称是规定好的
├── package.json
├── app.js (app.js 和 agent.js 用于自定义启动时的初始化工作)
├── agent.js (可选)
├── app
| ├── router.js(用于配置 URL 路由规则)
│ ├── controller(用于解析用户的输入,处理后返回相应的结果)
│ | └── home.js
│ ├── service (用于编写业务逻辑层,可选)
│ | └── user.js
│ ├── middleware (用于编写中间件,可选)
│ | └── response_time.js
│ ├── schedule (用于定时任务,可选)
│ | └── my_task.js
│ ├── public (用于放置静态资源,可选)
│ | └── reset.css
│ ├── extend (用于框架的扩展,可选)
│ | └── application.js app 对象指的是 Koa 的全局应用对象,全局只有一个,在应用启动时被创建。
│ ├── context.js (Context 指的是 Koa 的请求上下文,这是 请求级别 的对象)
│ ├── request.js (Request 对象和 Koa 的 Request 对象相同,是 请求级别 的对象)
│ ├── response.js (Response 对象和 Koa 的 Response 对象相同,是 请求级别 的对象)
│ ├── helper.js (Helper 函数用来提供一些实用的 utility 函数)
│ ├── view (用于放置模板文件)
│ | └── home.tpl
├── |── model (用于放置领域模型)
│ | └── home.tpl
│ └── extend (用于框架的扩展)
│ ├── helper.js (可选)
│ ├── request.js (可选)
│ ├── response.js (可选)
│ ├── context.js (可选)
│ ├── application.js (可选)
│ └── agent.js (可选)
├── config(用于编写配置文件)
| ├── plugin.js(用于配置需要加载的插件)
| ├── config.default.js
│ ├── config.prod.js
| ├── config.test.js (可选)
| ├── config.local.js (可选)
| └── config.unittest.js (可选)
└── test(用于单元测试)
├── middleware
| └── response_time.test.js
└── controller
└── home.test.js
框架提供了 egg-mysql 插件来访问 MySQL 数据库。这个插件既可以访问普通的 MySQL 数据库,也可以访问基于 MySQL 协议的在线数据库服务。
cnpm i --save egg-mysql
开启插件 config/plugin.js
exports.mysql = {
enable: true,
package: 'egg-mysql',
};
在一些较为复杂的应用中,我们可能会需要一个 ORM 框架来帮助我们管理数据层的代码。而在 Node.js 社区中,sequelize 是一个广泛使用的 ORM 框架,它支持 MySQL、PostgreSQL、SQLite 和 MSSQL 等多个数据源
- 安装
egg-sequelize插件会辅助我们将定义好的Model对象加载到app和ctx上
cnpm install --save egg-sequelize mysql2
- 启用插件
exports.sequelize = {
enable: true,
package: 'egg-sequelize',
};
- sequelize 配置
// config/config.default.js
config.sequelize = {
dialect: 'mysql',
host: 'localhost',
port: 3306,
username: "root",
password: "root",
database: 'cms-development'
};
// config/config.test.js
module.exports=app => {
let config={};
config.sequelize = {
dialect: 'mysql',
host: 'localhost',
port: 3306,
username: "root",
password: "root",
database: 'cms-test',
};
return config;
}
- 初始化数据库
sequelize 提供了 sequelize-cli 工具来实现 Migrations sequelize-cli用于支持数据迁移和项目引导。通过迁移,可以将现有数据库迁移到另一个状态,反之亦然 这些迁移文件会被保存在迁移文件中,迁移文件描述了怎样到达新状态以及如何恢复更改以返回到迁移前的旧状态
cnpm install --save sequelize sequelize-cli
- sequelizerc
我们希望将所有数据库 Migrations 相关的内容都放在database 目录下,所以我们在项目根目录下新建一个 .sequelizerc
配置文件
config 包含配置文件,它告诉 CLI 如何连接数据库
migrations-path 包含所有迁移文件
seeders-path 包含所有种子文件,seeders 来在初始化数据表中中初始化一些基础数据
models-path 包含您的项目的所有模型
const path = require('path');
module.exports = {
config: path.join(__dirname, 'database/config.json'),
'migrations-path': path.join(__dirname, 'database/migrations'),
'seeders-path': path.join(__dirname, 'database/seeders'),
'models-path': path.join(__dirname, 'app/model'),
};
- 初始化 Migrations
在项目的演进过程中,每一个迭代都有可能对数据库数据结构做变更,怎样跟踪每一个迭代的数据变更,并在不同的环境(开发、测试、CI)和迭代切换中,快速变更数据结构呢?这时候我们就需要 Migrations 来帮我们管理数据结构的变更了 初始化 Migrations 配置文件和目录 执行完后会生成 database/config.json 文件和 database/migrations
npx sequelize init:config
npx sequelize init:migrations
key是环境变量NODE_ENV的值,默认就是 development set NODE_ENV=test
config.json
{
"development": {
"username": "root",
"password": "root",
"database": "cms-development",
"host": "127.0.0.1",
"dialect": "mysql",
"operatorsAliases": false
},
"test": {
"username": "root",
"password": "root",
"database": "cms-test",
"host": "127.0.0.1",
"dialect": "mysql",
"operatorsAliases": false
}
}
- 创建users表
编写项目的第一个 Migration 文件来创建我们的一个 users 表
npx sequelize migration:generate --name=init-users
// 执行完后会在 database/migrations 目录下生成一个 migration 文件(${timestamp}-init-users.js)
创建升级脚本
// database\migrations\20190608143311-init-users.js
module.exports = {
// 在执行数据库升级时调用的函数,创建 users 表
up: async (queryInterface, Sequelize) => {
const { INTEGER, DATE, STRING } = Sequelize;
await queryInterface.createTable('users', {
id: { type: INTEGER, primaryKey: true, autoIncrement: true },
name: STRING(30),
age: INTEGER,
created_at: DATE,
updated_at: DATE,
});
},
// 在执行数据库降级时调用的函数,删除 users 表
down: async queryInterface => {
await queryInterface.dropTable('users');
},
};
执行 migrate 进行数据库变更
# 升级数据库
npx sequelize db:migrate
# 如果有问题需要回滚,可以通过 `db:migrate:undo` 回退一个变更
# npx sequelize db:migrate:undo
# 可以通过 `db:migrate:undo:all` 回退到初始状态
# npx sequelize db:migrate:undo:all
添加种子数据
sequelize seed:create --name init-users
npx sequelize db:seed:all
npx sequelize db:seed:all --env development
database\seeders\20190803152323-init-users.js
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.bulkInsert('users', [{
name: 'zhufeng',
age:1,
created_at: new Date(),
updated_at: new Date()
},{
name: 'jiagou',
age:2,
created_at: new Date(),
updated_at: new Date()
}],{});
},
down: (queryInterface, Sequelize) => {
return queryInterface.bulkDelete('users', null, {});
}
};
使用
// app\model\user.js
module.exports = app => {
const { STRING, INTEGER, DATE } = app.Sequelize;
const User = app.model.define('User', {
id: { type: INTEGER, primaryKey: true, autoIncrement: true },
name: STRING(30),
age: INTEGER,
created_at: DATE,
updated_at: DATE,
});
return User;
};
// 这个 Model 就可以在 Controller 和 Service 中通过 app.model.User 或者 ctx.model.User 访问到了
router.js
// app\router.js
module.exports = app => {
const { router, controller } = app;
router.get('/news', controller.news.index);
router.get('/users', controller.users.index);
}
users.js
const { Controller } = require('egg');
class UserController extends Controller {
async index() {
const {ctx,service}=this;
ctx.body = await ctx.model.User.findAll();
}
}
module.exports = UserController;
单元测试
添加命令 "test": "egg-bin test"
安装egg-mock npm i egg-mock -S -D
test/order.test1.js 是egg-mock的钩子函数