1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
package com.vincent.rsf.openApi.utils;
 
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.vincent.rsf.openApi.entity.app.ApiFunction;
import com.vincent.rsf.openApi.entity.app.ApiMap;
import com.vincent.rsf.openApi.entity.app.App;
import com.vincent.rsf.openApi.service.ApiMapService;
import com.vincent.rsf.openApi.service.ApiFunctionService;
import com.vincent.rsf.openApi.service.AppService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.tika.utils.StringUtils;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
/**
 * 接口字段动态映射工具类
 * 支持从数据库加载映射配置,并提供字段转换功能
 *
 * @author vincent
 * @since 2026-01-04
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class ParamsMapUtils {
 
    private final AppService appService;
    private final ApiFunctionService functionService;
    private final ApiMapService mapService;
 
    // 缓存到内存
    public static List<App> APPS = new ArrayList<>();
    public static List<ApiFunction> FUNCTIONS = new ArrayList<>();
    public static List<ApiMap> ATTRIBUTE_MAPS = new ArrayList<>();
 
    /**
     * 应用完全启动后自动加载配置
     * 使用 ApplicationReadyEvent 确保 Spring 容器完全初始化
     */
    @EventListener(ApplicationReadyEvent.class)
    public void init() {
        log.info("=============== 开始加载接口映射配置 ===============");
        try {
            appService.refreshCache();
            functionService.refreshCache();
            mapService.refreshCache();
 
            log.info("接口映射配置加载完成 - 应用数:{}, 功能数:{}, 映射规则数:{}",
                    APPS.size(), FUNCTIONS.size(), ATTRIBUTE_MAPS.size());
        } catch (Exception e) {
            log.error("接口映射配置加载失败", e);
        }
    }
 
    /**
     * 手动刷新所有缓存
     */
    public void refreshAll() {
        log.info("手动刷新所有映射缓存...");
        appService.refreshCache();
        functionService.refreshCache();
        mapService.refreshCache();
    }
 
    /**
     * 执行字段映射转换
     *
     * @param appId 应用ID
     * @param funcId 功能ID
     * @param params 原始参数
     * @return 转换后的参数
     */
    public static JSONObject apiMaps(String appId, String funcId, JSONObject params) {
        if (params == null || params.isEmpty()) {
            return params;
        }
 
        // 1、获取映射表
        List<ApiMap> maps = ATTRIBUTE_MAPS.stream()
                .filter(map -> map.getAppId().equals(appId) && map.getFuncId().equals(funcId))
                .toList();
 
        if (maps.isEmpty()) {
            log.debug("未找到映射配置 - appId:{}, funcId:{}", appId, funcId);
            return params;
        }
 
        // 2、构建映射规则Map
        Map<String, String> mappingRules = new HashMap<>();
        for (ApiMap map : maps) {
            String sourceAttribute = map.getSourceAttribute();
            String targetAttribute = map.getTargetAttribute();
            if (!StringUtils.isBlank(sourceAttribute) && !StringUtils.isBlank(targetAttribute)) {
                mappingRules.put(sourceAttribute, targetAttribute);
            }
        }
 
        // 3、递归替换所有层级的属性名称
        JSONObject result = replaceKeysRecursive(params, mappingRules);
 
        return result;
    }
 
    /**
     * 递归替换JSON所有层级的属性名称
     * 支持嵌套对象和数组的深度遍历
     *
     * @param json 原始JSON对象
     * @param mappingRules 映射规则 (源字段名 -> 目标字段名)
     * @return 替换后的JSON对象
     */
    public static JSONObject replaceKeysRecursive(JSONObject json, Map<String, String> mappingRules) {
        if (json == null || json.isEmpty()) {
            return json;
        }
 
        JSONObject result = new JSONObject();
 
        for (String key : json.keySet()) {
            Object value = json.get(key);
 
            // 确定新的键名(如果有映射规则则使用映射后的名称)
            String newKey = mappingRules.getOrDefault(key, key);
 
            if (value instanceof JSONObject) {
                // 递归处理嵌套对象
                JSONObject nestedResult = replaceKeysRecursive((JSONObject) value, mappingRules);
                result.put(newKey, nestedResult);
                log.debug("替换对象字段: {} -> {}", key, newKey);
 
            } else if (value instanceof JSONArray) {
                // 递归处理数组
                JSONArray arrayResult = replaceKeysInArray((JSONArray) value, mappingRules);
                result.put(newKey, arrayResult);
                log.debug("替换数组字段: {} -> {}", key, newKey);
 
            } else {
                // 普通值直接赋值
                Object convertedValue = convertValue(value, newKey);
                result.put(newKey, convertedValue);
                if (!key.equals(newKey)) {
                    log.debug("替换字段: {} -> {} (值: {})", key, newKey, convertedValue);
                }
            }
        }
 
        return result;
    }
 
    /**
     * 递归处理JSON数组中的所有元素
     *
     * @param array 原始JSON数组
     * @param mappingRules 映射规则
     * @return 处理后的JSON数组
     */
    private static JSONArray replaceKeysInArray(JSONArray array, Map<String, String> mappingRules) {
        if (array == null || array.isEmpty()) {
            return array;
        }
 
        JSONArray result = new JSONArray();
 
        for (int i = 0; i < array.size(); i++) {
            Object element = array.get(i);
 
            if (element instanceof JSONObject) {
                // 数组元素是对象,递归处理
                JSONObject replacedObject = replaceKeysRecursive((JSONObject) element, mappingRules);
                result.add(replacedObject);
 
            } else if (element instanceof JSONArray) {
                // 数组元素是数组,递归处理
                JSONArray replacedArray = replaceKeysInArray((JSONArray) element, mappingRules);
                result.add(replacedArray);
 
            } else {
                // 基本类型,直接添加
                result.add(element);
            }
        }
 
        return result;
    }
 
    /**
     * 通用的JSON属性名替换方法(对外提供)
     * 可以直接传入映射规则进行替换
     *
     * @param json 原始JSON对象
     * @param mappingRules 映射规则 Map<源字段名, 目标字段名>
     * @return 替换后的JSON对象
     */
    public static JSONObject replaceJsonKeys(JSONObject json, Map<String, String> mappingRules) {
        return replaceKeysRecursive(json, mappingRules);
    }
 
    /**
     * 通用的JSON数组属性名替换方法(对外提供)
     *
     * @param array 原始JSON数组
     * @param mappingRules 映射规则 Map<源字段名, 目标字段名>
     * @return 替换后的JSON数组
     */
    public static JSONArray replaceJsonArrayKeys(JSONArray array, Map<String, String> mappingRules) {
        return replaceKeysInArray(array, mappingRules);
    }
 
 
    /**
     * 值类型转换(可扩展)
     *
     * @param value 原始值
     * @param targetField 目标字段名
     * @return 转换后的值
     */
    private static Object convertValue(Object value, String targetField) {
        if (value == null) {
            return null;
        }
 
        // 这里可以根据需要添加更多类型转换逻辑
        // 例如:日期格式转换、数字精度转换等
 
        // 示例:如果字段名包含amount、price等,转换为BigDecimal
        String lowerField = targetField.toLowerCase();
        if ((lowerField.contains("amount") || lowerField.contains("price")
                || lowerField.contains("qty")) && value instanceof String) {
            try {
                return new BigDecimal(value.toString());
            } catch (Exception e) {
                log.warn("数字转换失败: {} -> {}", value, targetField);
                return value;
            }
        }
 
        return value;
    }
 
    /**
     * 获取应用信息
     *
     * @param appId 应用ID
     * @return 应用信息
     */
    public static App getApp(String appId) {
        return APPS.stream()
                .filter(app -> app.getId().equals(appId))
                .findFirst()
                .orElse(null);
    }
 
    /**
     * 获取功能信息
     *
     * @param funcId 功能ID
     * @return 功能信息
     */
    public static ApiFunction getFunction(String funcId) {
        return FUNCTIONS.stream()
                .filter(func -> func.getId().equals(funcId))
                .findFirst()
                .orElse(null);
    }
}