关于node.js:🚀eggjs实战10天入门第2天🚀-项目目录的作用

课程疏导

  1. 🚀【eggjs实战10天入门-第1天】🚀—— 搭建我的项目
  2. 🚀【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

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理