安装
npm i egg-init -g
egg-init egg-example --type=simple
cd egg-example
npm i
启动项目:
npm run dev
目录结构
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
路由
路由的写法:
// controller/news.js
const Controller = require('egg').Controller
class NewsController extends Controller{
async index(){
this.ctx.body = "news page"
}
}
module.exports = NewsController
// app.router.js
module.exports = app =>{
const {router,controller} = app
router.get('/news',controller.news.index)
}
get 传值
// news?q=123
let query = this.ctx.query
console.log(query) // {q:'123'}
动态路由
// newsdetail/859700
// app/router.js
router.get('/newsdetail/:id',controller.news.detail)
// controller/news.js
async detail(){
let params = this.ctx.params
console.log(params) // {id:"859700"}
this.ctx.body = "news detail"
}
模板引擎
egg-views-ejs
1.安装
npm install egg-views-ejs --save
2.配置
// config/plugin.js
module.exports = {
ejs:{
enable:true,
package:'egg-view-ejs'
}
}
// config/config.default.js
module.exports = appInfo =>{
const config = exports = {}
...
// 配置 ejs 模板引擎
config.view={
mapping:{
'.ejs':'ejs', // '.html':'ejs' 文件后缀可以修改成`.html`
}
}
return config
}
3.使用
// controller/news.js
const Controller = require('egg').Controller
class NewsController extends Controller{
async index(){
let msg ="news page"
let list = [{name:'frank',age:18},{name:'Bob',age:20},{name:'lily',age:22}]
await this.ctx.render('news.html',{msg,list})
}
}
module.exports = NewsController
// app.router.js
module.exports = app =>{
const {router,controller} = app
router.get('/news',controller.news.index)
}
// view/news.html
...
<%=msg%>
<%for(var i=0;i
- name:<%=list[i].name%> age:<%=list[i].age%>
<%}%>
...
静态资源
静态资源在egg 默认可以是访问的。比如在public/css
目录下有 style.css
,引入 css 文件
service
egg 中 数据都放在 service
里,方便管理,修改我们的代码,如下
// service/news.js
// ...
async list() {
let msg ="news page"
let list = [{ name: 'frank', age: 18 }, { name: 'Bob', age: 20 }, { name: 'lily', age: 22 }]
return {msg,list}
}
// ...
// controller/news.js
// ...
async index() {
let result = await this.ctx.service.news.list()
await this.ctx.render('news.html', result);
}
// ...
每一次用户请求,框架都会实例化对应的 Service 实例,由于它继承于 egg.Service,故拥有下列属性方便我们进行开发:
this.ctx
: 当前请求的上下文 Context 对象的实例,通过它我们可以拿到框架封装好的处理当前请求的各种便捷属性和方法。this.app
: 当前应用 Application 对象的实例,通过它我们可以拿到框架提供的全局对象和方法。this.service
:应用定义的 Service,通过它我们可以访问到其他业务层,等价于 this.ctx.service 。this.config
:应用运行时的配置项。this.logger
:logger 对象,上面有四个方法(debug,info,warn,error),分别代表打印四个不同级别的日志,使用方法和效果与 context logger 中介绍的一样,但是通过这个 logger 对象记录的日志,在日志前面会加上打印该日志的文件路径,以便快速定位日志打印位置。
service 命名规则
Service 文件必须放在 app/service 目录,可以支持多级目录,访问的时候可以通过目录名级联访问。
app/service/biz/user.js => ctx.service.biz.user // 推荐
app/service/sync_user.js => ctx.service.syncUser
app/service/HackerNews.js => ctx.service.hackerNews
中间件(Middleware)
编写一个简单的 auth 中间件,我们要在 app/middleware 目录下新建一个文件 auth.js
'use strict';
const url = require('url');
module.exports = options => {
return async function adminAuth(ctx, next) {
const pathName = url.parse(ctx.request.url).pathname;
if (ctx.session.userinfo) {
await next();
} else {
if (pathName === '/login') {
await next();
} else {
ctx.render('/login');
}
}
};
};
使用中间件,需要在 config.default.js
中配置
module.exports = appInfo => {
const config = exports = {};
config.middleware = [ 'auth' ];
return config;
};
通用配置
enable:控制中间件是否开启。
match:设置只有符合某些规则的请求才会经过这个中间件。
ignore:设置符合某些规则的请求不经过这个中间件。
enable
如果不需要 bodyParser 中间件,可以设置 enable
为 false
module.exports = {
bodyParser: {
enable: false,
},
};
match、ignore
match 和 ignore 支持的参数都一样,只是作用完全相反,match 和 ignore 不允许同时配置。
如果想让 auth
只对/admin
开头的 url 开启,可以配置 match
选项
module.exports = {
auth: {
match: '/admin',
},
};
连接数据库
以 mongodb 为例,安装 egg-mongoose
npm i egg-mongoose --save
config/plugin.js
中声明
exports.mongoose = {
enable: true,
package: 'egg-mongoose',
};
config/config.default.js
中连接数据库
module.exports = appInfo => {
const config = exports = {};
config.mongoose = {
client: {
url: 'mongodb://127.0.0.1:27017/egg-admin',
options: {
"useUnifiedTopology":true
}
},
};
return config;
};
在model
中配置集合
// model/user.js
module.exports = app => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const userSchema = new Schema({
username: { type: String },
password: { type: String },
mobile: { type: String },
email: { type: String },
status: { type: Number, default: 1 },
create_time: {
type: Number,
default: Date.now(),
}
});
return mongoose.model('User', userSchema, 'users');
};
使用
await ctx.model.User.find({})