Egg.js

介绍

Egg.js 官网

Egg.js 是《阿里旗下产品》基于 Node.js 和 Koa 是一个 Nodejs 的企业级应用开发框架。 可以帮助发团队和开发人员降低开发和维护成本。
Express 和 Koa 是 Node.js 社区广泛使用的框架,简单且扩展性强,非常适合做个人项 目。但框架本身缺少约定,标准的 MVC 模型会有各种千奇百怪的写法。Egg 按照约定进行 开发,奉行『约定优于配置』,团队协作成本低。
Egg.js 基于 Es6、Es7 以及 Typescript、Koa2 使得 Nodejs 具有更规范的开发模式、更低 的学习成本、更优雅的代码、更少的开发成本、更少的维护成本。为企业级框架而生。

特性

  1. 提供基于 Egg 定制上层框架的能力
  2. 高度可扩展的插件机制
  3. 内置多进程管理
  4. 基于 Koa 开发,性能优异
  5. 框架稳定,测试覆盖率高
  6. 渐进式开发

Egg 快速入门、搭建环境、创建项目

环境准备

操作系统:支持 macOS,Linux,Windows
运行环境:Nodejs 建议选择 LTS 版本,Nodejs 最低要求 8.x。

安装 egg 脚手架以及使用 egg-init 创建项目

我们推荐直接使用脚手架,只需几条简单指令,即可快速生成项目:

1
2
3
4
npm i egg-init -g
egg-init egg-example --type=simple
cd egg-example
npm i

启动项目:

1
npm run dev

目录介绍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|-- .idea idea配置文件
|-- app 项目开发目录*
|-- router.js
|-- controller 控制器
|-- service(可选) 数据模型
|-- middleware(可选)
|-- public(可选) 静态资源目录
|-- reset.css
|-- view(可选) 视图
|-- config 项目配置文件*
|-- plugin.js
|-- config.default.js
|-- config.prod.js
|-- logs 日志文件*
|-- node_modules
|-- run 项目运行配置文件
|-- test 测试文件
|-- package.json 项目配置文件 管理项目模块等元数据*
|-- appveyor.yml
|-- jsconfig.json
|-- README.md
|-- typings
|-- yarn.lock

app 的类型是 Egg.Application,是全局应用对象,在每个项目中只会实例化一次,也就是说 egg.js 默认把 router,controller 集成好了。

controller 里放置个个业务模块;

egg.js 使用规范:文件名小写,类名首字母大写并使用驼峰命名;

egg.js 框架中使用同步编程模式=> async…await;

ctx 每次用户在使用时,框架就会实例化的一个 Egg.content 上下文,content 用来存放用户请求的一些信息;

路由

Router 主要用来描述请求 URL 和具体承担执行动作的 Controller 的对应关系, 框架约定了 app/router.js 文件用于统一所有路由规则。

通过统一的配置,我们可以避免路由规则逻辑散落在多个地方,从而出现未知的冲突,集中在一起我们可以更方便的来查看全局的路由规则。

定义 Router

  • app/router.js 里面定义 URL 路由规则
1
2
3
4
5
6
7
8
9
10
"use strict";

/**
* @param {Egg.Application} app - egg application
*/
module.exports = app => {
const { router, controller } = app;

router.get("/", controller.home.index);
};

控制器

Controller 负责解析用户的输入,处理后返回相应的结果。框架推荐 Controller 层主要对用户的请求参数进行处理(校验、转换),然后调用对应的 service 方法处理业务,得到业务结果后封装并返回:

  1. 获取用户通过 HTTP 传递过来的请求参数。
  2. 校验、组装参数。
  3. 调用 Service 进行业务处理,必要时处理转换 Service 的返回结果,让它适应用户的需求。
  4. 通过 HTTP 将结果响应给用户。

传参

GET、POST、PUT、DELETE的区别
1、POST 创建
2、DELETE 删除
3、PUT 更新
4、GET 查看

get 请求两种传参

put 和 delete 请求传参格式与 get 请求一致

  1. params

路由配置

1
router.get("/news/detail/:id", controller.news.detail);

获取方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class NewsController extends Controller {
detail() {
const { ctx } = this;

// egg获取动态路由参数 /detail/123
var params = ctx.params || {};
console.log(params);

ctx.body = {
code: 0,
data: { params },
msg: "请求成功"
};
}
}
  1. query

路由配置

1
router.get("/news/updateId", controller.news.updateId);

获取方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class NewsController extends Controller {
async updateId() {
const { ctx } = this;

// egg get 请求获取body中的参数 updateId?id=456
const data = await ctx.query;

ctx.body = {
code: 0,
data,
msg: "修改成功"
};
}
}

