This commit is contained in:
Leo
2025-12-05 22:16:25 +08:00
parent 7581cc02a9
commit 2524461ff4

View File

@@ -24,10 +24,12 @@ public class LogisticsServiceImpl implements ILogisticsService {
private static final Logger logger = LoggerFactory.getLogger(LogisticsServiceImpl.class); private static final Logger logger = LoggerFactory.getLogger(LogisticsServiceImpl.class);
private static final String REDIS_WAYBILL_KEY_PREFIX = "logistics:waybill:order:"; private static final String REDIS_WAYBILL_KEY_PREFIX = "logistics:waybill:order:";
private static final String REDIS_LOCK_KEY_PREFIX = "logistics:lock:order:";
private static final String EXTERNAL_API_URL = "http://192.168.8.88:5001/fetch_logistics?tracking_url="; private static final String EXTERNAL_API_URL = "http://192.168.8.88:5001/fetch_logistics?tracking_url=";
private static final String PUSH_URL = "https://wxts.van333.cn/wx/send/pdd"; private static final String PUSH_URL = "https://wxts.van333.cn/wx/send/pdd";
private static final String PUSH_TOKEN = "super_token_b62190c26"; private static final String PUSH_TOKEN = "super_token_b62190c26";
private static final String CONFIG_KEY_PREFIX = "logistics.push.touser."; private static final String CONFIG_KEY_PREFIX = "logistics.push.touser.";
private static final long LOCK_EXPIRE_SECONDS = 300; // 锁过期时间5分钟防止死锁
@Resource @Resource
private StringRedisTemplate stringRedisTemplate; private StringRedisTemplate stringRedisTemplate;
@@ -51,27 +53,49 @@ public class LogisticsServiceImpl implements ILogisticsService {
return false; return false;
} }
// 检查物流链接 Long orderId = order.getId();
String logisticsLink = order.getLogisticsLink();
if (logisticsLink == null || logisticsLink.trim().isEmpty()) { // 双重检查:先检查是否已处理过
logger.info("订单暂无物流链接,跳过处理 - 订单ID: {}", order.getId()); if (isOrderProcessed(orderId)) {
return false; logger.info("订单已处理过,跳过 - 订单ID: {}", orderId);
return true; // 返回true表示已处理避免重复处理
}
// 获取分布式锁,防止并发处理同一订单
String lockKey = REDIS_LOCK_KEY_PREFIX + orderId;
Boolean lockAcquired = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "locked", LOCK_EXPIRE_SECONDS, TimeUnit.SECONDS);
if (Boolean.FALSE.equals(lockAcquired)) {
logger.warn("订单正在被其他线程处理,跳过 - 订单ID: {}", orderId);
return false; // 其他线程正在处理返回false让调用方稍后重试
} }
try { try {
// 获取锁后再次检查是否已处理(双重检查锁定模式)
if (isOrderProcessed(orderId)) {
logger.info("订单在获取锁后检查发现已处理,跳过 - 订单ID: {}", orderId);
return true;
}
// 检查物流链接
String logisticsLink = order.getLogisticsLink();
if (logisticsLink == null || logisticsLink.trim().isEmpty()) {
logger.info("订单暂无物流链接,跳过处理 - 订单ID: {}", orderId);
return false;
}
// 构建外部接口URL // 构建外部接口URL
String externalUrl = EXTERNAL_API_URL + URLEncoder.encode(logisticsLink, "UTF-8"); String externalUrl = EXTERNAL_API_URL + URLEncoder.encode(logisticsLink, "UTF-8");
logger.info("调用外部接口获取物流信息 - 订单ID: {}, URL: {}", order.getId(), externalUrl); logger.info("调用外部接口获取物流信息 - 订单ID: {}, URL: {}", orderId, externalUrl);
// 在服务端执行HTTP请求 // 在服务端执行HTTP请求
String result = HttpUtils.sendGet(externalUrl); String result = HttpUtils.sendGet(externalUrl);
if (result == null || result.trim().isEmpty()) { if (result == null || result.trim().isEmpty()) {
logger.warn("外部接口返回空结果 - 订单ID: {}", order.getId()); logger.warn("外部接口返回空结果 - 订单ID: {}", orderId);
return false; return false;
} }
logger.info("外部接口调用成功 - 订单ID: {}, 返回数据长度: {}", order.getId(), result.length()); logger.info("外部接口调用成功 - 订单ID: {}, 返回数据长度: {}", orderId, result.length());
// 解析返回结果 // 解析返回结果
JSONObject parsedData = null; JSONObject parsedData = null;
@@ -80,46 +104,59 @@ public class LogisticsServiceImpl implements ILogisticsService {
if (parsed instanceof JSONObject) { if (parsed instanceof JSONObject) {
parsedData = (JSONObject) parsed; parsedData = (JSONObject) parsed;
} else { } else {
logger.warn("返回数据不是JSON对象格式 - 订单ID: {}", order.getId()); logger.warn("返回数据不是JSON对象格式 - 订单ID: {}", orderId);
return false; return false;
} }
} catch (Exception e) { } catch (Exception e) {
logger.warn("解析返回数据失败 - 订单ID: {}, 错误: {}", order.getId(), e.getMessage()); logger.warn("解析返回数据失败 - 订单ID: {}, 错误: {}", orderId, e.getMessage());
return false; return false;
} }
// 检查waybill_no // 检查waybill_no
JSONObject dataObj = parsedData.getJSONObject("data"); JSONObject dataObj = parsedData.getJSONObject("data");
if (dataObj == null) { if (dataObj == null) {
logger.info("返回数据中没有data字段 - 订单ID: {}", order.getId()); logger.info("返回数据中没有data字段 - 订单ID: {}", orderId);
return false; return false;
} }
String waybillNo = dataObj.getString("waybill_no"); String waybillNo = dataObj.getString("waybill_no");
if (waybillNo == null || waybillNo.trim().isEmpty()) { if (waybillNo == null || waybillNo.trim().isEmpty()) {
logger.info("waybill_no为空无需处理 - 订单ID: {}", order.getId()); logger.info("waybill_no为空无需处理 - 订单ID: {}", orderId);
return false; return false;
} }
logger.info("检测到waybill_no: {} - 订单ID: {}", waybillNo, order.getId()); logger.info("检测到waybill_no: {} - 订单ID: {}", waybillNo, orderId);
// 调用企业应用推送,只有推送成功才记录状态 // 调用企业应用推送,只有推送成功才记录状态
boolean pushSuccess = sendEnterprisePushNotification(order, waybillNo); boolean pushSuccess = sendEnterprisePushNotification(order, waybillNo);
if (!pushSuccess) { if (!pushSuccess) {
logger.warn("企业微信推送未确认成功,稍后将重试 - 订单ID: {}, waybill_no: {}", order.getId(), waybillNo); logger.warn("企业微信推送未确认成功,稍后将重试 - 订单ID: {}, waybill_no: {}", orderId, waybillNo);
return false; return false;
} }
// 保存运单号到Redis避免重复处理 // 保存运单号到Redis避免重复处理- 使用原子操作确保只写入一次
String redisKey = REDIS_WAYBILL_KEY_PREFIX + order.getId(); String redisKey = REDIS_WAYBILL_KEY_PREFIX + orderId;
stringRedisTemplate.opsForValue().set(redisKey, waybillNo, 30, TimeUnit.DAYS); Boolean setSuccess = stringRedisTemplate.opsForValue().setIfAbsent(redisKey, waybillNo, 30, TimeUnit.DAYS);
logger.info("物流信息获取并推送成功 - 订单ID: {}, waybill_no: {}", order.getId(), waybillNo); if (Boolean.FALSE.equals(setSuccess)) {
// 如果Redis中已存在说明可能被其他线程处理了记录警告但不算失败
logger.warn("订单运单号已存在(可能被并发处理),但推送已成功 - 订单ID: {}, waybill_no: {}", orderId, waybillNo);
}
logger.info("物流信息获取并推送成功 - 订单ID: {}, waybill_no: {}", orderId, waybillNo);
return true; return true;
} catch (Exception e) { } catch (Exception e) {
logger.error("获取物流信息失败 - 订单ID: {}, 错误: {}", order.getId(), e.getMessage(), e); logger.error("获取物流信息失败 - 订单ID: {}, 错误: {}", orderId, e.getMessage(), e);
return false; return false;
} finally {
// 释放分布式锁
try {
stringRedisTemplate.delete(lockKey);
logger.debug("释放订单处理锁 - 订单ID: {}", orderId);
} catch (Exception e) {
logger.warn("释放订单处理锁失败 - 订单ID: {}, 错误: {}", orderId, e.getMessage());
}
} }
} }
@@ -238,31 +275,64 @@ public class LogisticsServiceImpl implements ILogisticsService {
* @return 是否成功 * @return 是否成功
*/ */
private boolean isPushResponseSuccess(String pushResult) { private boolean isPushResponseSuccess(String pushResult) {
if (pushResult == null || pushResult.trim().isEmpty()) {
logger.warn("推送响应为空,视为失败");
return false;
}
try { try {
JSONObject response = JSON.parseObject(pushResult); JSONObject response = JSON.parseObject(pushResult);
if (response == null) { if (response == null) {
logger.warn("推送响应解析为null视为失败。原始响应: {}", pushResult);
return false; return false;
} }
Integer code = response.getInteger("code"); Integer code = response.getInteger("code");
Boolean successFlag = response.getBoolean("success"); Boolean successFlag = response.getBoolean("success");
String status = response.getString("status"); String status = response.getString("status");
String message = response.getString("msg"); String message = response.getString("msg");
String errcode = response.getString("errcode");
// 记录完整的响应信息用于调试
logger.debug("推送响应解析 - code: {}, success: {}, status: {}, msg: {}, errcode: {}",
code, successFlag, status, message, errcode);
// 检查错误码errcode为0表示成功
if (errcode != null && "0".equals(errcode)) {
logger.info("推送成功通过errcode=0判断");
return true;
}
// 检查code字段0或200表示成功
if (code != null && (code == 0 || code == 200)) { if (code != null && (code == 0 || code == 200)) {
logger.info("推送成功通过code={}判断)", code);
return true; return true;
} }
// 检查success字段
if (Boolean.TRUE.equals(successFlag)) { if (Boolean.TRUE.equals(successFlag)) {
logger.info("推送成功通过success=true判断");
return true; return true;
} }
// 检查status字段
if (status != null && ("success".equalsIgnoreCase(status) || "ok".equalsIgnoreCase(status))) { if (status != null && ("success".equalsIgnoreCase(status) || "ok".equalsIgnoreCase(status))) {
logger.info("推送成功通过status={}判断)", status);
return true; return true;
} }
// 检查message字段某些接口可能用message表示成功
if (message != null && ("success".equalsIgnoreCase(message) || "ok".equalsIgnoreCase(message))) { if (message != null && ("success".equalsIgnoreCase(message) || "ok".equalsIgnoreCase(message))) {
logger.info("推送成功通过message={}判断)", message);
return true; return true;
} }
// 如果所有判断都失败,记录详细信息
logger.warn("推送响应未确认成功 - code: {}, success: {}, status: {}, msg: {}, errcode: {}, 完整响应: {}",
code, successFlag, status, message, errcode, pushResult);
return false; return false;
} catch (Exception e) { } catch (Exception e) {
logger.warn("解析企业应用推送响应失败,将视为未成功: {}", e.getMessage()); logger.error("解析企业应用推送响应失败,将视为未成功。原始响应: {}, 错误: {}", pushResult, e.getMessage(), e);
return false; return false;
} }
} }