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);
|
}
|
}
|