前提摘要:
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. 协作流程示例
- 控制器定义
scala
@Crud({
enabled: ['findOne', 'findAll', 'findPage'],
vos: {
findOne: UserDetailVo,
findAll: UserListVo,
findPage: UserPageVo
}
})
export class UsersController extends CrudController {
// 控制器方法
}
- 执行流程
-
- CRUD 装饰器初始化
-
-
- 收集 VO 配置
- 创建方法映射表
- 通过 TransformMethodMap 存储元数据
-
-
- 请求处理
-
-
- 方法执行,返回原数据
-
-
- 拦截器处理
-
-
- 获取当前方法的 VO 配置
- 根据数据类型选择转换策略
- 执行数据转换
- 返回转换后的数据
-
有不足的地方请多多指教!!!