@zenweb/controller
v6.6.1
Published
Zenweb Controller module
Readme
zenweb 控制器与路由发现
zenweb 模块 - 控制器与路由发现
演示
简单使用
在 src/controller 目录下新建一个文件 simple.ts
import { Context, Middleware, Next } from '@zenweb/core';
import { Injectable, Init } from '@zenweb/inject';
import { All, Controller, Get, Mapping, Post } from '@zenweb/controller';
async function demoMiddleware(ctx: Context, next: Next) {
console.log('demo middleware before');
await next();
console.log('demo middleware after');
}
function funcMiddleware(name: string): Middleware {
return async function (ctx, next) {
console.log(`middleware [${name}] before`);
await next();
console.log(`middleware [${name}] after`);
}
}
// 控制器全局中间件
// 控制器注解并不是必须的,只有需要进行特定配置时使用
@Controller({
middleware: demoMiddleware,
})
export class Simple {
// 构造器函数中的参数都是自动注入
constructor(
private ctx: Context,
) {}
@Init // 控制器每次被请求时候都会执行
init(ctx: Context) { // ctx 变量会自动注入
console.log('init:', ctx.path);
}
@Get()
index(ctx: Context) { // 在方法中的变量都是自动注入的
console.log('index:', ctx.ip);
return 'index:' + this.ctx.ip;
}
// 映射一个路径, 不指定参数默认为 `GET /方法名`
@Get()
@Get('/s2', funcMiddleware('s2')) // 给路由添加中间件
simple() {
console.log('simple')
return 'simple';
}
// 一次性定义多个方法*路径*中间件
@Mapping({
method: ['POST', 'GET'],
path: ['/aaa', '/bbb'],
middleware: funcMiddleware('aaa'),
})
aaa() {
return 'aaa';
}
@Post(funcMiddleware('post')) // 第一个参数可以是路径,也可以是中间件
post() {
return 'POST method';
}
@All(funcMiddleware('all-1'), funcMiddleware('all-2')) // 使用多个中间件
all() {
return 'any method';
}
}
@Injectable('request') // request 级别的中间件为默认值,可以不用指定,与直接使用 @Injectable 相同
export class RequestController {
@Get()
req() {
return 'req';
}
}
@Controller({ prefix: '/singleton' })
@Injectable('singleton') // 标记为单例类型,class 只会被初始化一次,且不销毁
export class SingletonController {
i = 0; // 单例变量不会被销毁
@Get()
index() {
return this.i++; // 每次请求都会 +1
}
}:::tip 注意
控制器方法中 return 数据如果需要统一处理需要安装 @zenweb/result 模块,否则 return 数据会被设置到 ctx.body 上
:::
使用中间件
import { Context, Next, Get, Controller } from 'zenweb';
// 定义一个中间件处理函数
function actionLog(ctx: Context, next: Next) {
console.log('actionLog middleware')
return next();
}
export class Controller {
// 方法上的中间件
@Get(actionLog)
simple() {
return 'simple';
}
}
// 控制器中间件,作用与所有控制器方法上
@Controller({
middleware: actionLog,
})
export class Controller2 {
@Get()
simple() {
return 'simple';
}
}自动路径映射规则
如果开启 autoControllerPrefix 功能,则会自动为控制器方法添加路径前缀,等同于自动给控制器类添加 @Controller({ prefix }) 选项
文件名规则
控制器扫描目录为 src/controller 下的文件结构
| 文件名 | 映射路径 | 说明 |
| --- | --- | --- |
| index.ts | / | index 名称为特殊名称,代表首页,所以默认为根路径 / |
| user.ts | /user | 非 index 文件名都会被映射为路径名 |
| user/index.ts | /user | 同理即使是子目录下面的 index 文件名会当成子目录的根路径处理 |
| user/profile.ts | /user/profile | 子目录下面的文件名会当成子目录的子路径处理 |
prefix 的处理规则
映射路径会自动修改控制器的 prefix 配置项,但是有如下几种特殊的处理规则:
prefix值没有设置时直接使用自动路径值- 已经设置的
prefix值如果开头为/(例如:prefix: '/admin')则不做任何处理(忽略) - 已经设置的
prefix值没有使用/开头(例如:prefix: 'admin'),则会在原来已经设置的结果前添加自动路径值。例如自动路径为/manage/some控制器值prefix: 'admin'则会变为prefix: '/manage/some/admin'
控制器内方法映射规则
即使没有开启 autoControllerPrefix 功能也不会影响控制器内方法的映射规则
class SomeController {
@Get() // 默认映射路径为 /
index() {}
@Get() // 默认映射路径为 /detail
detail() {}
@Get() // 默认映射路径为 /detail_by_id
detail_by_id() {}
@Get() // 默认映射路径为 /detail/:id
'detail/:id'(ctx: Context) { return ctx.params.id }
}使用技巧
统一管理后台接口
例如后台管理接口中需要统一添加 /admin 作为前缀,并且需要验证管理员身份,则可以这样使用
import { Mapping, Middleware, RouterMethod, RouterPath } from 'zenweb';
/**
* 管理员验证中间件
*/
export function adminRequired(): Middleware {
return function (ctx, next) {
if (!ctx.admin) {
fail('没有权限');
}
return next();
}
}
s
/**
* 管理后台路径统一映射
*/
export function AdminMapping(method?: RouterMethod, path?: RouterPath, ...middleware: Middleware[]) {
return Mapping({
method,
prefix: '/admin',
path,
middleware: [adminRequired(), ...middleware],
});
}import { Context, Next, Mapping, Controller } from 'zenweb';
import { AdminMapping } from './_helper';
export class IndexController {
// 等同于 @Mapping({ path: '/admin/', method: 'GET', middleware: [adminRequired()] })
@AdminMapping()
index() {
return 'admin index';
}
// 等同于 @Mapping({ path: '/admin/create_user', method: 'POST', middleware: [adminRequired()] })
@AdminMapping('POST')
create_user() {
return 'create user';
}
}