Skip to content

自定义装饰器

自定义装饰器本质就是个函数

注意

  1. 对已知得装饰器调用进行二次封装

  2. 对多个装饰器合并

  3. 参数装饰器

(一) 对已知得装饰器二次封装

新建一个aaa.decorator.ts 文件

ts
import { SetMetadata } from "@nestjs/common";

export const Aaa = (...args: string[]) => SetMetadata("aaa", args);

我在这里面调用了 SetMetadata 相当于设置权限

新建一个守卫aaa.guard.ts 文件

ts
import {
  CanActivate,
  ExecutionContext,
  Inject,
  Injectable,
} from "@nestjs/common";
import { Observable } from "rxjs";
import { Reflector } from "@nestjs/core";
@Injectable()
export class AaaGuard implements CanActivate {
  // 注入
  @Inject(Reflector)
  reflector: Reflector;

  canActivate(
    context: ExecutionContext
  ): boolean | Promise<boolean> | Observable<boolean> {
    // 函数里面注入以后 获取值
    console.log(this.reflector.get("aaa", context.getHandler()));
    // 类里面获取值
    console.log(this.reflector.get("aaa", context.getClass()));
    // 这里返回 true
    return true;
  }
}

守卫里面获取到我设置得权限是 aaa 的值.这里注意守卫里面的aaa与 SetMetadata 里面的aaa一致

在控制器里面使用

ts
  @Get()
  @Aaa('admin')
  // 替换 @SetMetadata('aaa', 'admin')
  @UseGuards(AaaGuard)
  findAll() {
    return this.aaaService.findAll();
  }

这样就能打印出['admin']

(二) 对多个装饰器合并

有的时候装饰器太多了.我们需要合并一个装饰器这里就需要用到 applyDecorators

新建一个bbb.decorator.ts 文件

ts
import { applyDecorators, UseGuards, Get } from "@nestjs/common";
import { Aaa } from "./aaa.decorator";
import { AaaGuard } from "./aaa.guard";
// 这里开始合并
export function BBB(path, role) {
  return applyDecorators(Get(path), Aaa(role), UseGuards(AaaGuard));
}

在控制器里面使用

ts
  @BBB('', 'admin2')
  findAll() {
    return this.aaaService.findAll();
  }

在访问的时候就是打印出['admin2']

(三) 参数装饰器

我们可以封装一个参数装饰器.在控制器里面使用获取到 header,query,ip 等等

获取到指定的头部信息

  • (1) 新建一个文件ccc.decorator.ts
ts
import { createParamDecorator, ExecutionContext } from "@nestjs/common";

export const CCC = createParamDecorator(
  (data: string, ctx: ExecutionContext) => {
    const request = ctx.switchToHttp().getRequest();
    return data ? request.headers[data.toLowerCase()] : request.headers;
  }
);
  • (2) 在控制器里面使用
ts
  @Get()
  findAll(@CCC('Accept') headerAccept) {
    console.log(headerAccept);
    return this.aaaService.findAll();
  }

这样就会打印出头部

获取参数

  • (1) 新建一个文件ddd.decorator.ts
ts
import { createParamDecorator, ExecutionContext } from "@nestjs/common";

export const MyQuery = createParamDecorator(
  (data: string, ctx: ExecutionContext) => {
    const request = ctx.switchToHttp().getRequest();
    return request.query[data];
  }
);
  • (2) 在控制器里面使用
ts
  @Get()
  findAll(@MyQuery('id') query) {
    console.log('接受得参数' + query);
    return this.aaaService.findAll();
  }

注意

  1. 参数装饰器同样可以使用管道来验证

  2. 比如 @MyQuery('id',new ParseIntPipe()) query 这样就可以验证参数是否为数字