Skip to content

控制器

控制器作用

Controller 负责解析用户的输入,处理后给前端返回相应的结果。

框架推荐的 Controller 层主要流程是:首先对用户通过 HTTP 传递过来的请求参数进行处理(校验、转换),然后调用对应的 service 方法处理业务,在必要时把 Service 的返回结果处理转换,使之满足用户需求,最后通过 HTTP 将结果响应给用户。具体步骤如下:

  • 获取用户通过 HTTP 传递过来的请求参数。
  • 校验、组装参数。
  • 调用 Service 进行业务处理,必要时处理转换 Service 的返回结果,让它适应用户的需求。
  • 通过 HTTP 将结果响应给用户。

简单案例

js
const { Controller } = require("egg");
class HomeController extends Controller {
  async index() {
    const { ctx } = this;
    ctx.body = "hi, egg";
  }
}
module.exports = HomeController;
  • 真实案例
js
const { Controller } = require("egg");
class PostController extends Controller {
  async create() {
    const { ctx, service } = this;
    const createRule = {
      title: { type: "string" },
      content: { type: "string" },
    };
    // 校验和组装参数
    ctx.validate(createRule);
    const data = Object.assign(ctx.request.body, {
      author: ctx.session.userId,
    });
    // 调用 Service 进行业务处理
    const res = await service.post.create(data);
    // 响应客户端数据
    ctx.body = { id: res.id };
    ctx.status = 201;
  }
}
module.exports = PostController;

ctx 对象

在 Controller 中通过 this.ctx 可以获取上下文对象,方便获取和设置相关参数,例如:

  • ctx.query:URL 中的请求参数(忽略重复 key)
  • ctx.quries:URL 中的请求参数(重复的 key 被放入数组中)
  • ctx.params:Router 上的命名参数
  • ctx.request.body:HTTP 请求体中的内容
  • ctx.request.files:前端上传的文件对象
  • ctx.getFileStream():获取上传的文件流
  • ctx.multipart():获取 multipart/form-data 数据
  • ctx.cookies:读取和设置 cookie
  • ctx.session:读取和设置 session
  • ctx.service.xxx:获取指定 service 对象的实例(懒加载)
  • ctx.status:设置状态码
  • ctx.body:设置响应体
  • ctx.set:设置响应头
  • ctx.redirect(url):重定向
  • ctx.render(template):渲染模板

继承基类

举例

js
// app/core/base_controller.js
const { Controller } = require("egg");
class BaseController extends Controller {
  get user() {
    return this.ctx.session.user;
  }
  success(data) {
    this.ctx.body = { success: true, data };
  }
  notFound(msg) {
    this.ctx.throw(404, msg || "not found");
  }
}
module.exports = BaseController;
  • 然后让所有的控制器继承这个自定义的 BaseController
js
// app/controller/post.js
const Controller = require("../core/base_controller");
class PostController extends Controller {
  async list() {
    const posts = await this.service.listByUser(this.user);
    this.success(posts);
  }
}

静态类

静态类就是自己封装了方法,通过 require 引入进来

  • app/utils 新建一个 tool.js 文件
js
class ResponsedataController {
  static async succss(data = null, message = "success", code = 200) {
    return {
      code,
      message,
      data,
    };
  }
}
module.exports = ResponsedataController;
  • 在控制器中使用
js
const { Controller } = require("egg");
const Tools = require("../../utils/tool");
class PostController extends Controller {
  async list() {
    // 业务逻辑
    const posts = await this.service.listByUser(this.user);
    this.ctx.body = Tools.success(posts, "success", 200);
  }
}

扩展

egg 框架提供了下面几个扩展点:

  • Application: Koa 的全局应用对象(应用级别),全局只有一个,在应用启动时被创建
  • Context:Koa 的请求上下文对象(请求级别),每次请求生成一个 Context 实例
  • Request:Koa 的 Request 对象(请求级别),提供请求相关的属性和方法
  • Response:Koa 的 Response 对象(请求级别),提供响应相关的属性和方法
  • Helper:用来提供一些实用的 utility 函数
bash

所有的扩展必须写到app/extend目录下,并且文件名必须以`扩展名.js`结尾,例如:
application.js、context.js、request.js、response.js、helper.js

Application 扩展

  • 新建 app/extend/application.js 文件

  • 扩展有两类:属性扩展和方法扩展

js
// app/extend/application.js
module.exports = {
  // 方法扩展
  currentTime() {
    return getTime();
  },
  // 属性扩展
  get timeProp() {
    return getTime();
  },
};

