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

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

相关推荐
妖孽白YoonA2 天前
NestJS - 循环依赖地狱及其避免方法
架构·nestjs
用户17592342150283 天前
原来 Nest.js 如此简单
nestjs
Whbbit19994 天前
在 Nestjs 中使用 Drizzle ORM
前端·javascript·nestjs
濮水大叔5 天前
VonaJS AOP编程:全局中间件全攻略
typescript·nodejs·nestjs
濮水大叔6 天前
AOP编程有三大场景:控制器切面,内部切面,外部切面,你get到了吗?
typescript·node.js·nestjs
急急王子小啊皓7 天前
nestjs中passport-jwt非对称签名算法的使用
nestjs
一碗饭特稀7 天前
NestJS入门(1)——TODO项目创建及概念初步了解
node.js·nestjs
程序员王天8 天前
【开发AGIC】Vue3+NestJS+DeepSeek AI作业批改系统(已开源)
vue.js·ai编程·nestjs