【nest系列】之 VO 的配置

前提摘要:

nest 有提供单独的方法可供 vo 对象转换,但下面我是写了一个 crud 基类,由于不同子类的 vo 不同,需要对其进行配置才有下面这种设计思路

实现流程

markdown 复制代码
【实现流程分析】
1. 数据流转过程
   CRUD装饰器 -> 配置元数据 -> Transform装饰器 -> 拦截器处理 -> 最终输出

2. 核心组件关系
   - CRUD装饰器:配置中心,管理VO映射关系
   - Transform装饰器:元数据存储,提供转换信息
   - Transform拦截器:执行转换,处理响应数据

流程分析

1. 装饰器实现-VO配置收集

swift 复制代码
interface CurdOptions {
// ... 其他配置
  vos?: {
    findOne?: Type<any>
    findAll?: Type<any>
    findPage?: Type<any>
    create?: Type<any>
    update?: Type<any>
  }
}

2. 元数据处理

javascript 复制代码
export const Crud = (options: CurdOptions) => <T extends CrudController>(Target: Type<T>) => {
  // 1. 保存CRUD配置到元数据
  Reflect.defineMetadata(CRUD_OPTIONS, options, Target);
  // 2. 获取配置信息
  const { enabled, vos } = Reflect.getMetadata(CRUD_OPTIONS, Target) as CurdOptions;
  // 3. 构建方法映射表
  if (vos) {
    const methodMap = {};
    for (const value of enabled) {
      const { name } = typeof value === 'string' ? { name: value } : value;
      if (vos[name]) {
        // 为每个启用的方法配置VO转换
        methodMap[name] = {
          VoType: vos[name],
          options: {
            excludeExtraneousValues: true,
            enableImplicitConversion: true
          }
        };
      }
    }
    // 4. 应用Transform装饰器
    if (Object.keys(methodMap).length > 0) {
      TransformMethodMap(methodMap)(Target);
    }
  }
}

3. Transform装饰器与元数据

3.1. 元数据存储机制

typescript 复制代码
// transform.decorator.ts
export const TRANSFORM_METHOD_MAP_KEY = 'transformMethodMap';

// 方法映射装饰器
export const TransformMethodMap = (methodMap: Record<string, any>) => {
  return SetMetadata(TRANSFORM_METHOD_MAP_KEY, methodMap);
}

3.2. 元数据结构示例

yaml 复制代码
{
  'findOne': {
    VoType: UserDetailVo,
    options: {
      excludeExtraneousValues: true,
      enableImplicitConversion: true
    }
  },
  'findAll': {
    VoType: UserListVo,
    options: {
      excludeExtraneousValues: true,
      enableImplicitConversion: true
    }
  }
}

4. 拦截器处理流程

4.1. 数据拦截与转换

kotlin 复制代码
@Injectable()
export class TransformInterceptor implements NestInterceptor {
  constructor(private reflector: Reflector) { }
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    return next.handle().pipe(
      map(data => {
        // 1. 获取当前执行上下文
        const handler = context.getHandler();
        const cls = context.getClass();
        // 2. 获取方法映射表
        const methodMap = this.reflector.get(TRANSFORM_METHOD_MAP_KEY, cls) || {};
        const methodName = handler.name;
        const config = methodMap[methodName];
        if (!config) return data;
        // 3. 获取转换配置
        const { VoType, options } = config;
        // 4. 执行数据转换
        return this.transformData(data, VoType, options);
      })
    );
  }
  // 5. 根据数据类型处理不同的转换场景
  private transformData(data: any, VoType: any, options: TransformOptions) {
    // 处理分页数据
    if (data?.list && Array.isArray(data.list)) {
      return this.handlePaginatedData(data, VoType, options);
    }
    // 处理数组数据
    if (Array.isArray(data)) {
      return this.handleArrayData(data, VoType, options);
    }
    // 处理单个对象
    return this.handleSingleData(data, VoType, options);
  }
}

4.2. 协作流程示例

  1. 控制器定义
scala 复制代码
@Crud({
  enabled: ['findOne', 'findAll', 'findPage'],
  vos: {
    findOne: UserDetailVo,
    findAll: UserListVo,
    findPage: UserPageVo
  }
})
export class UsersController extends CrudController {
  // 控制器方法
}
  1. 执行流程
    1. CRUD 装饰器初始化
      1. 收集 VO 配置
      2. 创建方法映射表
      3. 通过 TransformMethodMap 存储元数据
    1. 请求处理
      1. 方法执行,返回原数据
    1. 拦截器处理
      1. 获取当前方法的 VO 配置
      2. 根据数据类型选择转换策略
      3. 执行数据转换
      4. 返回转换后的数据

有不足的地方请多多指教!!!

相关推荐
一生躺平的仔1 天前
NestJS Swagger 使用说明文档
nestjs
plusone1 天前
【Nest指北系列-源码】(七)请求生命周期
nestjs
小山不高2 天前
nest中如何对typeorm 的repo设置总的center
nestjs
bug_marker15 天前
BullMq sleep job是否会阻塞worker中的其他的jobs
nestjs
濮水大叔21 天前
快来玩玩便捷、高效的Demo练习场
typescript·nodejs·nestjs
木西21 天前
Nest.js实战:构建聊天室的群聊与私聊模块
前端·后端·nestjs
LannyChung1 个月前
NestJS定时器之@Cron
nestjs
None3211 个月前
【NestJs】集成Prisma数据库配置
nestjs
濮水大叔1 个月前
你认为Vonajs提供的这些特性会比Nestjs更好用吗?
nodejs·nestjs