function getTime() {
  let now = new Date();
  let year = now.getFullYear();
  let month = now.getMonth() + 1;
  // 月份要是小于10,前面补0
  if (month < 10) {
    month = "0" + month;
  }
  let date = now.getDate();
  //  日期要是小于10,前面补0
  if (date < 10) {
    date = "0" + date;
  }
  let hour = now.getHours();
  // 时间要是小于10,前面补0
  if (hour < 10) {
    hour = "0" + hour;
  }
  let minute = now.getMinutes();
  // 分钟要是小于10,前面补0
  if (minute < 10) {
    minute = "0" + minute;
  }
  let second = now.getSeconds();
  // 秒数要是小于10,前面补0
  if (second < 10) {
    second = "0" + second;
  }
  return `${year}-年${month}月-${date}日 ${hour}:${minute}:${second}`;
}
  • 在控制器中使用
js
const { Controller } = require("egg");

class ExtendController extends Controller {
  async applicationindex() {
    const { ctx, app } = this;
    const method_result = app.currentTime();
    const attr = app.timeProp;
    ctx.body = {
      code: 200,
      data: {
        time: method_result,
        time2: attr,
      },
    };
  }
}

module.exports = ExtendController;

Context 扩展

  • 新建 app/extend/context.js 文件

  • 扩展有两类:属性扩展和方法扩展

js
// app/extend/context.js
module.exports = {
  params(key) {
    const method = this.request.method;
    if (method === "GET") {
      return key ? this.query[key] : this.query;
    } else {
      return key ? this.request.body[key] : this.request.body;
    }
  },
};
  • 在控制器中使用
js
const { Controller } = require("egg");

class ExtendController extends Controller {
  async contextindex() {
    const { ctx } = this;
    const params = ctx.params("id");
    console.log(params);
    ctx.body = params;
  }
}

module.exports = ExtendController;
  • 路由
js
module.exports = (app) => {
  const { router, controller } = app;
  // router
  const middleRouter = router.namespace("/extend");
  middleRouter.get("/application", controller.extend.extend.applicationindex);
  middleRouter.get("/context", controller.extend.extend.contextindex);
};
  • 使用
bash
http://127.0.0.1:7001/extend/context?id=5

Helper 扩展

  • 新建 app/extend/helper.js 文件

  • 扩展有两类:属性扩展和方法扩展

js
// app/extend/helper.js
module.exports = {
  base64Encode(str = "") {
    return Buffer.from(str).toString("base64");
  },
};
  • 在控制器中使用
js
const { Controller } = require("egg");

class ExtendController extends Controller {
  async helperindex() {
    const { ctx } = this;
    const testbase64 = ctx.helper.base64Encode("hello world");
    ctx.body = testbase64;
  }
}

module.exports = ExtendController;
  • 路由
js
module.exports = (app) => {
  const { router, controller } = app;
  // router
  const middleRouter = router.namespace("/extend");
  middleRouter.get("/application", controller.extend.extend.applicationindex);
  middleRouter.get("/context", controller.extend.extend.contextindex);
  middleRouter.get("/helper", controller.extend.extend.helperindex);
};
  • 使用
bash
http://127.0.0.1:7001/extend/helper

request 扩展

  • 新建 app/extend/request.js 文件

  • 扩展有两类:属性扩展和方法扩展

js
// app/extend/request.js
module.exports = {
  get token() {
    return this.get("token");
  },
};
  • 在控制器中使用
js
const { Controller } = require("egg");

class ExtendController extends Controller {
  async requestindex() {
    const { ctx } = this;
    const token = ctx.request.token;
    ctx.body = {
      status: 200,
      body: {
        token,
      },
    };
  }
}

module.exports = ExtendController;
  • 路由
js
module.exports = (app) => {
  const { router, controller } = app;
  // router
  const middleRouter = router.namespace("/extend");
  middleRouter.get("/application", controller.extend.extend.applicationindex);
  middleRouter.get("/context", controller.extend.extend.contextindex);
  middleRouter.get("/helper", controller.extend.extend.helperindex);
  middleRouter.get("/request", controller.extend.extend.requestindex);
};
  • 使用
bash
请求头部带token
http://127.0.0.1:7001/extend/request

response 扩展

  • 新建 app/extend/response.js 文件

  • 扩展有两类:属性扩展和方法扩展

js
// app/extend/request.js
module.exports = {
  set token(token) {
    return this.set("token", token);
  },
};
  • 在控制器中使用
js
const { Controller } = require("egg");

class ExtendController extends Controller {
  async responseindex() {
    const { ctx } = this;
    ctx.response.token = "ceshitoken";
    ctx.body = "newResponse";
  }
}

module.exports = ExtendController;
  • 路由
js
module.exports = (app) => {
  const { router, controller } = app;
  // router
  const middleRouter = router.namespace("/extend");
  middleRouter.get("/application", controller.extend.extend.applicationindex);
  middleRouter.get("/context", controller.extend.extend.contextindex);
  middleRouter.get("/helper", controller.extend.extend.helperindex);
  middleRouter.get("/request", controller.extend.extend.requestindex);
  middleRouter.get("/response", controller.extend.extend.responseindex);
};
  • 使用
bash
返回数据的头部里面就有token了
http://127.0.0.1:7001/extend/response