控制器
控制器作用
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
:读取和设置 cookiectx.session
:读取和设置 sessionctx.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