物流处理 完成了顺丰api对接

This commit is contained in:
2025-07-21 23:39:30 +08:00
parent ca0ec753c7
commit b1914b7edc
23 changed files with 1581 additions and 4 deletions

View File

@@ -0,0 +1,224 @@
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.OaExpress;
import com.ruoyi.oa.domain.vo.OaExpressVo;
import sun.misc.BASE64Encoder;
import com.ruoyi.common.utils.DateUtils;
import org.apache.commons.lang3.StringUtils;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Base64;
import java.net.URLEncoder;
import java.util.UUID;
import java.util.List;
import java.util.Arrays;
import java.util.Date;
/**
* 顺丰路由地址查询工具
*/
public class SfRouteQueryUtil {
// 顺丰开放平台 partnerID
private static final String PARTNER_ID = "YIX65G10";
// 顺丰开放平台接口地址
private static final String API_URL = "https://bspgw.sf-express.com/std/service";
// 顺丰开放平台 checkWord
private static final String CHECK_WORD = "PkJL4cpEQIUuV1goWvhIznqthletmddX";
// 顺丰OAuth认证
private static final String OAUTH_URL = "https://sfapi.sf-express.com/oauth2/accessToken";
private static final String GRANT_TYPE = "password";
/**
* 查询顺丰路由
* @param mailNo 顺丰运单号
* @return 查询结果JSON
*/
public static String queryRoute(String mailNo,String phoneNumber) {
List<String> mailNos = Arrays.asList(mailNo);
try {
// 1. 构造业务数据msgData
JSONObject msgData = new JSONObject();
msgData.put("language", "zh-CN");
msgData.put("trackingType", "1"); // 1:运单号 2:订单号
msgData.put("methodType", "1"); // 1:标准路由
msgData.put("trackingNumber", mailNos);
msgData.put("checkPhoneNo", StringUtils.right(phoneNumber, 4));
String msgDataStr = msgData.toJSONString();
System.out.println(msgDataStr);
// 2. 公共参数
String requestID = UUID.randomUUID().toString().replaceAll("-", "");
String serviceCode = "EXP_RECE_SEARCH_ROUTES";
String timestamp = String.valueOf(System.currentTimeMillis());
// String msgDigest = genSign(msgDataStr, timestamp, CHECK_WORD);
// System.out.println(msgDigest);
String accessToken = oAuth();
System.out.println(accessToken);
// 3. 拼接表单参数
StringBuilder formParams = new StringBuilder();
formParams.append("partnerID=").append(URLEncoder.encode(PARTNER_ID, "UTF-8"));
formParams.append("&requestID=").append(URLEncoder.encode(requestID, "UTF-8"));
formParams.append("&serviceCode=").append(URLEncoder.encode(serviceCode, "UTF-8"));
formParams.append("&timestamp=").append(URLEncoder.encode(timestamp, "UTF-8"));
formParams.append("&accessToken=").append(URLEncoder.encode(accessToken, "UTF-8"));
formParams.append("&msgData=").append(URLEncoder.encode(msgDataStr, "UTF-8"));
String formBody = formParams.toString();
System.out.println(formBody);
// 4. 发送POST请求
return doPost(API_URL, formBody);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 顺丰msgDigest生成方式Base64(MD5(URLEncode(msgData+timestamp+partnerId+checkWord)))
*/
private static String genSign(String msgData, String timestamp, String checkWord) throws Exception {
String toVerifyText = msgData + timestamp + checkWord;
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(toVerifyText.getBytes("UTF-8"));
byte[] digest = md5.digest();
return Base64.getEncoder().encodeToString(digest);
}
/**
* 顺丰OAUTH2
*/
private static String oAuth() throws Exception {
StringBuilder formParams = new StringBuilder();
formParams.append("partnerID=").append(URLEncoder.encode(PARTNER_ID, "UTF-8"));
formParams.append("&secret=").append(URLEncoder.encode(CHECK_WORD, "UTF-8"));
formParams.append("&grantType=").append(URLEncoder.encode(GRANT_TYPE, "UTF-8"));
String oauthResponse = doPost(OAUTH_URL, formParams.toString());
JSONObject jsonObject = JSON.parseObject(oauthResponse);
return jsonObject.getString("accessToken");
}
/**
* 发送POST请求表单格式
*/
private static String doPost(String urlStr, String formBody) throws Exception {
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
conn.setDoOutput(true);
try (OutputStream os = conn.getOutputStream()) {
os.write(formBody.getBytes(StandardCharsets.UTF_8));
}
int code = conn.getResponseCode();
if (code == 200) {
try (BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
return sb.toString();
}
} else {
throw new RuntimeException("HTTP请求失败状态码" + code);
}
}
public static OaExpressVo parseData(String result) {
if (StringUtils.isBlank(result)) {
return null;
}
try {
// 1. 解析最外层的JSON
JSONObject outerJson = JSON.parseObject(result);
if (outerJson == null) {
return null;
}
// 2. 获取apiResultData字符串并再次解析
String apiResultDataStr = outerJson.getString("apiResultData");
if (StringUtils.isBlank(apiResultDataStr)) {
return null;
}
JSONObject innerJson = JSON.parseObject(apiResultDataStr);
if (innerJson == null) {
return null;
}
// 3. 提取所需数据
JSONObject msgData = innerJson.getJSONObject("msgData");
if (msgData == null) {
return null;
}
JSONArray routeResps = msgData.getJSONArray("routeResps");
if (routeResps == null || routeResps.isEmpty()) {
return null;
}
JSONObject firstRouteResp = routeResps.getJSONObject(0);
if (firstRouteResp == null) {
return null;
}
JSONArray routes = firstRouteResp.getJSONArray("routes");
if (routes == null || routes.isEmpty()) {
return null;
}
JSONObject lastRoute = routes.getJSONObject(routes.size() - 1);
if (lastRoute == null) {
return null;
}
String acceptTime = lastRoute.getString("acceptTime");
String firstStatusName = lastRoute.getString("firstStatusName");
OaExpressVo oaExpressVo = new OaExpressVo();
// 转换日期并设置如果日期格式不正确则设置为null
if (StringUtils.isNotBlank(acceptTime)) {
try {
Date date = DateUtils.parseDate(acceptTime);
oaExpressVo.setAcceptTime(date);
} catch (Exception e) {
oaExpressVo.setAcceptTime(null);
}
}
oaExpressVo.setFirstStatusName(firstStatusName);
System.out.println(acceptTime);
System.out.println(firstStatusName);
return oaExpressVo;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* main方法测试
*/
public static void main(String[] args) {
String mailNo = "SF0282456509537";
String result = queryRoute(mailNo,"18012017423");
System.out.println(result);
OaExpressVo oaExpress = parseData(result);
}
}