课程疏导
- 🚀【eggjs实战10天入门-第1天】🚀—— 搭建我的项目
-
🚀【eggjs实战10天入门-第2天】🚀—— controller、service和config(本篇)
本节指标
相熟config/router/controller/service各自的作用
1、路由(Router)
1.1、路由和controller的关系
// router.js
module.exports = app => {
const { router, controller } = app;
router.get('/hello', controller.base.index);
};
// base.js
const { Controller } = require('egg')
class BaseController extends Controller {
async index() {
this.ctx.body = {
data: "hello it's me"
}
}
}
module.exports = BaseController
再上一节中咱们在router.js中写了这样的代码,他代表的含意就是当用户执行 GET /hello
时,app/controller文件夹下的base.js 这个外面的 index 办法就会执行。
那么既然有get办法,必定就有post办法,del办法等。
然而在实在的场景中,咱们必定不会只用/hello这种比拟中二的申请形式。咱们须要接管前端传递过去的参数。比方获取某个id的具体信息,那咱们如何获取参数呢
1.2、参数的传递
1.2.1、Query String 形式
也就是罕用的xxx?a=1&b=2这种Query传参形式
咱们新增一条路由,/getInfo, 这时当拜访/getInfo时,就会触发base.js的getInfo办法
// app/router.js
module.exports = app => {
const { router, controller } = app;
router.get('/hello', controller.base.index);
app.router.get('/getInfo', controller.base.getInfo);
};
咱们新增一个getInfo办法。当申请走到getInfo函数时,咱们从this中获取ctx,也是本次申请的一个上下文context,外面蕴含着本次申请的数据,如参数,header,中间件挂载的一些罕用数据
const { Controller } = require('egg')
class BaseController extends Controller {
index() {
this.ctx.body = {
data: "hello it's me"
}
}
getInfo () {
const { ctx } = this
console.log('ctx.query', ctx.query)
ctx.body = {
query: ctx.query
}
}
}
module.exports = BaseController
当咱们发动申请,
http://127.0.0.1:7001/getInfo?a=1&b=1
,这时通过ctx.query就能拿到参数对象,{ a: '1', b: '1' }
1.2.1、Query String 形式
当参数只有一到2个的时候,咱们更趋向于应用
咱们新增第三条路由,getUser/:name, 这时当拜访/getUser/:name时,就会触发base.js的getUser办法
module.exports = app => {
const { router, controller } = app;
router.get('/hello', controller.base.index);
app.router.get('/getInfo', controller.base.getInfo);
app.router.get('/getUser/:name', controller.base.getUser);
};
const { Controller } = require('egg')
class BaseController extends Controller {
index() {
this.ctx.body = {
data: "hello it's me"
}
}
getInfo () {
const { ctx } = this
console.log('ctx.query', ctx.query)
ctx.body = {
query: ctx.query
}
}
getUser () {
const { ctx } = this
console.log('ctx.params', ctx.params)
ctx.body = {
params: ctx.params
}
}
}
module.exports = BaseController
当咱们发动申请,
http://127.0.0.1:7001/getUser/100
,这时通过ctx.params就能拿到参数,{ name: '100' }
2、控制器(Controller)
2.1、再次梳理router和Controller的关系
所有的 Controller 文件都必须放在app/controller
目录下,层级能够是多级。
eggjs就能够依据这个约定,把对应的文件名会转换为驼峰格局。
所以当咱们申明路由router.get('/hello', controller.base.index)
时, controller.base就是对应的app/controller/base.js文件
app/controller/base.js => app.controller.base
module.exports = app => {
const { router, controller } = app;
router.get('/hello', controller.base.index);
app.router.get('/getInfo', controller.base.getInfo);
app.router.get('/getUser/:name', controller.base.getUser);
};
2.2、controller的性能
官网文档有一句话,Controller负责解析用户的输出,解决后返回相应的后果
换句话说, Controller层不解决具体的业务逻辑
咱们我的项目中的controller类继承于 egg.Controller
,
this.ctx
: 以后申请的上下文Context的实例,能够拿到各种便捷属性和办法。this.app
: 以后利用Application的实例,能够拿到全局对象和办法。this.service
:利用定义的Service,能够调用业务逻辑层。-
this.config
:利用运行时的配置。2.3、controller的承当的责任
- 获取用户通过 HTTP 传递过去的申请参数。
- 校验、组装参数
- 调用 Service 进行业务解决,解决转换 Service 的返回后果,让它适应用户的需要。
- 通过 HTTP 将后果响应给用户。
2.4、controller调用service办法
同controller的约定一样,service须要在app下创立service文件夹,而后在这个文件夹外面咱们创立文件base_info.js(咱们验证下eggjs是不是真的会把对应的文件名会转换为驼峰格局。)
在controller调用service下baseInfo的办法
const { Controller } = require('egg')
class BaseController extends Controller {
getUser () {
const { ctx, service } = this
const { name } = ctx.params;
const userInfo = service.baseInfo.getUserInfo({
name
})
ctx.body = userInfo
}
}
module.exports = BaseController
service文件夹下的base_info, eggjs会将该文件挂载到service.baseInfo下
const { Service } = require('egg')
class BaseService extends Service {
getUserInfo({name}) {
const userInfo = {
name: `我的name是${name}`
}
return userInfo
}
}
module.exports = BaseService;
咱们执行
http://127.0.0.1:7001/getUser/100
, 失去`{
"name": "我的name是100"
}`
3、服务(Service)
- 能够让Controller中的比拟纯正
- service能够被多个Controller反复调用, 能够使更多的业务逻辑
官网的说法是
Service
不是单例,是 申请级别 的对象,它挂载在Context
上的。
Service
是提早实例化的,仅在每一次申请中,首次调用到该Service
的时候,才会实例化。因而,无需放心实例化的性能损耗,通过咱们大规模的实践证明,能够忽略不计。
4、config配置
在咱们开发的时候,常常会遇到一些配置。比方如果咱们对接七牛云的图片上传,咱们就须要用到七牛云提供的cdn配置
而后咱们从新创立新的router,controller和service,正好温习下后面讲到的货色
4.1、读取config配置
app/config/config.default.js 咱们减少一个cdn配置
module.exports = appInfo => {
const config = {}
config.keys = appInfo.name + '_1672833991623_8554';
config.cdn = {
AK: 'test',
SK: 'test',
BucketName: 'xxx-xxx',
DoMain: 'https://xxx.xxx.com'
}
config.security = {
csrf: {
enable: true,
headerName: 'token',
},
};
return {
...config
};
};
app/router.js,新增uploadImg路由,指向到qiniu.js的upload办法
module.exports = app => {
const { router, controller } = app;
router.get('/hello', controller.base.index);
router.get('/getInfo', controller.base.getInfo);
router.get('/getUser/:name', controller.base.getUser);
router.post('/uploadImg', controller.qiniu.upload);
};
app/controller/qiniu.js
const { Controller } = require('egg')
class QiniuController extends Controller {
upload () {
const { ctx, service } = this
const info = service.qiniu.upload()
ctx.body = info
}
}
module.exports = QiniuController
app/service/qiniu.js
const { Service } = require('egg')
class QiniuService extends Service {
upload() {
const { app } = this;
const { cdn } = app.config
return {
data: cdn
}
}
}
module.exports = QiniuService;
在这个例子中,咱们就能够看到,app.config可就能够读取到咱们的配置文件的信息
4.2、不同环境下的配置
在下面咱们读取到了配置文件,然而大家有没有想过,不同环境下的配置文件很可能是不同的
比方开发环境下的cdn和测试环境/生产环境的cdn配置是齐全不同的。
如果咱们去手动的更改配置文件显然显得有些中二,eggjs为咱们提供了多环境配置,也就是在不同的环境下会加载不同的配置文件,咱们具体演示下
package.json的脚本配置,通过–env能够指定环境,就会主动加载对应的文件,比方咱们改为
egg-bin dev --env=prod
,这时就会加载config.prod.js。这样咱们只须要批改环境就能够应用该环境对应的配置了。config.default.js 为默认的配置文件,所有环境都会加载这个配置文件,个别也会作为开发环境的默认配置文件。
当指定 env 时会同时加载默认配置和对应的配置(具名配置)文件,具名配置和默认配置将合并(应用extend2深拷贝)成最终配置,具名配置项会笼罩默认配置文件的同名配置。如 prod 环境会加载 config.prod.js 和 config.default.js 文件,config.prod.js 会笼罩 config.default.js 的同名配置。
整个配置相似于webpack的配置的merge操作
config
|- config.default.js
|- config.test.js
|- config.prod.js
"scripts": {
"dev": "egg-bin dev --env=prod"
}
本节源码github
tag为v1.1.0
下节预报
下节课开始对接mysql
发表回复