1
This commit is contained in:
@@ -163,53 +163,108 @@ public class BatchPublishServiceImpl implements IBatchPublishService
|
|||||||
log.info("提取的URLs: {}", urls);
|
log.info("提取的URLs: {}", urls);
|
||||||
log.info("提取的SKUIDs: {}", skuids);
|
log.info("提取的SKUIDs: {}", skuids);
|
||||||
|
|
||||||
// 查询商品详情
|
// 查询商品详情(保证与输入URL数量一致且顺序一致;失败使用占位)
|
||||||
List<Map<String, Object>> products = new ArrayList<>();
|
List<Map<String, Object>> products = new ArrayList<>();
|
||||||
Set<String> processedSkuids = new HashSet<>();
|
Set<String> processedSkuids = new HashSet<>();
|
||||||
|
|
||||||
// 优先处理URL(更准确)
|
|
||||||
for (int i = 0; i < urls.size(); i++) {
|
for (int i = 0; i < urls.size(); i++) {
|
||||||
String url = urls.get(i);
|
String url = urls.get(i);
|
||||||
try {
|
try {
|
||||||
log.info("正在处理第 {}/{} 个URL: {}", i + 1, urls.size(), url);
|
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) {
|
if (productInfo == null) {
|
||||||
log.warn("URL解析返回空结果: {}", url);
|
log.warn("URL解析失败,使用占位返回: {}", url);
|
||||||
continue;
|
Map<String, Object> placeholder = new HashMap<>();
|
||||||
}
|
placeholder.put("skuid", null);
|
||||||
|
placeholder.put("productName", "未解析:" + url);
|
||||||
String skuid = (String) productInfo.get("skuid");
|
placeholder.put("price", null);
|
||||||
if (skuid == null || skuid.trim().isEmpty()) {
|
placeholder.put("productImage", null);
|
||||||
log.warn("商品SKUID为空,URL: {}, 返回数据: {}", url, productInfo);
|
placeholder.put("shopName", null);
|
||||||
continue;
|
placeholder.put("shopId", null);
|
||||||
}
|
placeholder.put("commission", null);
|
||||||
|
placeholder.put("commissionShare", null);
|
||||||
if (processedSkuids.contains(skuid)) {
|
placeholder.put("commissionInfo", null);
|
||||||
log.info("SKUID已存在,跳过: {}", skuid);
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 不对URL阶段做去重,保持与输入一致(允许同款多条)
|
||||||
products.add(productInfo);
|
products.add(productInfo);
|
||||||
processedSkuids.add(skuid);
|
Object skuObj = productInfo.get("skuid");
|
||||||
log.info("成功添加商品: SKUID={}, 名称={}", skuid, productInfo.get("productName"));
|
if (skuObj != null) {
|
||||||
|
processedSkuids.add(String.valueOf(skuObj));
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} 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) {
|
for (String skuid : skuids) {
|
||||||
if (!processedSkuids.contains(skuid)) {
|
if (!processedSkuids.contains(skuid)) {
|
||||||
try {
|
try {
|
||||||
Map<String, Object> productInfo = queryProductInfo(skuid);
|
Map<String, Object> productInfo = queryProductInfoWithRetry(skuid, 2, 200);
|
||||||
if (productInfo != null) {
|
if (productInfo != null) {
|
||||||
products.add(productInfo);
|
products.add(productInfo);
|
||||||
processedSkuids.add(skuid);
|
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) {
|
} 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.setProvince(commonParams.getProvince());
|
||||||
shop.setCity(commonParams.getCity());
|
shop.setCity(commonParams.getCity());
|
||||||
shop.setDistrict(commonParams.getDistrict());
|
shop.setDistrict(commonParams.getDistrict());
|
||||||
shop.setTitle(item.getProductName()); // 使用商品名称
|
// 标题长度限制:最多60个字符,做安全截断(按code point防止截断表情)
|
||||||
|
String title = item.getProductName();
|
||||||
|
shop.setTitle(truncateByCodePoints(title, 60));
|
||||||
|
|
||||||
// 【修改】使用用户选择的文案
|
// 【修改】使用用户选择的文案
|
||||||
String content = getSelectedWenanContent(productConfig);
|
String content = getSelectedWenanContent(productConfig);
|
||||||
@@ -643,6 +726,24 @@ public class BatchPublishServiceImpl implements IBatchPublishService
|
|||||||
return wenanItem != null ? wenanItem.getContent() : null;
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 延迟上架商品
|
* 延迟上架商品
|
||||||
|
|||||||
Reference in New Issue
Block a user