Commit 38869e0a by renyizhao

获取模型列表接口

parent 8cbaffa1
package com.luhu.computility.module.apihub.controller.app.aimodel;
import cn.hutool.core.util.StrUtil;
import com.luhu.computility.framework.common.pojo.CommonResult;
import com.luhu.computility.framework.security.core.util.SecurityFrameworkUtils;
import com.luhu.computility.module.apihub.controller.admin.newapi.NewApiResponse;
import com.luhu.computility.module.apihub.controller.app.aimodel.vo.AppModelPricingVO;
import com.luhu.computility.module.apihub.controller.app.aimodel.vo.AppModelVO;
import com.luhu.computility.module.apihub.controller.app.aimodel.vo.AppPricingVO;
import com.luhu.computility.module.apihub.service.newapi.NewApiClient;
import com.luhu.computility.module.member.dal.dataobject.user.MemberUserDO;
import com.luhu.computility.module.member.service.user.MemberUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* APP端 - AI 模型与定价接口
*/
@Slf4j
@RestController
@RequestMapping("/app/ai")
@Tag(name = "APP端 - AI模型与定价")
public class AppAiModelController {
/**
* 业务倍率系数:puhui 在 New API 价格基础上额外乘的固定系数
*/
private static final BigDecimal BUSINESS_RATIO = new BigDecimal("2");
@Resource
private NewApiClient newApiClient;
@Resource
private MemberUserService memberUserService;
/**
* 获取定价信息(原始)
*/
@GetMapping("/pricing")
@Operation(summary = "获取 New API 定价信息(含模型定价和分组倍率,按当前登录用户权限)")
public CommonResult<AppPricingVO> getPricing() {
String accessToken = getCurrentUserAccessToken();
String userId = getCurrentUserNewApiId();
NewApiResponse<Map<String, Object>> resp = newApiClient.getPricing(accessToken, userId);
if (resp.getSuccess() == null || !resp.getSuccess() || resp.getData() == null) {
log.error("[getPricing] 调用 New API 失败:{}", resp.getMessage());
return CommonResult.error(1, "获取定价失败: " + resp.getMessage());
}
return CommonResult.success(buildPricingVO(resp.getData()));
}
/**
* 获取模型列表(带元数据)
*/
@GetMapping("/models")
@Operation(summary = "获取 New API 模型列表(带元数据和图标)")
public CommonResult<List<AppModelVO>> getModels(@RequestParam(defaultValue = "0") Integer page,
@RequestParam(defaultValue = "100") Integer pageSize) {
NewApiResponse<Map<String, Object>> resp = newApiClient.getModels(page, pageSize);
if (resp.getSuccess() == null || !resp.getSuccess() || resp.getData() == null) {
log.error("[getModels] 调用 New API 失败:{}", resp.getMessage());
return CommonResult.error(1, "获取模型列表失败: " + resp.getMessage());
}
@SuppressWarnings("unchecked")
List<Map<String, Object>> items = (List<Map<String, Object>>) resp.getData().get("items");
if (items == null) {
return CommonResult.success(Collections.emptyList());
}
// 顺便获取 vendor 用于图标 fallback
List<Map<String, Object>> vendors = null;
NewApiResponse<Map<String, Object>> pricingResp = newApiClient.getPricing(null, null);
if (pricingResp.getSuccess() != null && pricingResp.getSuccess() && pricingResp.getData() != null) {
@SuppressWarnings("unchecked")
List<Map<String, Object>> v = (List<Map<String, Object>>) pricingResp.getData().get("vendors");
vendors = v;
}
List<AppModelVO> result = new ArrayList<>();
for (Map<String, Object> item : items) {
AppModelVO vo = new AppModelVO();
vo.setId(toLong(item.get("id")));
vo.setModelName((String) item.get("model_name"));
vo.setIcon((String) item.get("icon"));
vo.setStatus(toInteger(item.get("status")));
vo.setDescription((String) item.get("description"));
// 解析 enable_groups
Object eg = item.get("enable_groups");
if (eg instanceof List) {
@SuppressWarnings("unchecked")
List<String> enableGroups = (List<String>) eg;
vo.setEnableGroups(enableGroups);
}
// 解析 endpoints(JSON 字符串)
Object ep = item.get("endpoints");
if (ep instanceof String) {
try {
vo.setEndpoints(com.luhu.computility.framework.common.util.json.JsonUtils.parseArray((String) ep, String.class));
} catch (Exception e) {
log.warn("[getModels] 解析 endpoints 失败:{}", ep);
}
} else if (ep instanceof List) {
@SuppressWarnings("unchecked")
List<String> endpoints = (List<String>) ep;
vo.setEndpoints(endpoints);
}
// vendor 名称:如果模型没配 icon,用 model_name 推断
if (StrUtil.isBlank(vo.getIcon())) {
vo.setIcon(resolveIconByName(vo.getModelName(), vendors));
}
if (StrUtil.isBlank(vo.getVendorName())) {
vo.setVendorName(resolveVendorName(vo.getModelName(), vendors));
}
result.add(vo);
}
return CommonResult.success(result);
}
/**
* 聚合接口:模型列表 + 定价
*/
@GetMapping("/models-with-pricing")
@Operation(summary = "获取模型列表及定价(已按当前用户分组倍率计算好价格)")
public CommonResult<List<AppModelPricingVO>> getModelsWithPricing() {
// 1. 用当前用户 token 调 /api/pricing,拿到该用户实际生效的 group_ratio
String accessToken = getCurrentUserAccessToken();
String userId = getCurrentUserNewApiId();
NewApiResponse<Map<String, Object>> pricingResp = newApiClient.getPricing(accessToken, userId);
if (pricingResp.getSuccess() == null || !pricingResp.getSuccess() || pricingResp.getData() == null) {
log.error("[getModelsWithPricing] 获取定价失败:{}", pricingResp.getMessage());
return CommonResult.error(1, "获取定价失败");
}
Map<String, Object> pricingData = pricingResp.getData();
// 业务最终倍率 = group_ratio.default × 业务系数
BigDecimal groupRatio = resolveGroupRatio(pricingData);
// 2. 构造 model_name -> pricing 索引
@SuppressWarnings("unchecked")
List<Map<String, Object>> modelPricingList = (List<Map<String, Object>>) pricingData.get("data");
Map<String, Map<String, Object>> pricingIndex = new java.util.HashMap<>();
if (modelPricingList != null) {
for (Map<String, Object> p : modelPricingList) {
Object name = p.get("model_name");
if (name != null) {
pricingIndex.put(name.toString(), p);
}
}
}
// 3. 获取供应商
@SuppressWarnings("unchecked")
List<Map<String, Object>> vendors = (List<Map<String, Object>>) pricingData.get("vendors");
// 4. 拉取所有模型元数据(分页拉满)
NewApiResponse<Map<String, Object>> modelsResp = newApiClient.getModels(0, 200);
if (modelsResp.getSuccess() == null || !modelsResp.getSuccess() || modelsResp.getData() == null) {
log.error("[getModelsWithPricing] 获取模型列表失败:{}", modelsResp.getMessage());
return CommonResult.error(1, "获取模型列表失败");
}
@SuppressWarnings("unchecked")
List<Map<String, Object>> items = (List<Map<String, Object>>) modelsResp.getData().get("items");
if (items == null) {
return CommonResult.success(Collections.emptyList());
}
List<AppModelPricingVO> result = new ArrayList<>();
for (Map<String, Object> item : items) {
String modelName = (String) item.get("model_name");
if (modelName == null) continue;
AppModelPricingVO vo = new AppModelPricingVO();
vo.setModelName(modelName);
vo.setIcon((String) item.get("icon"));
vo.setStatus(toInteger(item.get("status")));
vo.setDescription((String) item.get("description"));
// endpoints
Object ep = item.get("endpoints");
if (ep instanceof String) {
try {
vo.setSupportedEndpoints(com.luhu.computility.framework.common.util.json.JsonUtils.parseArray((String) ep, String.class));
} catch (Exception ignored) {
}
} else if (ep instanceof List) {
@SuppressWarnings("unchecked")
List<String> eps = (List<String>) ep;
vo.setSupportedEndpoints(eps);
}
// enable_groups
Object eg = item.get("enable_groups");
if (eg instanceof List) {
@SuppressWarnings("unchecked")
List<String> egs = (List<String>) eg;
vo.setEnableGroups(egs);
}
// 合并 pricing
Map<String, Object> pricing = pricingIndex.get(modelName);
if (pricing != null) {
vo.setQuotaType(toInteger(pricing.get("quota_type")));
vo.setModelRatio(toBigDecimal(pricing.get("model_ratio")));
vo.setModelPrice(toBigDecimal(pricing.get("model_price")));
vo.setCompletionRatio(toBigDecimal(pricing.get("completion_ratio")));
// 计算价格
BigDecimal modelPrice = vo.getModelPrice() != null ? vo.getModelPrice() : BigDecimal.ZERO;
BigDecimal modelRatio = vo.getModelRatio() != null ? vo.getModelRatio() : BigDecimal.ZERO;
BigDecimal completionRatio = vo.getCompletionRatio() != null ? vo.getCompletionRatio() : BigDecimal.ONE;
if (vo.getQuotaType() != null && vo.getQuotaType() == 1) {
// 固定价模式:业务系数不参与
vo.setInputPrice(modelPrice.setScale(2, RoundingMode.HALF_UP));
vo.setOutputPrice(modelPrice.multiply(completionRatio).setScale(2, RoundingMode.HALF_UP));
} else {
// 倍率模式
vo.setInputPrice(modelPrice.add(modelRatio).multiply(groupRatio).setScale(2, RoundingMode.HALF_UP));
vo.setOutputPrice(modelPrice.add(modelRatio.multiply(completionRatio)).multiply(groupRatio).setScale(2, RoundingMode.HALF_UP));
}
}
vo.setGroupRatio(groupRatio);
// icon & vendor 推断
if (StrUtil.isBlank(vo.getIcon())) {
vo.setIcon(resolveIconByName(modelName, vendors));
}
vo.setVendorName(resolveVendorName(modelName, vendors));
result.add(vo);
}
return CommonResult.success(result);
}
/**
* 从 pricing 原始数据中解析业务最终倍率 = group_ratio.default × 业务系数
*/
private BigDecimal resolveGroupRatio(Map<String, Object> pricingData) {
@SuppressWarnings("unchecked")
Map<String, Object> groupRatioMap = (Map<String, Object>) pricingData.get("group_ratio");
if (groupRatioMap == null) {
return BUSINESS_RATIO;
}
Object defaultRatio = groupRatioMap.get("default");
if (defaultRatio == null) {
return BUSINESS_RATIO;
}
try {
BigDecimal base = new BigDecimal(String.valueOf(defaultRatio));
return base.multiply(BUSINESS_RATIO);
} catch (Exception e) {
log.warn("[resolveGroupRatio] 解析 group_ratio.default 失败:{}", defaultRatio);
return BUSINESS_RATIO;
}
}
/**
* 获取当前登录用户的 New API accessToken(无则返回 null)
*/
private String getCurrentUserAccessToken() {
MemberUserDO user = getCurrentMemberUser();
return user == null ? null : user.getNewapiAccessToken();
}
/**
* 获取当前登录用户在 New API 的 userId(无则返回 null)
*/
private String getCurrentUserNewApiId() {
MemberUserDO user = getCurrentMemberUser();
return user == null || user.getNewapiUserId() == null ? null : user.getNewapiUserId().toString();
}
/**
* 获取当前登录用户的 MemberUserDO
*/
private MemberUserDO getCurrentMemberUser() {
try {
Long userId = SecurityFrameworkUtils.getLoginUserId();
if (userId == null) {
return null;
}
return memberUserService.getUser(userId);
} catch (Exception e) {
log.error("[getCurrentMemberUser] 异常", e);
return null;
}
}
/**
* 构造定价 VO
*/
private AppPricingVO buildPricingVO(Map<String, Object> data) {
AppPricingVO vo = new AppPricingVO();
// 分组倍率
@SuppressWarnings("unchecked")
Map<String, Object> groupRatioMap = (Map<String, Object>) data.get("group_ratio");
if (groupRatioMap != null) {
Map<String, BigDecimal> ratios = new java.util.HashMap<>();
groupRatioMap.forEach((k, v) -> {
try {
ratios.put(k, new BigDecimal(String.valueOf(v)));
} catch (Exception ignored) {
}
});
vo.setGroupRatios(ratios);
}
// 当前用户实际生效倍率(已含业务系数)
vo.setGroupRatio(resolveGroupRatio(data));
// 支持的端点
@SuppressWarnings("unchecked")
Map<String, Object> supportedEndpoint = (Map<String, Object>) data.get("supported_endpoint");
vo.setSupportedEndpoint(supportedEndpoint);
// 供应商列表
@SuppressWarnings("unchecked")
List<Map<String, Object>> vendors = (List<Map<String, Object>>) data.get("vendors");
vo.setVendors(vendors);
// 模型定价(原始)
@SuppressWarnings("unchecked")
List<Map<String, Object>> modelPricing = (List<Map<String, Object>>) data.get("data");
vo.setModelPricing(modelPricing);
return vo;
}
/**
* 根据 model_name 推断 icon 名
*/
private String resolveIconByName(String modelName, List<Map<String, Object>> vendors) {
if (modelName == null) return "AI";
String lower = modelName.toLowerCase();
if (lower.contains("qwen")) return "Qwen.Color";
if (lower.contains("deepseek")) return "DeepSeek.Color";
if (lower.contains("doubao")) return "Doubao.Color";
if (lower.contains("gpt") || lower.contains("openai") || lower.contains("o1") || lower.contains("o3") || lower.contains("o4")) return "OpenAI";
if (lower.contains("claude")) return "Claude.Color";
if (lower.contains("gemini")) return "Gemini.Color";
if (lower.contains("llama") || lower.contains("meta")) return "Meta";
if (lower.contains("moonshot") || lower.contains("kimi")) return "Moonshot";
if (lower.contains("glm") || lower.contains("zhipu") || lower.contains("chatglm")) return "Zhipu.Color";
if (lower.contains("embedding") || lower.contains("bge") || lower.contains("m3e") || lower.contains("bge-m3")) return "Embedding";
if (lower.contains("rerank")) return "Rerank";
if (lower.contains("stable") || lower.contains("sdxl")) return "StableDiffusion";
if (lower.contains("wav2lip") || lower.contains("tts") || lower.contains("asr") || lower.contains("audio")) return "Audio";
if (lower.contains("mistral") || lower.contains("mixtral")) return "Mistral";
if (lower.contains("yi")) return "Yi";
if (lower.contains("baichuan")) return "Baichuan";
if (lower.contains("minimax")) return "MiniMax.Color";
if (lower.contains("hunyuan") || lower.contains("tencent")) return "Hunyuan";
if (lower.contains("spark") || lower.contains("xunfei") || lower.contains("iflytek")) return "Spark";
if (lower.contains("sensenova") || lower.contains("sense")) return "SenseNova";
return "AI";
}
/**
* 根据 model_name 推断 vendor 名
*/
private String resolveVendorName(String modelName, List<Map<String, Object>> vendors) {
if (modelName == null) return null;
if (vendors != null) {
for (Map<String, Object> v : vendors) {
Object name = v.get("name");
if (name == null) continue;
String n = name.toString().toLowerCase();
if (modelName.toLowerCase().contains(n)) {
return name.toString();
}
}
}
return null;
}
private Long toLong(Object o) {
if (o == null) return null;
if (o instanceof Number) return ((Number) o).longValue();
try {
return Long.parseLong(o.toString());
} catch (Exception ignored) {
return null;
}
}
private Integer toInteger(Object o) {
if (o == null) return null;
if (o instanceof Number) return ((Number) o).intValue();
try {
return Integer.parseInt(o.toString());
} catch (Exception ignored) {
return null;
}
}
private BigDecimal toBigDecimal(Object o) {
if (o == null) return null;
if (o instanceof Number) return new BigDecimal(o.toString());
if (o instanceof String) {
try {
return new BigDecimal((String) o);
} catch (Exception ignored) {
return null;
}
}
return null;
}
}
package com.luhu.computility.module.apihub.controller.app.aimodel.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
/**
* APP端 - 模型定价信息 VO(聚合后)
*/
@Data
@Schema(description = "APP端 - 模型定价信息")
public class AppModelPricingVO {
@Schema(description = "模型名")
private String modelName;
@Schema(description = "图标名(lobehub 风格,如 Qwen.Color)")
private String icon;
@Schema(description = "供应商名")
private String vendorName;
@Schema(description = "支持的端点列表")
private List<String> supportedEndpoints;
@Schema(description = "支持的分组列表")
private List<String> enableGroups;
@Schema(description = "计价方式:0-按倍率,1-按固定价")
private Integer quotaType;
@Schema(description = "模型倍率")
private BigDecimal modelRatio;
@Schema(description = "固定价(元/1k tokens)")
private BigDecimal modelPrice;
@Schema(description = "补全价格倍率")
private BigDecimal completionRatio;
@Schema(description = "当前用户分组倍率")
private BigDecimal groupRatio;
@Schema(description = "输入价格(元/1k tokens),已乘 groupRatio")
private BigDecimal inputPrice;
@Schema(description = "输出价格(元/1k tokens),已乘 groupRatio")
private BigDecimal outputPrice;
@Schema(description = "状态:1-启用,0-禁用")
private Integer status;
@Schema(description = "模型描述(未设置则为空)")
private String description;
}
package com.luhu.computility.module.apihub.controller.app.aimodel.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
/**
* APP端 - 模型信息 VO
*/
@Data
@Schema(description = "APP端 - 模型信息")
public class AppModelVO {
@Schema(description = "模型ID")
private Long id;
@Schema(description = "模型名")
private String modelName;
@Schema(description = "图标名")
private String icon;
@Schema(description = "供应商名(自动匹配)")
private String vendorName;
@Schema(description = "支持的端点")
private List<String> endpoints;
@Schema(description = "支持的分组")
private List<String> enableGroups;
@Schema(description = "状态:1-启用,0-禁用")
private Integer status;
@Schema(description = "模型描述(未设置则为空)")
private String description;
}
package com.luhu.computility.module.apihub.controller.app.aimodel.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
import java.util.Map;
/**
* APP端 - 定价信息 VO
*/
@Data
@Schema(description = "APP端 - 定价信息")
public class AppPricingVO {
@Schema(description = "当前用户所属分组名")
private String group;
@Schema(description = "当前分组倍率")
private java.math.BigDecimal groupRatio;
@Schema(description = "所有可用分组及倍率")
private Map<String, java.math.BigDecimal> groupRatios;
@Schema(description = "支持的端点")
private Map<String, Object> supportedEndpoint;
@Schema(description = "供应商列表(用于图标 fallback)")
private List<Map<String, Object>> vendors;
@Schema(description = "模型定价列表(原始数据)")
private List<Map<String, Object>> modelPricing;
}
......@@ -5,6 +5,8 @@ import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.luhu.computility.module.apihub.config.NewApiProperties;
import com.luhu.computility.module.apihub.controller.admin.newapi.*;
import lombok.extern.slf4j.Slf4j;
......@@ -21,6 +23,9 @@ public class NewApiClient {
@Resource
private NewApiProperties newApiProperties;
@Resource
private ObjectMapper objectMapper;
private static final String HEADER_USER = "New-Api-User";
private static final String HEADER_AUTH = "Authorization";
private static final String USER_ANONYMOUS = "-1";
......@@ -283,6 +288,122 @@ public class NewApiClient {
}
}
/**
* 获取定价信息(含模型定价、分组倍率、支持端点)
* GET /api/pricing
*
* @param accessToken 用户访问令牌(可空)。传入后使用对应账号权限请求,group_ratio.default 即为该用户实际倍率;不传则匿名请求。
* @param userId 用户在 New API 的 userId(与 accessToken 配套传入,用于 New-Api-User 头)。可空。
*/
public NewApiResponse<Map<String, Object>> getPricing(String accessToken, String userId) {
String url = newApiProperties.getBaseUrl() + "/api/pricing";
log.info("[NewApiClient.getPricing] 请求URL: {}, 带token={}, 带userId={}", url,
StrUtil.isNotBlank(accessToken), StrUtil.isNotBlank(userId));
try {
HttpRequest request = HttpRequest.get(url).timeout(30000);
if (StrUtil.isBlank(accessToken)) {
// 匿名请求
request.header(HEADER_USER, USER_ANONYMOUS);
} else {
// 带 token 时同时传 New-Api-User 头
if (StrUtil.isNotBlank(userId)) {
request.header(HEADER_USER, userId);
}
request.header(HEADER_AUTH, "Bearer " + accessToken);
}
HttpResponse response = request.execute();
log.info("[NewApiClient.getPricing] 响应状态: {}", response.getStatus());
return parseMapResponse(response);
} catch (Exception e) {
log.error("[NewApiClient.getPricing] 请求异常", e);
return NewApiResponse.<Map<String, Object>>builder()
.success(false)
.message("请求异常: " + e.getMessage())
.httpResponse(null)
.build();
}
}
/**
* 获取模型列表(管理员权限)
* GET /api/models/?p=0&page_size=100
*/
public NewApiResponse<Map<String, Object>> getModels(Integer page, Integer pageSize) {
String url = newApiProperties.getBaseUrl() + "/api/models/";
if (page != null || pageSize != null) {
StringBuilder sb = new StringBuilder(url).append("?");
if (page != null) sb.append("p=").append(page);
if (page != null && pageSize != null) sb.append("&");
if (pageSize != null) sb.append("page_size=").append(pageSize);
url = sb.toString();
}
log.info("[NewApiClient.getModels] 请求URL: {}", url);
try {
HttpResponse response = HttpRequest.get(url)
.header(HEADER_USER, newApiProperties.getAdminUserId())
.header(HEADER_AUTH, "Bearer " + newApiProperties.getAdminToken())
.timeout(30000)
.execute();
log.info("[NewApiClient.getModels] 响应状态: {}", response.getStatus());
return parseMapResponse(response);
} catch (Exception e) {
log.error("[NewApiClient.getModels] 请求异常", e);
return NewApiResponse.<Map<String, Object>>builder()
.success(false)
.message("请求异常: " + e.getMessage())
.httpResponse(null)
.build();
}
}
@SuppressWarnings("unchecked")
private NewApiResponse<Map<String, Object>> parseMapResponse(HttpResponse response) {
try {
String body = response.body();
if (StrUtil.isBlank(body)) {
log.warn("[NewApiClient.parseMapResponse] 响应为空,status={}", response.getStatus());
return NewApiResponse.<Map<String, Object>>builder()
.success(false)
.message("Empty response")
.httpResponse(response)
.build();
}
// 调试日志:记录原始响应体(截断避免过长)
String bodyPreview = body.length() > 500 ? body.substring(0, 500) + "..." : body;
log.info("[NewApiClient.parseMapResponse] status={}, body={}", response.getStatus(), bodyPreview);
// 使用 Jackson 解析(兼容 New API 返回的含特殊字符 JSON)
Map<String, Object> root = objectMapper.readValue(body, new TypeReference<Map<String, Object>>() {});
NewApiResponse<Map<String, Object>> result = new NewApiResponse<>();
result.setSuccess(root.get("success") == null ? null : Boolean.valueOf(root.get("success").toString()));
result.setMessage(root.get("message") == null ? null : root.get("message").toString());
result.setHttpResponse(response);
if (root.containsKey("data") && root.get("data") != null) {
Object data = root.get("data");
if (data instanceof Map) {
result.setData((Map<String, Object>) data);
} else {
// data 是其他类型(List 等),原样返回,调用方自行处理
Map<String, Object> wrapper = new HashMap<>();
wrapper.put("data", data);
result.setData(wrapper);
}
}
return result;
} catch (Exception e) {
log.error("[NewApiClient.parseMapResponse] 解析响应异常,body={}", response.body(), e);
return NewApiResponse.<Map<String, Object>>builder()
.success(false)
.message("解析响应失败: " + e.getMessage())
.build();
}
}
@SuppressWarnings("unchecked")
private <T> NewApiResponse<T> parseResponse(HttpResponse response, Class<T> dataClass) {
try {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment