快速初始化
我们推荐直接使用脚手架,只需几条简单指令,即可快速生成项目:
$ mkdir egg-example && cd egg-example
$ npm init egg --type=simple
$ npm i
启动项目:
$ npm run dev
$ open localhost:7001
启动后的界面
注意:这里默认地址是7001,如果修改,可以在config配置文件里面做如下修改:
// 自定义端口
config.cluster = {
listen: {
port: 7010
}
};
框架目录结构
- egg.js是约定优于配置的
egg-project
├── package.json
├── app.js (可选)
├── agent.js (可选)
├── app
| ├── router.js
│ ├── controller
│ | └── home.js
│ ├── service (可选)
│ | └── user.js
│ ├── middleware (可选)
│ | └── response_time.js
│ ├── schedule (可选)
│ | └── my_task.js
│ ├── public (可选)
│ | └── reset.css
│ ├── view (可选)
│ | └── 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
如上,由框架约定的目录:
app/router.js
用于配置 URL 路由规则,具体参见 Router。app/controller/**
用于解析用户的输入,处理后返回相应的结果,具体参见 Controller。app/service/**
用于编写业务逻辑层,可选,建议使用,具体参见 Service。app/middleware/**
用于编写中间件,可选,具体参见 Middleware。app/public/**
用于放置静态资源,可选,具体参见内置插件 egg-static。app/extend/**
用于框架的扩展,可选,具体参见框架扩展。config/config.{env}.js
用于编写配置文件,具体参见配置。config/plugin.js
用于配置需要加载的插件,具体参见插件。test/**
用于单元测试,具体参见单元测试。app.js
和agent.js
用于自定义启动时的初始化工作,可选,具体参见启动自定义。关于agent.js
的作用参见Agent机制。
由内置插件约定的目录:
app/public/**
用于放置静态资源,可选,具体参见内置插件 egg-static。app/schedule/**
用于定时任务,可选,具体参见定时任务。
怎么写一个接口?
后台接口避免不了和数据库打交道,下面例子咱们使用MySQL,ORM使用sequelize,
首先安装MySQL数据库(安装教程),以及navicat界面管理工具,这样就可以验证自己操作数据库是否成功。
egg中使用MySQL
安装对应的插件 egg-mysql :
$ npm i --save egg-mysql
开启插件:
// config/plugin.js
exports.mysql = {
enable: true,
package: ‘egg-mysql’,
};
在 config/config.${env}.js
配置各个环境的数据库连接信息。更详细教程参考官方文档
安装并配置 egg-sequelize 插件
(它会辅助我们将定义好的 Model 对象加载到 app 和 ctx 上)和 mysql2 模块
- 安装
npm install --save egg-sequelize mysql2
- 在
config/plugin.js
中引入 egg-sequelize 插件
exports.sequelize = {
enable: true,
package: ‘egg-sequelize’,
};
这里有个坑,egg项目初始化plugin.js导出使用的module.exports,而教程里又是 exports导出,这两者不能并存的,有多坑?你自己体验吧!如果使用module.exports就要以key: value的形式配置插件!不懂这俩区别的人就容易入坑!!!嗯~我就入了,所以推荐一篇文章https://www.imooc.com/article/34483。
- 在
config/config.default.js
中编写 sequelize 配置
config.sequelize = {
dialect: 'mysql',
host: '127.0.0.1',
port: 3306,
database: 'dev2',
username: 'root',
password: '',
timezone: "+08:00",
};
1. Router
Router 主要用来描述请求 URL 和具体承担执行动作的 Controller 的对应关系, 框架约定了 app/router.js 文件用于统一所有路由规则。通过统一的配置,我们可以避免路由规则逻辑散落在多个地方,从而出现未知的冲突,集中在一起我们可以更方便的来查看全局的路由规则。
下面我们添加一个注册接口,在app/router.js添加
'use strict';
/**
* @param {Egg.Application} app - egg application
*/
module.exports = app => {
const { router, controller } = app;
//注册
app.post("/example/register", app.controller.userControl.register);
router.get('/*', controller.home.index);
};
2. Controller
一切准备就绪后,开始我们的第一个Controller。我们下载的simple类型的example目录结构中是有controller这样一个目录。注意我在文章开头提到过,egg.js是约定优于配置的,这些目录是什么意思都可以在(官方教程的目录结构中看到)这个controller目录结构就是指明这个目录就是一个Controller,所有跟Controller有关的东西都放在这个目录下面。
下面我们自定义一个controller看看效果,在controller文件夹下新建一个userControl.js文件
'use strict';
const Controller = require('egg').Controller;
class userControl extends Controller {
async register() {
const { ctx } = this;
const params = ctx.request.body; // 获取请求参数
// 校验规则
const rule = {
username: { type: 'string' },
password: { type: 'string' },
};
try {
ctx.validate(rule, params); // 参数校验
const data = await ctx.service.userServer.register(params); // 把业务逻辑交给service处理
ctx.body = JSON.stringify(data); // 成功返回前端
} catch (err) {
ctx.body = JSON.stringify(err); // 异常返回前端
ctx.logger.info("userControl.register-error: ", JSON.stringify(err)); // 异常打印日志
}
}
}
module.exports = userControl;
参数校验egg自带了egg-validate,用的不是很舒服,我个人推荐使用egg-joi,使用方式我的博客有写哦,
一波小广告=>eggJS egg-joi优雅的参数校验。
3. Service
Service是业务逻辑层在我们自己下载的example中是没有这么一项的,但是在官方教程的目录结构中是有的,只是被标注了可选。首先我们需要在app下创建一个service的文件夹用来存放service文件(注意约定大于配置),再在service文件夹下新建一个userServer.js文件用来编写service代码
下面我们自定义一个service看看效果,先建一个service文件夹,在service文件夹下新建一个userServer.js文件
const Service = require('egg').Service;
class userServer extends Service {
async register(params) {
const ctx = this.ctx;
try {
// 我这里没有做复杂的业务逻辑,注册直接存库,所以就调用下model里的insertUserInfo方法
const results = await ctx.model.UserModel.insertUserInfo(params);
return results;
} catch (err) {
ctx.body = JSON.stringify(err);
}
}
}
module.exports = userServer;
4. Model
egg-sequelize会自动将sequelize实例挂载到app.model上面,然后静态方法和属性则会直接被绑定到app上,通过app.Sequelize进行获取。
model层作为MVC的最底层,需要注意到数据模型的pure,model文件也应该是纯净的,这个文件里面应该是和数据库中的表一一对应,一个model文件对应一个DB中的表,这个文件中不应该包含任何和逻辑相关的代码,应该完全是数据模型的定义。
下面我们自定义一个model看看效果,先建一个model文件夹,再在model文件夹下新建一个UserModel.js文件
'use strict';
module.exports = app => {
const Sequelize = app.Sequelize;
const UserModel = app.model.define('user', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
},
username: {
type: Sequelize.STRING,
},
password: {
type: Sequelize.STRING,
},
}, {
tableName: 'user',
timestamps: true,
underscoredAll: true
});
/**
* 插入数据
*/
UserModel.insertUserInfo = (params) => {
return new Promise((resolve, reject) => {
UserModel.create({
username: params.username,
password: params.password,
}).then(results => {
// console.log("UserModel.updateUserInfo-results===", results);
if (results && results.dataValues) {
resolve(results.dataValues);
} else {
reject(false);
}
}).catch((err) => {
console.log('UserModel.updateUserInfo-err===', err);
reject(err);
});
});
};
return UserModel;
};
sequelize使用原始查询方法写SQL语句使用Sequlize提供的工具函数sequelize.query来实现。
上面的插入方法用SQL写如下:
UserModel.insertUserInfo = (params) => {
return new Promise((resolve, reject) => {
let sql = `INSERT INTO user (username, password,created_at, updated_at) VALUES ('${params.username}', '${params.password}', now(), now())`;
app.model.query(sql).spread((results, metadata) => {
// console.log("UserModel.updateUserInfo-results===", results);
if (results && results.dataValues) {
resolve(results.dataValues);
} else {
reject(false);
}
}).catch(err => {
console.log('UserModel.insertUserInfo-err======', err);
reject(err);
});
});
};
sequelize的确很便捷,提供的方法也比较多,我这里就拿一个举例,其他的大家可以去网上找文章,很多的。
如果要使用连接MongoDB的话可以参考我的一篇博客eggJS 连接和使用Mongodb。
咱们调用一下,看下接口返回的结果,这里推荐一个工具postman。
应用部署
-
在该文件下打包,生成tgz文件:tar -zcvf …/FileName.tgz
-
环境部署(建议下载Xshell客户端,当然别的工具都可以,根据个人喜好~~~)
a.进入要部署的服务器对应文件夹下,cd 等等;
b.//创建文件 mkdir 文件名称;
c.打开压缩包: rz -be;
d.解包:tar zxvf FileName.tar;
e.移除压缩包: rm -rf FileName.tar -
然后就可以启动啦:npm start即可。
本节demo:https://gitee.com/netbuggang/egg-example
参考文献:
https://eggjs.org/zh-cn/tutorials/index.html
https://www.jianshu.com/p/6b04330ee4a1
https://blog.csdn.net/qq_35954591/article/details/78803859