1
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user