当前位置: 首页 > article >正文

参数映射服务完整解决方案

参数映射服务完整解决方案

1. 背景说明

在复杂的工作流程中,后续程序需要动态构造输入参数,这些参数源自多个前序程序的 JSON 数据输出。为了增强系统的灵活性和可扩展性,需要一个通用的参数映射服务来处理这种复杂的数据转换需求。

1.1 主要挑战

  • 数据来源多样性:需要处理来自不同程序的多种格式数据
  • 映射逻辑复杂:包含条件判断、循环处理、多源合并等场景
  • 配置驱动:需要通过配置文件定义映射规则,避免硬编码
  • 扩展性要求:支持新增映射类型,保持代码结构清晰

2. 核心需求

2.1 基础功能需求

  • 简单参数映射:支持从单一来源提取数据
  • 复杂逻辑支持
    • 条件逻辑(if-then-else)
    • 循环体处理
    • 字段映射和合并
  • 多来源支持:从多个前序程序提取数据,支持不同合并策略
  • 常量支持:允许直接使用固定值

2.2 设计目标

  • 通用性:提供统一的配置结构
  • 灵活性:支持多种动态逻辑
  • 易读性:配置结构清晰直观
  • 可扩展性:易于添加新的映射类型

3. 系统架构

3.1 架构图

+----------------+          +----------------+           +----------------+
| 前序程序输出     | ------> | 参数映射服务     | -------> | 后序程序输入参数    |
| JSON 数据       |          | (JSON 配置驱动) |           | 动态生成          |
+----------------+          +----------------+           +----------------+

3.2 核心组件

  1. 值对象基类:定义通用接口和基础功能
  2. 专用值对象:实现不同类型的参数映射逻辑
  3. 值对象工厂:负责创建具体的值对象实例
  4. 参数映射服务:统一的服务入口

4. 配置结构设计

4.1 参数配置

字段名称类型必填说明
namestring参数名称
valueobject参数值定义
descriptionstring参数描述

4.2 值对象类型

4.2.1 常量值(ConstantValue)
{
  "type": "constant",
  "value": "固定值"
}
4.2.2 单一来源(SingleSourceValue)
{
  "type": "jmespath",
  "jmespath": "data.path.to.value"
}
4.2.3 多来源(MultiSourceValue)
{
  "type": "multiSource",
  "sources": {
    "sourceA": "path.to.arrayA",
    "sourceB": "path.to.arrayB"
  },
  "mergeStrategy": "concat"
}
4.2.4 循环体(LoopValue)
{
  "type": "loop",
  "jmespath": "items[*]",
  "mappings": {
    "id": "id",
    "name": "name"
  }
}
4.2.5 条件值(ConditionalValue)
{
  "type": "conditional",
  "jmespath": "status",
  "conditions": [
    {
      "if": "status == 'success'",
      "then": {
        "type": "constant",
        "value": "成功"
      }
    }
  ],
  "else": {
    "type": "constant",
    "value": "其他"
  }
}

5. 代码实现

5.1 工具函数

import jp from "jmespath";

/**
 * 安全的 JMESPath 查询
 * @param {Object} data - 查询的上下文对象
 * @param {string} expression - JMESPath 表达式
 * @param {*} defaultValue - 查询失败时的默认值
 * @returns {*} 查询结果或默认值
 */
function safeJMESPath(data, expression, defaultValue = null) {
  try {
    const result = jp.search(data, expression);
    return result !== undefined ? result : defaultValue;
  } catch (error) {
    console.warn(`JMESPath 查询失败: ${expression}`, error);
    return defaultValue;
  }
}

5.2 值对象基类

/**
 * 值对象基类
 */
class ValueObject {
  constructor(config) {
    this.type = config.type;
    if (!this.type) {
      throw new Error("值对象类型未定义");
    }
  }

  getValue(context) {
    throw new Error("子类必须实现 getValue 方法");
  }
}

5.3 专用值对象实现

/**
 * 常量值对象
 */
class ConstantValue extends ValueObject {
  constructor(config) {
    super(config);
    this.value = config.value;
    if (this.value === undefined) {
      throw new Error("常量值未指定");
    }
  }

  getValue() {
    return this.value;
  }
}

/**
 * 单一来源值对象
 */
class SingleSourceValue extends ValueObject {
  constructor(config) {
    super(config);
    this.jmespath = config.jmespath;
    if (!this.jmespath) {
      throw new Error("JMESPath 表达式未指定");
    }
  }

  getValue(context) {
    return safeJMESPath(context, this.jmespath);
  }
}

/**
 * 多来源值对象
 */
class MultiSourceValue extends ValueObject {
  constructor(config) {
    super(config);
    this.sources = config.sources;
    this.mergeStrategy = config.mergeStrategy || "concat";
    if (!this.sources || typeof this.sources !== "object") {
      throw new Error("多来源配置无效");
    }
  }

  getValue(context) {
    const values = Object.entries(this.sources).map(([key, jmespath]) => {
      return safeJMESPath(context[key], jmespath, []);
    });

    switch (this.mergeStrategy) {
      case "concat":
        return values.flat();
      case "unique":
        return [...new Set(values.flat())];
      case "priority":
        return values.find((value) => value.length > 0) || [];
      default:
        throw new Error(`不支持的合并策略: ${this.mergeStrategy}`);
    }
  }
}

/**
 * 循环体值对象
 */
class LoopValue extends ValueObject {
  constructor(config) {
    super(config);
    this.jmespath = config.jmespath;
    this.mappings = config.mappings || {};
    if (!this.jmespath) {
      throw new Error("循环体数据源表达式未指定");
    }
  }