post 请求传参

路由配置

1
router.post("/news/add", controller.news.add);

获取方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class NewsController extends Controller {
async add() {
const { ctx } = this;

// egg post请求获取body中的参数
const data = await ctx.request.body;

ctx.body = {
code: 0,
data,
msg: "添加成功"
};
}
}

mysql

  1. 安装对应的插件 egg-mysql :
1
npm i --save egg-mysql
  1. 开启插件:
1
2
3
4
5
6
7
8
9
// config/plugin.js
"use strict";

module.exports = {
mysql: {
enable: true,
package: "egg-mysql"
}
};
  1. 单数据源
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// config/config.default.js

config.mysql = {
// 单数据库信息配置
client: {
// host
host: "0.0.0.0",
// 端口号
port: "0000",
// 用户名
user: "username",
// 密码
password: "password",
// 数据库名
database: "dbname"
},
// 是否加载到 app 上,默认开启
app: true,
// 是否加载到 agent 上,默认关闭
agent: false
};

sequelize

  1. 安装
1
npm install --save egg-sequelize mysql2
  1. 开启插件:
1
2
3
4
5
6
7
8
9
// config/plugin.js
"use strict";

module.exports = {
sequelize: {
enable: true,
package: "egg-sequelize"
}
};
  1. 编写 sequelize 配置
1
2
3
4
5
6
7
8
9
10
11
// config/config.default.js

config.sequelize = {
Sequelize: require("sequelize"),
dialect: "mysql",
database: "test_ry",
host: "47.94.214.227",
port: "3306",
username: "root",
password: "123456"
};

service

  1. router.js
1
2
3
4
5
module.exports = app => {
const { router, controller } = app;

// ...
};
  1. /service/article.js
1
2
3
4
5
6
7
8
9
"use strict";

const Service = require("egg").Service;

class ArticleService extends Service {
// ...
}

module.exports = ArticleService;
  1. /controller/article.js
1
2
3
4
5
6
7
8
9
10
"use strict";

const Controller = require("egg").Controller;
const moment = require("moment");

class ArticleController extends Controller {
// ...
}

module.exports = ArticleController;

  1. router.js
1
router.post("/article/create", controller.article.create);
  1. /service/article.js
1
2
3
4
5
6
7
8
9
10
async create(params) {
const { app } = this;
try {
const result = app.mysql.insert("newsList", params);
return result;
} catch (error) {
console.log(error);
return null;
}
}
  1. /controller/article.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
async create() {
const { ctx, service } = this;

const data = {
...ctx.request.body,
create_time: moment().format("YYYY-MM-DD HH:mm:ss")
};

const result = await service.article.create(data);

if (result) {
ctx.body = {
status: 200,
data: result
};
} else {
ctx.body = {
status: 500,
msg: "发布文章失败"
};
}
}

  1. router.js
1
router.delete("/article/delete/:id", controller.article.delete);
  1. /service/article.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
async delete(id) {
if (!id) {
console.log("id必须传递");
return null;
}

try {
const result = await this.app.mysql.delete("newsList", { id });
return result;
} catch (error) {
console.log(error);
return null;
}
}
  1. /controller/article.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
async delete() {
const { ctx, service } = this;

const result = await service.article.delete(ctx.params.id);

if (result) {
ctx.body = {
status: 200,
data: result
};
} else {
ctx.body = {
status: 500,
msg: "删除文章失败"
};
}
}

  1. router.js
1
2
router.get("/article/lists", controller.article.lists);
router.get("/article/detail/:id", controller.article.detail);
  1. /service/article.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
async lists() {
const { app } = this;

try {
const result = await app.mysql.select("newsList", {
orders: [["id", "desc"]],
limit: 2
});
return result;
} catch (error) {
console.log(error);
return null;
}
}

async detail(id) {
if (!id) {
console.log("id必须传递");
return null;
}

try {
const result = await this.app.mysql.get("newsList", { id });
return result;
} catch (error) {
console.log(error);
return null;
}
}
  1. /controller/article.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
async lists() {
const { ctx, service } = this;

const result = await service.article.lists();

if (result) {
ctx.body = {
status: 200,
data: result
};
} else {
ctx.body = {
status: 500,
msg: "查询文章列表失败"
};
}
}

async detail() {
const { ctx, service } = this;

const result = await service.article.detail(ctx.params.id);

if (result) {
ctx.body = {
status: 200,
data: result
};
} else {
ctx.body = {
status: 500,
msg: "查询文章详情失败"
};
}
}