Skip to main content

自定义装饰器

自定义装饰器在Summer中是一项强大的功能,你可用它来拦截请求,验证登录信息,提取请求信息,修改返回code...

创建装饰器接口

创建方法可标记在哪里用途
createParamDecorator使用在Controller接口方法里提取请求数据
createMethodDecorator使用在方法上方法拦截
createClassDecorator使用在类上拦截类中所有方法
createClassAndMethodDecorator使用在类或方法上拦截类中所有方法或单一方法
createPropertyDecorator使用在属性上属性注入

创建方法参数装饰器

export const [DecoratorName] = createParamDecorator(
(ctx?, paramName?, arg1?, arg2?,...) => {
return [Value]
}
)

DecoratorName 装饰器名字
ctx 请求上下文
paramName 在方法中的参数名字
arg1, arg2... 自定义参数 @DecoratorName(arg1,arg2,...)

获取前端APP发来的头部'app-version'信息
import { Controller, createParamDecorator, Get } from '@summer-js/summer'

export const AppVersion = createParamDecorator((ctx) => {
return ctx.request.headers['app-version']
})

@Controller
export class AppVersionController {
@Get('/app/version')
async version(@AppVersion version) {
return version
}
}
解析JWT Token
import { Controller, createParamDecorator, Get } from '@summer-js/summer'
import jwt from 'jsonwebtoken'

export const Uid = createParamDecorator((ctx) => {
const token = ctx.request.headers['authentication']
try {
const decoded = jwt.verify(token, 'xxxxxxxx')
return decoded.uid
} catch (e) {}
return null
})

@Controller
export class JWTController {
@Get('/userinfo')
userinfo(@Uid uid?: number) {
return uid
}
}

创建类/方法装饰器

// 只可以用在方法上
export const [DecoratorName] = createMethodDecorator(
async (ctx?, invokeMethod? , arg1?, arg2?,...) => {
return await invokeMethod(ctx.invocation.params)
}
);

// 只可以用在类上,标记会拦截所有方法
export const [DecoratorName] = createClassDecorator(
async (ctx?, invokeMethod? , arg1?, arg2?,...) => {
return await invokeMethod(ctx.invocation.params)
}
);

// 既可以用在类上,也可以在单一方法上,标记会拦截所有方法
export const [DecoratorName] = createClassAndMethodDecorator(
async (ctx?, invokeMethod? , arg1?, arg2?,...) => {
return await invokeMethod(ctx.invocation.params)
}
);

DecoratorName 装饰器名字
ctx 请求上下文
invokeMethod 被执行的方法
arg1, arg2... 自定义参数 @DecoratorName(arg1,arg2,...)

开发一个 @RequireLogin 装饰器
import { Controller, createClassAndMethodDecorator, Get, Put } from '@summer-js/summer'
import jwt from 'jsonwebtoken'

export const RequireLogin = createClassAndMethodDecorator(async (ctx, invokeMethod?) => {
const token = ctx.request.headers['authentication']
try {
jwt.verify(token, 'xxxxxxxx')
return await invokeMethod(ctx.invocation.params)
} catch (e) {
ctx.response.statusCode = 401
ctx.response.body = 'Unauthorized'
}
})

@Controller
@RequireLogin
export class LoginController {
@Get('/me')
info() {}

@Put('/me')
update() {}
}

@Controller
export class LoginController2 {
@Get('/users/:id')
userInfo() {}

@RequireLogin
@Put('/userinfo')
update() {}
}

创建属性装饰器

export const [DecoratorName] = createPropertyDecorator(
(config?, propertyName? , arg1?, arg2?,...) => {
return [Value]
}
);

DecoratorName 装饰器名字
config 当前的配置
propertyName 属性的名字
arg1, arg2... 自定义参数 @DecoratorName(arg1,arg2,...)

注入MySQL配置
import { Controller, createPropertyDecorator, Get } from '@summer-js/summer'

export const MySQLConfig = createPropertyDecorator((config) => {
return config['MySQL_CONFIG']
})

@Controller
export class ConfigInjectController {
@MySQLConfig
mysqlConfig

@Get('/mysql-host')
host() {
return this.mysqlConfig.host
}
}
注入城市列表
import { Controller, createPropertyDecorator, Get } from '@summer-js/summer'

export const CityList = createPropertyDecorator(() => {
return ['Shanghai', 'Tokyo', 'New York City']
})

@Controller
export class CityListController {
@CityList
cityList

@Get('/cities')
list() {
return this.cityList
}
}

更多例子

改变HTTP请求返回码

import { Controller, createMethodDecorator, Get } from '@summer-js/summer'

export const ResponseCode = createMethodDecorator(
async (ctx, invokeMethod, code: number) => {
ctx.response.statusCode = code
return await invokeMethod(ctx.invocation.params)
}
)

@Controller
export class ResponseCodeController {
@ResponseCode(404)
@Get('/dog')
userInfo() {
return '404 小狗走丢了'
}
}

缓存返回值

import { AutoInject, Controller, createMethodDecorator, Get, Logger, PathParam, Service } from '@summer-js/summer'
import md5 from 'md5'

const CACHE = {}
export const Cache = createMethodDecorator(async (ctx, invokeMethod, cacheTime: number) => {
const callParamHash = md5(JSON.stringify(ctx.invocation))
if (CACHE[callParamHash] === undefined) {
CACHE[callParamHash] = await invokeMethod(ctx.invocation.params)
Logger.info('Cache ' + CACHE[callParamHash] + ' in ' + cacheTime + 's')
if (cacheTime) {
setTimeout(() => {
CACHE[callParamHash] = undefined
Logger.info('Clear Cache')
}, cacheTime)
}
}
return CACHE[callParamHash]
})

@Service
export class CacheService {
@Cache
async cache(id) {
return id + ':' + Date.now()
}
}

@Controller
export class CacheController {
cacheService: CacheService

@Get('/cache/:id')
@Cache(1000)
async api(@PathParam id) {
return id + ':' + Date.now()
}

@Get('/cache2/:id')
async api2(@PathParam id) {
return this.cacheService.cache(id)
}
}

下载文件

import { Controller, createMethodDecorator, Get } from '@summer-js/summer'

export const DownLoadFile = createMethodDecorator(
async (ctx, invokeMethod, fileName: string) => {
ctx.response.headers['Content-Type'] = 'application/octet-stream'
ctx.response.headers['Content-Disposition'] = `attachment; filename="${fileName}"`
return await invokeMethod(ctx.invocation.params)
}
)

@Controller
export class DownloadController {
@DownLoadFile('hello.txt')
@Get('/download')
download() {
return 'Hello Summer'
}
}