  getValue(context) {
    const array = safeJMESPath(context, this.jmespath, []);
    if (!Array.isArray(array)) {
      return [];
    }

    return array.map((item) => {
      const mappedItem = {};
      for (const [key, expression] of Object.entries(this.mappings)) {
        mappedItem[key] = safeJMESPath(item, expression);
      }
      return mappedItem;
    });
  }
}

/**
 * 条件值对象
 */
class ConditionalValue extends ValueObject {
  constructor(config) {
    super(config);
    this.jmespath = config.jmespath;
    this.conditions = config.conditions || [];
    this.else = config.else;
    if (!this.jmespath) {
      throw new Error("条件数据源表达式未指定");
    }
  }

  getValue(context) {
    const data = safeJMESPath(context, this.jmespath, {});
    
    for (const condition of this.conditions) {
      if (safeJMESPath(data, condition.if, false)) {
        return new ValueObjectFactory().create(condition.then).getValue(context);
      }
    }

    return this.else ? 
      new ValueObjectFactory().create(this.else).getValue(context) : 
      null;
  }
}

5.4 值对象工厂

/**
 * 值对象工厂
 */
class ValueObjectFactory {
  constructor() {
    this.typeMap = {
      constant: ConstantValue,
      jmespath: SingleSourceValue,
      multiSource: MultiSourceValue,
      loop: LoopValue,
      conditional: ConditionalValue,
    };
  }

  create(config) {
    const ValueObjectClass = this.typeMap[config.type];
    if (!ValueObjectClass) {
      throw new Error(`不支持的值对象类型: ${config.type}`);
    }
    return new ValueObjectClass(config);
  }
}

5.5 参数映射服务

/**
 * 参数映射服务
 */
class ParameterMappingService {
  constructor(config) {
    this.parameters = config.parameters || [];
    this.factory = new ValueObjectFactory();
  }

  mapParameters(context) {
    const output = {};
    for (const param of this.parameters) {
      try {
        const valueObject = this.factory.create(param.value);
        output[param.name] = valueObject.getValue(context);
      } catch (error) {
        console.error(`处理参数 ${param.name} 时发生错误:`, error);
        output[param.name] = null;
      }
    }
    return output;
  }
}

6. 使用示例

// 配置示例
const config = {
  parameters: [
    {
      name: "version",
      value: {
        type: "constant",
        value: "1.0.0"
      }
    },
    {
      name: "userId",
      value: {
        type: "jmespath",
        jmespath: "userInfo.id"
      }
    },
    {
      name: "permissions",
      value: {
        type: "multiSource",
        sources: {
          rolePerms: "permissions[*].code",
          userPerms: "customPermissions[*]"
        },
        mergeStrategy: "unique"
      }
    }
  ]
};

// 示例数据
const context = {
  userInfo: {
    id: "user123"
  },
  rolePerms: {
    permissions: [
      { code: "READ" },
      { code: "WRITE" }
    ]
  },
  userPerms: {
    customPermissions: ["ADMIN"]
  }
};

// 使用示例
const service = new ParameterMappingService(config);
const result = service.mapParameters(context);
console.log(result);
/* 输出:
{
  version: "1.0.0",
  userId: "user123",
  permissions: ["READ", "WRITE", "ADMIN"]
}
*/

7. 总结

本解决方案通过灵活的配置结构和可扩展的代码设计,实现了一个通用的参数映射服务。主要特点:

  1. 配置驱动:通过 JSON 配置文件定义映射规则
  2. 类型丰富:支持常量、单源、多源、循环、条件等多种映射类型
  3. 扩展性好:基于工厂模式,易于添加新的值对象类型
  4. 健壮性强:完善的错误处理和默认值机制

后续优化方向

  1. 支持更多合并策略
  2. 添加参数验证功能
  3. 支持自定义函数扩展
  4. 增加缓存机制
  5. 添加映射性能监控

http://www.kler.cn/a/537688.html

相关文章:

  • 在 NXP Yocto 环境下实现 Qualcomm Wi-Fi Driver 的 GitLab CI/CD
  • CLion2024.3.2版中引入vector头文件报错
  • c++计算机教程
  • Junit5使用教程(5) --扩展模型2-临时目录扩展
  • Docker安装pypiserver私服
  • c++ 浮点数比较判断
  • Could not create task ‘:mainActivity:minifyReleaseWithR8‘.
  • 【Flink快速入门-8.Flink Flink 架构介绍】
  • 利用Termux在安卓手机中安装 PostgreSQL
  • CPP集群聊天服务器开发实践(一):用户注册与登录
  • Chrome谷歌多开教程:实用方法与工具
  • 使用Python和`moviepy`库从输入的图片、动图和音频生成幻灯片式视频的示例代码
  • 盘姬工具箱:完全免费的电脑工具箱
  • DeepSeek从入门到精通:全面掌握AI大模型的核心能力
  • 【Outlook】如何将特定邮件显示在Outlook的重点收件箱中
  • 机器学习数学基础:19.线性相关与线性无关
  • TaskBuilder项目实战:创建项目
  • 为AI聊天工具添加一个知识系统 之90 详细设计之31 Derivation 之5-- 神经元变元用它衍生神经网络
  • 动手写ORM框架 - GeeORM第一天 database/sql 基础
  • IDEA查看项目依赖包及其版本
  • AIGC-微头条爆款文案创作智能体完整指令(DeepSeek,豆包,千问,Kimi,GPT)
  • 2025.2.8总结
  • 使用Postman创建Mock Server
  • .NET周刊【1月第4期 2025-01-26】
  • Matplotlib基础01( 基本绘图函数/多图布局/图形嵌套/绘图属性)
  • [渗透测试]热门搜索引擎推荐— — shodan篇