fix(pdd): 发品前归一化图片 URL,兼容主档 JSON 对象(path/url/name)

拼多多 thumb_url/carousel_gallery 仅接受 http(s) 字符串;若 sku 图或轮播误存为整段 JSON 会报图片 url 不合法。发布前从对象/数组中抽取 url 或 path。

Made-with: Cursor
This commit is contained in:
huangyujie 2026-03-25 19:14:46 +08:00
parent d375b548b0
commit eb5d00f998
1 changed files with 77 additions and 10 deletions

View File

@ -120,7 +120,7 @@ public class PddGoodsAddParamBuilder {
sku.put("quantity", row.getStockQty() != null ? row.getStockQty().longValue() : 0L);
sku.put("weight", row.getWeightGram() != null ? row.getWeightGram() : 1000L);
sku.put("spec_id_list", ov.getSpecIdList());
sku.put("thumb_url", StringUtils.hasText(row.getSkuImageUrl()) ? row.getSkuImageUrl() : thumbFallback);
sku.put("thumb_url", firstNonBlankImageUrl(row.getSkuImageUrl(), thumbFallback));
if (StringUtils.hasText(row.getOuterErpSkuId())) {
sku.put("out_sku_sn", row.getOuterErpSkuId());
}
@ -231,7 +231,7 @@ public class PddGoodsAddParamBuilder {
sku.put("quantity", qty);
sku.put("weight", row.getWeightGram() != null ? row.getWeightGram() : 1000L);
sku.put("spec_id_list", "[]");
sku.put("thumb_url", StringUtils.hasText(row.getSkuImageUrl()) ? row.getSkuImageUrl() : carousel.get(0));
sku.put("thumb_url", firstNonBlankImageUrl(row.getSkuImageUrl(), carousel.get(0)));
if (StringUtils.hasText(row.getOuterErpSkuId())) {
sku.put("out_sku_sn", row.getOuterErpSkuId());
}
@ -590,19 +590,84 @@ public class PddGoodsAddParamBuilder {
private static List<String> resolveCarousel(OGoods goods, ExternalGoodsUpsertRequest req) {
List<String> out = new ArrayList<>();
if (StringUtils.hasText(goods.getImage())) {
out.add(goods.getImage().trim());
}
addNormalizedCarouselUrl(out, goods != null ? goods.getImage() : null);
if (req != null && !CollectionUtils.isEmpty(req.getImages())) {
for (String u : req.getImages()) {
if (StringUtils.hasText(u) && !out.contains(u.trim())) {
out.add(u.trim());
}
addNormalizedCarouselUrl(out, u);
}
}
return out;
}
/**
* 主档/前端可能把图片存成 {@code {"url":"...","path":"...","name":"..."}} 整段 JSON
* 拼多多 {@code carousel_gallery}/{@code thumb_url} 仅接受可访问的 http(s) 字符串
*/
private static String normalizePddImageUrl(String raw) {
if (!StringUtils.hasText(raw)) {
return null;
}
String t = raw.trim();
if (t.startsWith("http://") || t.startsWith("https://")) {
return t;
}
if (t.startsWith("{")) {
try {
JSONObject o = JSON.parseObject(t);
if (o != null) {
String u = o.getString("url");
if (!StringUtils.hasText(u)) {
u = o.getString("path");
}
if (StringUtils.hasText(u)) {
return u.trim();
}
}
} catch (Exception ignored) {
}
return null;
}
if (t.startsWith("[")) {
try {
JSONArray arr = JSON.parseArray(t);
if (arr != null && !arr.isEmpty()) {
Object first = arr.get(0);
if (first instanceof String s) {
return normalizePddImageUrl(s);
}
if (first instanceof JSONObject jo) {
String u = jo.getString("url");
if (!StringUtils.hasText(u)) {
u = jo.getString("path");
}
if (StringUtils.hasText(u)) {
return u.trim();
}
}
}
} catch (Exception ignored) {
}
return null;
}
return t;
}
private static void addNormalizedCarouselUrl(List<String> out, String raw) {
String n = normalizePddImageUrl(raw);
if (StringUtils.hasText(n) && !out.contains(n)) {
out.add(n);
}
}
private static String firstNonBlankImageUrl(String primary, String fallback) {
String a = normalizePddImageUrl(primary);
if (StringUtils.hasText(a)) {
return a;
}
String b = normalizePddImageUrl(fallback);
return StringUtils.hasText(b) ? b : "";
}
private static List<String> resolveDetailImages(OGoods goods) {
if (!StringUtils.hasText(goods.getCanonicalExt())) {
return List.of();
@ -618,9 +683,11 @@ public class PddGoodsAddParamBuilder {
}
List<String> list = new ArrayList<>();
for (int i = 0; i < arr.size(); i++) {
String u = arr.getString(i);
Object el = arr.get(i);
String raw = el instanceof String s ? s : (el != null ? el.toString() : null);
String u = normalizePddImageUrl(raw);
if (StringUtils.hasText(u)) {
list.add(u.trim());
list.add(u);
}
}
return list;