package com.designhub.service; import com.designhub.dto.ExternalAssetDTO; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.*; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; /** * 第三方素材API服务 * 用于查询外部素材系统的任务完成状态和下载链接 */ @Slf4j @Service @RequiredArgsConstructor public class ExternalAssetService { private final SystemConfigService systemConfigService; private final RestTemplate restTemplate; private final ObjectMapper objectMapper; /** * 查询任务素材 * @param taskNo 任务编号 * @return 素材信息,包含下载链接 */ public ExternalAssetDTO queryAssets(String taskNo) { String apiUrl = systemConfigService.getConfigValue("external_asset_api_url"); String apiKey = systemConfigService.getConfigValue("external_asset_api_key"); if (apiUrl == null || apiUrl.isEmpty()) { log.warn("第三方素材API地址未配置"); ExternalAssetDTO result = new ExternalAssetDTO(); result.setSuccess(false); ExternalAssetDTO.ErrorInfo error = new ExternalAssetDTO.ErrorInfo(); error.setCode("CONFIG_ERROR"); error.setMessage("第三方素材API未配置"); result.setError(error); return result; } if (apiKey == null || apiKey.isEmpty()) { log.warn("第三方素材API Key未配置"); ExternalAssetDTO result = new ExternalAssetDTO(); result.setSuccess(false); ExternalAssetDTO.ErrorInfo error = new ExternalAssetDTO.ErrorInfo(); error.setCode("CONFIG_ERROR"); error.setMessage("第三方素材API Key未配置"); result.setError(error); return result; } try { // 构建请求URL String url = apiUrl.endsWith("/") ? apiUrl : apiUrl + "/"; url = url + "product-assets?taskNo=" + taskNo; log.info("查询第三方素材API: {}", url); // 构建请求头 HttpHeaders headers = new HttpHeaders(); headers.set("X-API-Key", apiKey); headers.setContentType(MediaType.APPLICATION_JSON); HttpEntity entity = new HttpEntity<>(headers); // 发送请求 ResponseEntity response = restTemplate.exchange( url, HttpMethod.GET, entity, String.class ); log.info("第三方素材API响应状态: {}", response.getStatusCode()); log.debug("第三方素材API响应内容: {}", response.getBody()); if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) { return objectMapper.readValue(response.getBody(), ExternalAssetDTO.class); } else { ExternalAssetDTO result = new ExternalAssetDTO(); result.setSuccess(false); ExternalAssetDTO.ErrorInfo error = new ExternalAssetDTO.ErrorInfo(); error.setCode("REQUEST_FAILED"); error.setMessage("请求失败: " + response.getStatusCode()); result.setError(error); return result; } } catch (Exception e) { log.error("调用第三方素材API失败", e); ExternalAssetDTO result = new ExternalAssetDTO(); result.setSuccess(false); ExternalAssetDTO.ErrorInfo error = new ExternalAssetDTO.ErrorInfo(); error.setCode("EXCEPTION"); error.setMessage("调用API失败: " + e.getMessage()); result.setError(error); return result; } } /** * 检查任务素材是否完成 * @param taskNo 任务编号 * @return 下载链接(如果完成),否则返回null */ public String checkTaskCompletion(String taskNo) { ExternalAssetDTO result = queryAssets(taskNo); if (result.isSuccess() && result.getData() != null) { ExternalAssetDTO.DownloadUrls urls = result.getData().getDownloadUrls(); if (urls != null && urls.getAll() != null && !urls.getAll().isEmpty()) { log.info("任务 {} 素材已完成,下载链接: {}", taskNo, urls.getAll()); return urls.getAll(); } } log.info("任务 {} 素材未完成或查询失败", taskNo); return null; } /** * 测试API连接 * @return 测试结果 */ public boolean testConnection() { String apiUrl = systemConfigService.getConfigValue("external_asset_api_url"); String apiKey = systemConfigService.getConfigValue("external_asset_api_key"); if (apiUrl == null || apiUrl.isEmpty() || apiKey == null || apiKey.isEmpty()) { log.warn("第三方素材API配置不完整"); return false; } try { // 测试连接(使用正确格式的测试任务号) String url = apiUrl.endsWith("/") ? apiUrl : apiUrl + "/"; url = url + "product-assets?taskNo=TASK000000000000"; log.info("测试第三方素材API连接: {}", url); HttpHeaders headers = new HttpHeaders(); headers.set("X-API-Key", apiKey); HttpEntity entity = new HttpEntity<>(headers); ResponseEntity response = restTemplate.exchange( url, HttpMethod.GET, entity, String.class ); log.info("测试连接响应状态: {}", response.getStatusCode()); // 只要能收到响应(无论是404还是200),说明连接正常 return response.getStatusCode().is2xxSuccessful() || response.getStatusCode() == HttpStatus.NOT_FOUND; } catch (org.springframework.web.client.HttpClientErrorException e) { // HTTP 4xx 错误 log.info("测试连接HTTP错误: {} - {}", e.getStatusCode(), e.getResponseBodyAsString()); // 400 Bad Request 但是包含业务错误码(如TASK_NOT_FOUND, INVALID_TASK_NO) // 说明API连接正常,只是参数不对 if (e.getStatusCode() == HttpStatus.BAD_REQUEST) { String body = e.getResponseBodyAsString(); if (body.contains("TASK_NOT_FOUND") || body.contains("INVALID_TASK_NO")) { log.info("API连接正常,测试任务号不存在或格式不对(这是正常的)"); return true; } } // 404 Not Found 也说明连接正常 if (e.getStatusCode() == HttpStatus.NOT_FOUND) { log.info("API连接正常,任务不存在(这是正常的)"); return true; } // 401/403 认证错误 if (e.getStatusCode() == HttpStatus.UNAUTHORIZED || e.getStatusCode() == HttpStatus.FORBIDDEN) { log.error("API密钥无效或权限不足"); return false; } return false; } catch (Exception e) { log.error("测试第三方素材API连接失败: {}", e.getMessage()); return false; } } }