快速初始化
我們推薦直接使用腳手架,只需幾條簡單指令,即可快速生成項目:
$ 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