参数映射服务完整解决方案
参数映射服务完整解决方案
1. 背景说明
在复杂的工作流程中,后续程序需要动态构造输入参数,这些参数源自多个前序程序的 JSON 数据输出。为了增强系统的灵活性和可扩展性,需要一个通用的参数映射服务来处理这种复杂的数据转换需求。
1.1 主要挑战
- 数据来源多样性:需要处理来自不同程序的多种格式数据
- 映射逻辑复杂:包含条件判断、循环处理、多源合并等场景
- 配置驱动:需要通过配置文件定义映射规则,避免硬编码
- 扩展性要求:支持新增映射类型,保持代码结构清晰
2. 核心需求
2.1 基础功能需求
- 简单参数映射:支持从单一来源提取数据
- 复杂逻辑支持:
- 条件逻辑(if-then-else)
- 循环体处理
- 字段映射和合并
- 多来源支持:从多个前序程序提取数据,支持不同合并策略
- 常量支持:允许直接使用固定值
2.2 设计目标
- 通用性:提供统一的配置结构
- 灵活性:支持多种动态逻辑
- 易读性:配置结构清晰直观
- 可扩展性:易于添加新的映射类型
3. 系统架构
3.1 架构图
+----------------+ +----------------+ +----------------+
| 前序程序输出 | ------> | 参数映射服务 | -------> | 后序程序输入参数 |
| JSON 数据 | | (JSON 配置驱动) | | 动态生成 |
+----------------+ +----------------+ +----------------+
3.2 核心组件
- 值对象基类:定义通用接口和基础功能
- 专用值对象:实现不同类型的参数映射逻辑
- 值对象工厂:负责创建具体的值对象实例
- 参数映射服务:统一的服务入口
4. 配置结构设计
4.1 参数配置
字段名称 | 类型 | 必填 | 说明 |
---|---|---|---|
name | string | 是 | 参数名称 |
value | object | 是 | 参数值定义 |
description | string | 否 | 参数描述 |
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. 总结
本解决方案通过灵活的配置结构和可扩展的代码设计,实现了一个通用的参数映射服务。主要特点:
- 配置驱动:通过 JSON 配置文件定义映射规则
- 类型丰富:支持常量、单源、多源、循环、条件等多种映射类型
- 扩展性好:基于工厂模式,易于添加新的值对象类型
- 健壮性强:完善的错误处理和默认值机制
后续优化方向
- 支持更多合并策略
- 添加参数验证功能
- 支持自定义函数扩展
- 增加缓存机制
- 添加映射性能监控