1
This commit is contained in:
@@ -551,6 +551,66 @@ public class JDInnerController {
|
||||
* 返回:{ message, success }
|
||||
* 注意:请将skey放在请求Body中(JSON格式),不是Query参数
|
||||
*/
|
||||
/**
|
||||
* 回填历史订单 goodsInfo(店铺名、商品图)
|
||||
* Body: { "skey": "...", "orderIds": "352543902480387,3525433002460987" }
|
||||
* 或: { "skey": "...", "missing": true, "limit": 100 }
|
||||
*/
|
||||
@PostMapping("/backfillGoodsInfo")
|
||||
public Object backfillGoodsInfo(@RequestBody(required = false) Map<String, Object> body) {
|
||||
if (body == null || body.isEmpty()) {
|
||||
return error("请求Body不能为空,示例: {\"skey\":\"...\",\"orderIds\":\"订单号1,订单号2\"}");
|
||||
}
|
||||
String skey = body.get("skey") != null ? String.valueOf(body.get("skey")) : null;
|
||||
if (checkSkey(skey)) {
|
||||
return error("invalid skey");
|
||||
}
|
||||
try {
|
||||
boolean missing = body.get("missing") != null && Boolean.parseBoolean(String.valueOf(body.get("missing")));
|
||||
int limit = parseInt(body.get("limit"), 50);
|
||||
if (missing) {
|
||||
return jdScheduleJob.backfillMissingGoodsInfo(limit);
|
||||
}
|
||||
List<String> orderNos = parseOrderIdList(body.get("orderIds"));
|
||||
if (orderNos.isEmpty()) {
|
||||
return error("请提供 orderIds(逗号分隔)或 missing=true");
|
||||
}
|
||||
return jdScheduleJob.backfillGoodsInfoByOrderNos(orderNos);
|
||||
} catch (Exception e) {
|
||||
logger.error("backfillGoodsInfo error", e);
|
||||
return error("backfillGoodsInfo failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static List<String> parseOrderIdList(Object raw) {
|
||||
List<String> result = new ArrayList<>();
|
||||
if (raw == null) {
|
||||
return result;
|
||||
}
|
||||
if (raw instanceof Collection<?> collection) {
|
||||
for (Object item : collection) {
|
||||
if (item != null) {
|
||||
String s = String.valueOf(item).trim();
|
||||
if (!s.isEmpty()) {
|
||||
result.add(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
String text = String.valueOf(raw).trim();
|
||||
if (text.isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
for (String part : text.split("[,,\\s]+")) {
|
||||
String s = part.trim();
|
||||
if (!s.isEmpty()) {
|
||||
result.add(s);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@PostMapping("/cleanRedisData")
|
||||
public Object cleanRedisData(@RequestBody(required = false) Map<String, Object> body) {
|
||||
// 兼容处理:如果body为空,返回友好提示
|
||||
|
||||
@@ -8,6 +8,7 @@ package cn.van.business.repository;
|
||||
*/
|
||||
|
||||
import cn.van.business.model.jd.OrderRow;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
@@ -62,6 +63,9 @@ public interface OrderRowRepository extends JpaRepository<OrderRow, String> {
|
||||
|
||||
List<OrderRow> findByUnionId(long l);
|
||||
|
||||
@Query("SELECT DISTINCT o.orderId FROM OrderRow o WHERE o.goodsInfoId IS NULL AND o.orderId IS NOT NULL ORDER BY o.orderTime DESC")
|
||||
List<Long> findDistinctOrderIdsWithNullGoodsInfo(Pageable pageable);
|
||||
|
||||
//// 在OrderRowRepository中添加模糊查询方法
|
||||
//// 模糊查询收件人姓名或地址(包含分页)
|
||||
//@Query("SELECT o FROM OrderRow o WHERE " + "o.recipientName LIKE %:keyword% OR " + "o.address LIKE %:keyword% " + "ORDER BY o.orderTime DESC")
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.redis.core.HashOperations;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
@@ -199,6 +200,174 @@ public class JDScheduleJob {
|
||||
return goodsInfoRepository.save(vo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按订单号批量回填 goodsInfo(店铺名、商品图)
|
||||
*
|
||||
* @param orderNos 订单号列表(子单号或父单号)
|
||||
*/
|
||||
public Map<String, Object> backfillGoodsInfoByOrderNos(List<String> orderNos) {
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
List<Map<String, Object>> details = new ArrayList<>();
|
||||
int updated = 0;
|
||||
int failed = 0;
|
||||
int skipped = 0;
|
||||
|
||||
List<SuperAdmin> admins = activeSuperAdmins();
|
||||
if (admins.isEmpty()) {
|
||||
result.put("success", false);
|
||||
result.put("message", "未找到可用的联盟 appKey/secretKey");
|
||||
return result;
|
||||
}
|
||||
|
||||
if (orderNos == null || orderNos.isEmpty()) {
|
||||
result.put("success", false);
|
||||
result.put("message", "orderIds 不能为空");
|
||||
return result;
|
||||
}
|
||||
|
||||
for (String orderNo : orderNos) {
|
||||
Map<String, Object> item = new LinkedHashMap<>();
|
||||
item.put("orderId", orderNo);
|
||||
if (orderNo == null || orderNo.isBlank()) {
|
||||
item.put("status", "skipped");
|
||||
item.put("reason", "空订单号");
|
||||
skipped++;
|
||||
details.add(item);
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
Long orderId = Long.parseLong(orderNo.trim());
|
||||
int rows = backfillGoodsInfoForOrderId(orderId, admins);
|
||||
if (rows > 0) {
|
||||
item.put("status", "updated");
|
||||
item.put("rows", rows);
|
||||
updated++;
|
||||
} else {
|
||||
item.put("status", "skipped");
|
||||
item.put("reason", "京东未返回 goodsInfo 或本地无匹配行");
|
||||
skipped++;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
item.put("status", "failed");
|
||||
item.put("reason", e.getMessage());
|
||||
failed++;
|
||||
logger.warn("回填 goodsInfo 失败 orderId={}", orderNo, e);
|
||||
}
|
||||
details.add(item);
|
||||
sleepQuietly(200);
|
||||
}
|
||||
|
||||
result.put("success", failed == 0);
|
||||
result.put("total", orderNos.size());
|
||||
result.put("updated", updated);
|
||||
result.put("skipped", skipped);
|
||||
result.put("failed", failed);
|
||||
result.put("details", details);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动回填 goods_info_id 为空的最近订单
|
||||
*/
|
||||
public Map<String, Object> backfillMissingGoodsInfo(int limit) {
|
||||
int safeLimit = limit <= 0 ? 50 : Math.min(limit, 500);
|
||||
List<Long> orderIds = orderRowRepository.findDistinctOrderIdsWithNullGoodsInfo(PageRequest.of(0, safeLimit));
|
||||
List<String> orderNos = orderIds.stream().map(String::valueOf).collect(Collectors.toList());
|
||||
Map<String, Object> result = backfillGoodsInfoByOrderNos(orderNos);
|
||||
result.put("mode", "missing");
|
||||
result.put("limit", safeLimit);
|
||||
return result;
|
||||
}
|
||||
|
||||
private int backfillGoodsInfoForOrderId(Long orderId, List<SuperAdmin> admins) throws Exception {
|
||||
for (SuperAdmin admin : admins) {
|
||||
int updated = backfillGoodsInfoForOrderId(orderId, admin.getAppKey(), admin.getSecretKey());
|
||||
if (updated > 0) {
|
||||
return updated;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int backfillGoodsInfoForOrderId(Long orderId, String appKey, String secretKey) throws Exception {
|
||||
int updated = 0;
|
||||
int pageIndex = 1;
|
||||
boolean hasMore = true;
|
||||
while (hasMore) {
|
||||
UnionOpenOrderRowQueryResponse response = queryByOrderId(orderId, pageIndex, appKey, secretKey);
|
||||
if (response == null || response.getQueryResult() == null
|
||||
|| response.getQueryResult().getCode() != 200
|
||||
|| response.getQueryResult().getData() == null) {
|
||||
break;
|
||||
}
|
||||
OrderRowResp[] data = response.getQueryResult().getData();
|
||||
for (OrderRowResp resp : data) {
|
||||
if (resp == null) {
|
||||
continue;
|
||||
}
|
||||
updated += applyGoodsInfoFromResponse(resp);
|
||||
}
|
||||
hasMore = Boolean.TRUE.equals(response.getQueryResult().getHasMore());
|
||||
pageIndex++;
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
private int applyGoodsInfoFromResponse(OrderRowResp resp) {
|
||||
GoodsInfoVO goodsInfoVO = resolveGoodsInfo(resp.getGoodsInfo(), resp.getSkuId());
|
||||
if (goodsInfoVO == null) {
|
||||
return 0;
|
||||
}
|
||||
int updated = 0;
|
||||
if (resp.getId() != null) {
|
||||
Optional<OrderRow> local = orderRowRepository.findById(resp.getId());
|
||||
if (local.isPresent()) {
|
||||
OrderRow row = local.get();
|
||||
if (row.getGoodsInfoId() == null || !row.getGoodsInfoId().equals(goodsInfoVO.getId())) {
|
||||
row.setGoodsInfoId(goodsInfoVO.getId());
|
||||
orderRowRepository.save(row);
|
||||
updated++;
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
}
|
||||
OrderRow orderRow = createOrderRow(resp);
|
||||
orderRowRepository.save(orderRow);
|
||||
return 1;
|
||||
}
|
||||
|
||||
public UnionOpenOrderRowQueryResponse queryByOrderId(Long orderId, int pageIndex, String appKey, String secretKey) throws Exception {
|
||||
JdClient client = new DefaultJdClient(SERVER_URL, ACCESS_TOKEN, appKey, secretKey);
|
||||
UnionOpenOrderRowQueryRequest request = new UnionOpenOrderRowQueryRequest();
|
||||
OrderRowReq orderReq = new OrderRowReq();
|
||||
orderReq.setOrderId(orderId);
|
||||
orderReq.setFields("goodsInfo");
|
||||
orderReq.setPageIndex(pageIndex);
|
||||
orderReq.setPageSize(200);
|
||||
request.setOrderReq(orderReq);
|
||||
request.setVersion("1.0");
|
||||
request.setSignmethod("md5");
|
||||
Date date = new Date();
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
request.setTimestamp(simpleDateFormat.format(date));
|
||||
return client.execute(request);
|
||||
}
|
||||
|
||||
private List<SuperAdmin> activeSuperAdmins() {
|
||||
return super_admins.values().stream()
|
||||
.filter(a -> a.getAppKey() != null && !a.getAppKey().isBlank()
|
||||
&& a.getSecretKey() != null && !a.getSecretKey().isBlank())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private void sleepQuietly(long ms) {
|
||||
try {
|
||||
Thread.sleep(ms);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据指定的日期时间拉取订单
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user