如何将外部API返回的JSON存入MultiKeyMap,消除Spring Boot项目硬编码实现动态逻辑
实现步骤
1. 引入所需依赖
首先在pom.xml中加入JSON解析和MultiKeyMap所需的依赖:
<!-- Jackson JSON解析 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.15.2</version> </dependency> <!-- Apache Commons Collections 包含MultiKeyMap --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-collections4</artifactId> <version>4.4</version> </dependency>
2. 定义航司配置实体类
创建和返回JSON字段对应的实体类,可搭配Lombok简化代码:
import lombok.Data; @Data public class AirlineConfig { private Integer id; private String airlineCode; private String supplierCode; private Integer portalConfigurationId; private Boolean enabled; private String microServiceName; }
3. 解析API响应并存入MultiKeyMap
在原有调用配置接口的逻辑基础上,解析响应并存储到MultiKeyMap,这里使用supplierCode + microServiceName作为组合键,适配同一航司多个微服务的场景:
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.collections4.map.MultiKeyMap; import okhttp3.Response; import java.util.List; // 全局初始化ObjectMapper和OkHttpClient(建议注入Spring单例,不要重复创建) ObjectMapper objectMapper = new ObjectMapper(); MultiKeyMap<String, AirlineConfig> airlineConfigMap = new MultiKeyMap<>(); // 原有配置接口调用逻辑,建议加try-with-resources自动释放响应 try (Response getActiveMicroservicesResponse = client.newCall(getActiveMicroservicesRequest).execute()) { if (getActiveMicroservicesResponse.isSuccessful() && getActiveMicroservicesResponse.body() != null) { String responseStr = getActiveMicroservicesResponse.body().string(); JsonNode rootNode = objectMapper.readTree(responseStr); // 解析data数组为配置实体列表 List<AirlineConfig> configList = objectMapper.convertValue(rootNode.get("data"), new TypeReference<List<AirlineConfig>>() {}); // 存入MultiKeyMap,组合键为[供应商编码, 微服务名称] for (AirlineConfig config : configList) { airlineConfigMap.put(config.getSupplierCode(), config.getMicroServiceName(), config); } } } catch (Exception e) { // 配置接口调用失败可降级使用本地默认配置,自行补充逻辑 LOG.error("获取航司配置失败", e); }
4. 遍历MultiKeyMap替换硬编码逻辑
将原有每个航司的重复硬编码逻辑替换为遍历逻辑,动态生成请求:
// 提前注入航司服务地址映射,配置在application.properties中,避免硬编码URL前缀 // 示例配置格式:airline.service-url.G8=http://xxx.xxx.xxx:8080 @Value("#{${airline.service-url}}") private Map<String, String> serviceUrlMap; // 遍历所有配置,只处理启用的搜索服务 int supplierCount = 0; for (AirlineConfig config : airlineConfigMap.values()) { // 跳过未启用的航司 + 只处理搜索场景的微服务,可根据业务调整筛选条件 if (!config.getEnabled() || !"search".equals(config.getMicroServiceName())) { continue; } String supplierCode = config.getSupplierCode(); // 动态拼接请求地址 String baseUrl = serviceUrlMap.get(supplierCode); String requestUrl = String.format("%s/%s/v1.0/search", baseUrl, supplierCode.toLowerCase()); // 构造请求,复用原有body、公共请求头逻辑 Request searchRequest = new Request.Builder().url(requestUrl).post(body) .addHeader("X-AFFILIATE-ID", request.getHeader("X-AFFILIATE-ID")) .addHeader("X-AFFILIATE-NAME", request.getHeader("X-AFFILIATE-NAME")) .addHeader("X-XL-CODE", request.getHeader("X-XL-CODE")) .addHeader("X-SEARCH-ID", uuId).build(); Call call = client.newCall(searchRequest); // 异步回调逻辑,动态替换日志中的航司标识 call.enqueue(new Callback() { @Override public void onResponse(Call call, Response response) throws IOException { MDC.setContextMap(mdcContext); LOG.debug("{} responded success, status Code: {}", supplierCode, response.code()); response.close(); } @Override public void onFailure(Call call, IOException e) { MDC.setContextMap(MDC.getCopyOfContextMap()); LOG.error("Failure, Reason For {}: ", supplierCode, e); } }); supplierCount++; LOG.info("Search initiated for {} , url: {}", supplierCode, requestUrl); }
优化建议
- 配置接口调用结果可加本地缓存,设置5-10分钟的过期时间,避免每次业务请求都重复拉取配置
- OkHttpClient统一注册为Spring单例Bean,复用连接池提升性能
- 可额外维护供应商编码和航司名称的映射字典,方便日志可读性
内容的提问来源于stack exchange,提问作者Nasheed Azhar
相关产品推荐
相关产品推荐

