【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. 返回转换后的数据

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

相关推荐
yuanlaile16 天前
做了 3 年后端才明白:学 NestJS 千万不要只学 API 语法,完整电商项目才是分水岭
typescript·nestjs·node.js 后端·nestjs实战
濮水大叔16 天前
NestJS Dynamic Providers 与 Cabloy/Vona Provider Scene:同接口多实现的两种装配哲学
typescript·node.js·nestjs
濮水大叔17 天前
Cabloy/Vona 如何避开 NestJS 的循环依赖问题:懒属性注入机制源码解析
typescript·node.js·nestjs
花旗蜕变1 个月前
前端转 NestJS 全栈实践:从表单页面到微信业务系统
前端·typescript·nestjs
柒和远方1 个月前
NestJS + TypeORM 学习笔记:语法和类型不绕了
postgresql·orm·nestjs
小二李1 个月前
第15章 NestJS 项目部署
nestjs
前端踩bug工程师1 个月前
nestjs 实现一对多,多对一,一对一在实现上的区别
nestjs
爱丶不疚1 个月前
Electron:Module 与 Service 的职责边界与加载时序编排
前端·electron·nestjs
沐沐师2 个月前
Nest.js 微服务入门教程
微服务·nestjs
沐沐师2 个月前
Redis 入门教程
redis·nestjs