This commit is contained in:
2025-10-30 16:25:36 +08:00
parent 5408f9a21d
commit 3c44408f4f

View File

@@ -163,53 +163,108 @@ public class BatchPublishServiceImpl implements IBatchPublishService
log.info("提取的URLs: {}", urls);
log.info("提取的SKUIDs: {}", skuids);
// 查询商品详情
// 查询商品详情保证与输入URL数量一致且顺序一致失败使用占位
List<Map<String, Object>> products = new ArrayList<>();
Set<String> processedSkuids = new HashSet<>();
// 优先处理URL更准确
for (int i = 0; i < urls.size(); i++) {
String url = urls.get(i);
try {
log.info("正在处理第 {}/{} 个URL: {}", i + 1, urls.size(), url);
Map<String, Object> productInfo = queryProductInfo(url);
Map<String, Object> productInfo = queryProductInfoWithRetry(url, 2, 200);
if (productInfo == null) {
log.warn("URL解析返回空结果: {}", url);
log.warn("URL解析失败,使用占位返回: {}", url);
Map<String, Object> placeholder = new HashMap<>();
placeholder.put("skuid", null);
placeholder.put("productName", "未解析:" + url);
placeholder.put("price", null);
placeholder.put("productImage", null);
placeholder.put("shopName", null);
placeholder.put("shopId", null);
placeholder.put("commission", null);
placeholder.put("commissionShare", null);
placeholder.put("commissionInfo", null);
placeholder.put("materialUrl", url);
placeholder.put("images", Collections.emptyList());
placeholder.put("wenan", Collections.emptyList());
placeholder.put("_raw", Collections.singletonMap("sourceUrl", url));
placeholder.put("parseFailed", true);
products.add(placeholder);
continue;
}
String skuid = (String) productInfo.get("skuid");
if (skuid == null || skuid.trim().isEmpty()) {
log.warn("商品SKUID为空URL: {}, 返回数据: {}", url, productInfo);
continue;
}
if (processedSkuids.contains(skuid)) {
log.info("SKUID已存在跳过: {}", skuid);
continue;
}
// 不对URL阶段做去重保持与输入一致允许同款多条
products.add(productInfo);
processedSkuids.add(skuid);
log.info("成功添加商品: SKUID={}, 名称={}", skuid, productInfo.get("productName"));
Object skuObj = productInfo.get("skuid");
if (skuObj != null) {
processedSkuids.add(String.valueOf(skuObj));
}
} catch (Exception e) {
log.error("查询商品信息失败URL: {}", url, e);
log.error("查询商品信息异常(占位返回)URL: {}", url, e);
Map<String, Object> placeholder = new HashMap<>();
placeholder.put("skuid", null);
placeholder.put("productName", "未解析:" + url);
placeholder.put("price", null);
placeholder.put("productImage", null);
placeholder.put("shopName", null);
placeholder.put("shopId", null);
placeholder.put("commission", null);
placeholder.put("commissionShare", null);
placeholder.put("commissionInfo", null);
placeholder.put("materialUrl", url);
placeholder.put("images", Collections.emptyList());
placeholder.put("wenan", Collections.emptyList());
placeholder.put("_raw", Collections.singletonMap("sourceUrl", url));
placeholder.put("parseFailed", true);
products.add(placeholder);
}
}
// 处理剩余的SKUID
// 额外处理文本中单独出现的SKUID避免重复
for (String skuid : skuids) {
if (!processedSkuids.contains(skuid)) {
try {
Map<String, Object> productInfo = queryProductInfo(skuid);
Map<String, Object> productInfo = queryProductInfoWithRetry(skuid, 2, 200);
if (productInfo != null) {
products.add(productInfo);
processedSkuids.add(skuid);
} else {
Map<String, Object> placeholder = new HashMap<>();
placeholder.put("skuid", skuid);
placeholder.put("productName", "未解析:" + skuid);
placeholder.put("price", null);
placeholder.put("productImage", null);
placeholder.put("shopName", null);
placeholder.put("shopId", null);
placeholder.put("commission", null);
placeholder.put("commissionShare", null);
placeholder.put("commissionInfo", null);
placeholder.put("materialUrl", null);
placeholder.put("images", Collections.emptyList());
placeholder.put("wenan", Collections.emptyList());
placeholder.put("_raw", Collections.singletonMap("skuid", skuid));
placeholder.put("parseFailed", true);
products.add(placeholder);
}
} catch (Exception e) {
log.error("查询商品信息失败SKUID: {}", skuid, e);
log.error("查询商品信息失败(占位返回)SKUID: {}", skuid, e);
Map<String, Object> placeholder = new HashMap<>();
placeholder.put("skuid", skuid);
placeholder.put("productName", "未解析:" + skuid);
placeholder.put("price", null);
placeholder.put("productImage", null);
placeholder.put("shopName", null);
placeholder.put("shopId", null);
placeholder.put("commission", null);
placeholder.put("commissionShare", null);
placeholder.put("commissionInfo", null);
placeholder.put("materialUrl", null);
placeholder.put("images", Collections.emptyList());
placeholder.put("wenan", Collections.emptyList());
placeholder.put("_raw", Collections.singletonMap("skuid", skuid));
placeholder.put("parseFailed", true);
products.add(placeholder);
}
}
}
@@ -255,6 +310,32 @@ public class BatchPublishServiceImpl implements IBatchPublishService
}
}
/**
* 带重试的商品信息查询
* @param urlOrSkuid 传入URL或SKUID
* @param retries 重试次数
* @param backoffMillis 两次尝试之间等待毫秒
*/
private Map<String, Object> queryProductInfoWithRetry(String urlOrSkuid, int retries, long backoffMillis) {
int attempts = 0;
while (attempts <= retries) {
Map<String, Object> result = queryProductInfo(urlOrSkuid);
if (result != null) {
return result;
}
attempts++;
if (attempts <= retries) {
try {
Thread.sleep(backoffMillis);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
}
return null;
}
/**
* 规范化商品信息
*/
@@ -529,7 +610,9 @@ public class BatchPublishServiceImpl implements IBatchPublishService
shop.setProvince(commonParams.getProvince());
shop.setCity(commonParams.getCity());
shop.setDistrict(commonParams.getDistrict());
shop.setTitle(item.getProductName()); // 使用商品名称
// 标题长度限制最多60个字符做安全截断按code point防止截断表情
String title = item.getProductName();
shop.setTitle(truncateByCodePoints(title, 60));
// 【修改】使用用户选择的文案
String content = getSelectedWenanContent(productConfig);
@@ -643,6 +726,24 @@ public class BatchPublishServiceImpl implements IBatchPublishService
return wenanItem != null ? wenanItem.getContent() : null;
}
/**
* 安全按字符数截断字符串按Unicode code point避免截断表情导致乱码
*/
private String truncateByCodePoints(String text, int maxChars) {
if (text == null) {
return null;
}
if (maxChars <= 0) {
return "";
}
final int length = text.codePointCount(0, text.length());
if (length <= maxChars) {
return text;
}
int endIndex = text.offsetByCodePoints(0, maxChars);
return text.substring(0, endIndex);
}
/**
* 延迟上架商品