From 909340092238dda7d49ac0eed8661a1363ea89c8 Mon Sep 17 00:00:00 2001 From: Joshi <3040996759@qq.com> Date: Wed, 13 Aug 2025 11:31:40 +0800 Subject: [PATCH] =?UTF-8?q?feat(oa):=20=E6=B7=BB=E5=8A=A0=E9=A1=BA?= =?UTF-8?q?=E5=BF=83=E6=8D=B7=E8=BE=BE=E5=BF=AB=E9=80=92=E8=BD=A8=E8=BF=B9?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 SxjdRouteQueryUtil工具类,用于查询顺心捷达快递轨迹 - 在OaExpressServiceImpl 中集成顺心捷达轨迹查询逻辑 - 实现了顺心捷达快递的轨迹查询和解析功能 --- .../oa/service/impl/OaExpressServiceImpl.java | 9 + .../ruoyi/oa/utils/SxjdRouteQueryUtil.java | 240 ++++++++++++++++++ 2 files changed, 249 insertions(+) create mode 100644 ruoyi-oa/src/main/java/com/ruoyi/oa/utils/SxjdRouteQueryUtil.java diff --git a/ruoyi-oa/src/main/java/com/ruoyi/oa/service/impl/OaExpressServiceImpl.java b/ruoyi-oa/src/main/java/com/ruoyi/oa/service/impl/OaExpressServiceImpl.java index 61b2615..e540015 100644 --- a/ruoyi-oa/src/main/java/com/ruoyi/oa/service/impl/OaExpressServiceImpl.java +++ b/ruoyi-oa/src/main/java/com/ruoyi/oa/service/impl/OaExpressServiceImpl.java @@ -244,6 +244,15 @@ public class OaExpressServiceImpl implements IOaExpressService { oaExpressVo.setLastStatus(stoVo.getFirstStatusName()); } } + if (expressType.equals("SXJD") && oaExpressVo.getStatus() == 1L) { + // 顺心捷达快递轨迹查询 + String result = SxjdRouteQueryUtil.queryRoute(oaExpressVo.getExpressCode()); + OaExpressVo sxjdVo = SxjdRouteQueryUtil.parseData(result); + if (sxjdVo != null) { + oaExpressVo.setLastUpdateTime(sxjdVo.getLastUpdateTime()); + oaExpressVo.setLastStatus(sxjdVo.getLastStatus()); + } + } OaExpress add = BeanUtil.toBean(oaExpressVo, OaExpress.class); baseMapper.updateById(add);; } diff --git a/ruoyi-oa/src/main/java/com/ruoyi/oa/utils/SxjdRouteQueryUtil.java b/ruoyi-oa/src/main/java/com/ruoyi/oa/utils/SxjdRouteQueryUtil.java new file mode 100644 index 0000000..5fa803c --- /dev/null +++ b/ruoyi-oa/src/main/java/com/ruoyi/oa/utils/SxjdRouteQueryUtil.java @@ -0,0 +1,240 @@ +package com.ruoyi.oa.utils; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; +import com.ruoyi.oa.domain.vo.OaExpressVo; +import org.apache.commons.lang3.StringUtils; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.util.Date; +import java.util.UUID; +import org.apache.commons.codec.binary.Base64; + +/** + * 顺心捷达路由地址查询工具 + */ +public class SxjdRouteQueryUtil { + + // 顺心捷达开放平台配置 + private static final String APP_KEY = "d2f3f98ebff25410e1280ed89c01be75"; + private static final String APP_CODE = "000466"; + private static final String APP_SECRET = "902379cccfa1981f23bfb1833264de87"; + private static final String SX_CUSTOMER_CODE = "C20001611"; + + // 顺心捷达API地址 - 根据环境选择 + // 测试环境: https://oms.sit.sf-express.com:9010/api/gateway/service + // 生产环境: https://oms.sxjdfreight.com/api/gateway/service + // 沙箱环境: https://oms.sxjdfreight.com/api/gateway/sandbox + private static final String API_URL = "https://oms.sit.sf-express.com:9010/api/gateway/service"; + + /** + * 查询顺心捷达轨迹 + * @param waybillId 运单号 + * @return 查询结果JSON + */ + public static String queryRoute(String waybillId) { + return queryRoute(waybillId, null, null); + } + + /** + * 查询顺心捷达轨迹(支持子单号查询) + * @param waybillId 运单号 + * @param queryType 查询方式 1=查询母单轨迹 2=按子单号查询子单轨迹 + * @param subWaybillId 子运单号 + * @return 查询结果JSON + */ + public static String queryRoute(String waybillId, Integer queryType, String subWaybillId) { + try { + // 1. 构造请求数据 + JSONObject data = new JSONObject(); + data.put("waybillId", waybillId); + if (queryType != null) { + data.put("queryType", queryType); + } + if (StringUtils.isNotBlank(subWaybillId)) { + data.put("subWaybillId", subWaybillId); + } + + String dataStr = data.toJSONString(); + String timestamp = String.valueOf(System.currentTimeMillis()); + String messageId = UUID.randomUUID().toString(); + + // 2. 生成签名 + String dataDigest = generateDataDigest(dataStr, timestamp); + + // 3. 构造表单参数 + StringBuilder formParams = new StringBuilder(); + formParams.append("apiType=SX_QUERY_TRACK"); + formParams.append("&appKey=").append(URLEncoder.encode(APP_KEY, "UTF-8")); + formParams.append("&sxCustomerCode=").append(URLEncoder.encode(SX_CUSTOMER_CODE, "UTF-8")); + formParams.append("×tamp=").append(URLEncoder.encode(timestamp, "UTF-8")); + formParams.append("&dataDigest=").append(URLEncoder.encode(dataDigest, "UTF-8")); + formParams.append("&messageId=").append(URLEncoder.encode(messageId, "UTF-8")); + formParams.append("&data=").append(URLEncoder.encode(dataStr, "UTF-8")); + + String formBody = formParams.toString(); + System.out.println("顺心捷达请求参数:" + formBody); + + // 4. 发送POST请求 + return doPost(API_URL, formBody); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * 解析顺心捷达返回数据,转为OaExpressVo + */ + public static OaExpressVo parseData(String result) { + if (result == null || result.trim().isEmpty()) { + return null; + } + try { + JSONObject json = JSON.parseObject(result); + + // 检查响应状态 + if (!json.getBooleanValue("success")) { + System.err.println("顺心捷达查询失败:" + json.getString("message")); + return null; + } + + JSONObject data = json.getJSONObject("data"); + if (data == null) return null; + + JSONArray trackInfoList = data.getJSONArray("trackInfoList"); + if (trackInfoList == null || trackInfoList.isEmpty()) return null; + + // 获取最新的轨迹信息(第一条是最新的) + JSONObject latestTrack = trackInfoList.getJSONObject(0); + + OaExpressVo vo = new OaExpressVo(); + vo.setExpressCode(latestTrack.getString("waybillId")); + vo.setLastUpdateTime(new Date(latestTrack.getLongValue("operationTime"))); + vo.setLastStatus(latestTrack.getString("step")); + vo.setRemark(latestTrack.getString("trackDesc")); + + return vo; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * 生成数据签名 + * 签名算法:MD5(data + timestamp + appSecret) 然后Base64编码 + */ + private static String generateDataDigest(String data, String timestamp) throws Exception { + String signStr = data + timestamp + APP_SECRET; + MessageDigest md = MessageDigest.getInstance("MD5"); + md.update(signStr.getBytes(StandardCharsets.UTF_8)); + byte[] digest = md.digest(); + + // 使用Base64编码,URL安全模式 + return new String(Base64.encodeBase64URLSafe(digest), StandardCharsets.UTF_8); + } + + /** + * 发送POST请求 + */ + private static String doPost(String urlStr, String formData) throws Exception { + URL url = new URL(urlStr); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("POST"); + connection.setDoOutput(true); + connection.setDoInput(true); + connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + connection.setRequestProperty("Accept", "application/json"); + connection.setConnectTimeout(10000); + connection.setReadTimeout(30000); + + // 发送请求数据 + try (OutputStream os = connection.getOutputStream()) { + byte[] input = formData.getBytes(StandardCharsets.UTF_8); + os.write(input, 0, input.length); + } + + // 读取响应 + StringBuilder response = new StringBuilder(); + try (BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) { + String line; + while ((line = br.readLine()) != null) { + response.append(line); + } + } + + connection.disconnect(); + return response.toString(); + } + + /** + * 判断是否为顺心捷达快递 + * 根据运单号规则判断:通常以S开头 + */ + public static boolean isSxjdExpress(String waybillId) { + if (StringUtils.isBlank(waybillId)) { + return false; + } + // 顺心捷达运单号通常以S开头,长度为12位 + return waybillId.startsWith("S") && waybillId.length() >= 10; + } + + /** + * MD5编码方法(用于测试) + */ + public static String md5Encode(String str) { + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + md.update(str.getBytes(StandardCharsets.UTF_8)); + byte[] digest = md.digest(); + String r = new String(Base64.encodeBase64URLSafe(digest), StandardCharsets.UTF_8); + return r; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * 测试方法 + */ + public static void main(String[] args) { + // 测试签名生成 + String data = "{ \"customerOrderNo\":\"QW2315464601\", \"orderChannelNo\":\"SE1231322\", \"orderType\":1,\"whetherEwb\":true,\"senderCompany\":\"测试公司890\", \"senderName\":\"测试收\", \"senderMobile\":\"12345667634\", \"senderTel\":\"0755-8658521\", \"senderProv\":\"广东省\", \"senderCity\":\"广州市\", \"senderArea\":\"越秀区\", \"senderAddress\":\"白云街道102号筒子巷\", \"receiverCompany\":\"绿色公司\", \"receiverName\":\"大师傅\", \"receiverTel\":\"021-85685452\", \"receiverMobile\":\"12313213213\", \"receiverProv\":\"广东省\", \"receiverCity\":\"广州市\", \"receiverArea\":\"海珠区\", \"receiverAddress\":\"华洲街道\", \"cargoName\":\"装修物品\", \"totalPackages\":3, \"totalWeight\":12, \"totalVolume\":15, \"pickupWay\":\"送货(不含上楼)\", \"backSignBill\":\"电子回单\", \"remark\":\"客户接入:sxCustomerCode必填\", \"insuranceValue\":800, \"codAmount\":1024, \"fcodAmount\":620, \"getGoodMode\":\"上门接货\", \"orderSource\":\"PDD\",\"productName\":\"顺心包裹\",\"payType\":\"现付\",\"subMailNos\":\"20220426013,20220426014,20220426015\"}"; + String timestamp = System.currentTimeMillis() + ""; + String app_secret = "773bebe1bd75680a9e03ee579874d5a2"; + String dataDigest = md5Encode(data + timestamp + app_secret); + System.out.println("测试签名生成:" + dataDigest); + + // 测试轨迹查询 + String waybillId = "S60201493742"; + String result = queryRoute(waybillId); + System.out.println("顺心捷达原始返回:" + result); + + OaExpressVo vo = parseData(result); + if (vo != null) { + System.out.println("解析后结果:"); + System.out.println("运单号:" + vo.getExpressCode()); + System.out.println("最新状态:" + vo.getLastStatus()); + System.out.println("更新时间:" + vo.getLastUpdateTime()); + System.out.println("描述:" + vo.getRemark()); + } else { + System.out.println("解析失败或数据为空"); + } + + // 测试运单号判断 + System.out.println("\n运单号判断测试:"); + System.out.println("S60201493742 是否为顺心捷达:" + isSxjdExpress("S60201493742")); + System.out.println("SF1234567890 是否为顺心捷达:" + isSxjdExpress("SF1234567890")); + System.out.println("1234567890 是否为顺心捷达:" + isSxjdExpress("1234567890")); + } +}