韵达快递、安能快递、百世快递、中国邮政快递、EMS、德邦快递、极兔快递、顺丰快递、申通快递、众邮快递、圆通快递、中通快递
Express接口类
public interface Express {
/**
* 快递编码
*
* @return String
*/
String expressCode();
/**
* 根据快递编码相关信息查询快递信息
*
* @param request 请求参数
* @return ExpressSearchResponse
* @throws NoSuchAlgorithmException
*/
ExpressSearchResponse logisticsSearch(ExpressSearchRequest request) throws NoSuchAlgorithmException;
}
SelectExpress类
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
@Service
public class SelectExpress implements CommandLineRunner {
@Resource
private ApplicationContext applicationContext;
private Map<String, Express> expressMap = new HashMap<>();
/**
* 根据名字返回相应的实现类
*
* @param code 快递公司编码
* @return 实现类
*/
public Express get(String code) {
return expressMap.get(code);
}
@Override
public void run(String... args) throws Exception {
applicationContext.getBeansOfType(Express.class).values()
.forEach(express -> expressMap.put(express.expressCode(), express));
}
}
ExpressSearchRequest请求类
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
@Data
public class ExpressSearchRequest implements Serializable {
private static final long serialVersionUID = -880253965590928905L;
@ApiModelProperty(value = "真实物流单号")
private String logisticsNo;
@ApiModelProperty(value = "物流公司名称", hidden = true)
private String expressName;
@ApiModelProperty(value = "物流公司编码", hidden = true)
private String expressCode;
@ApiModelProperty(value = "订单编码", hidden = true)
private String orderNo;
@ApiModelProperty(value = "收件人姓名", hidden = true)
private String receiverName;
@ApiModelProperty(value = "收件人手机号", hidden = true)
private String receiverMobile;
@ApiModelProperty(value = "收人地址:省份名称", hidden = true)
private String provinceName;
@ApiModelProperty(value = "收人地址:地市名称", hidden = true)
private String cityName;
@ApiModelProperty(value = "收人地址:区县名称", hidden = true)
private String districtName;
@ApiModelProperty(value = "收件人详细地址", hidden = true)
private String detailAddress;
}
ExpressSearchResponse返回类
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
@Data
public class ExpressSearchResponse implements Serializable {
private static final long serialVersionUID = 8570085965157271803L;
@ApiModelProperty("快递公司名称")
private String logisticsName = "";
@ApiModelProperty("快递单号")
private String logisticsNo = "";
@ApiModelProperty("描述")
List<ExpressDescDTO> descList = new ArrayList<>();
}
ExpressDescDTO返回类子类
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
@Data
public class ExpressDescDTO implements Serializable {
private static final long serialVersionUID = 2774275564551643616L;
@ApiModelProperty("轨迹描述")
private String desc = "";
@ApiModelProperty("日期")
private String date = "";
}
ResponseController返回结果封装类
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jumi.microservice.warehouse.entity.dto.ExpressDescDTO;
import com.jumi.microservice.warehouse.entity.dto.ExpressSearchRequest;
import com.jumi.microservice.warehouse.entity.dto.ExpressSearchResponse;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
public class ResponseController {
/**
* 校验返回结果
*
* @param jsonArray json数组
* @param request 请求参数
* @return ExpressSearchResponse
*/
public ExpressSearchResponse checkResult(JSONArray jsonArray, ExpressSearchRequest request) {
ExpressSearchResponse expressSearchResponse = new ExpressSearchResponse();
expressSearchResponse.setLogisticsName(request.getExpressName());
expressSearchResponse.setLogisticsNo(request.getLogisticsNo());
if (jsonArray == null || jsonArray.isEmpty()) {
expressSearchResponse.setDescList(new ArrayList<>());
}
return expressSearchResponse;
}
/**
* 组装返回实体类
*
* @param expressSearchResponse 返回信息
* @param jsonArr json数组
* @param descKey 描述
* @param dateKey 时间
* @return 组装返回实体类
*/
public ExpressSearchResponse controller(ExpressSearchResponse expressSearchResponse, JSONArray jsonArr,
String descKey, String dateKey) {
if (jsonArr == null || jsonArr.isEmpty()) {
return expressSearchResponse;
}
List<ExpressDescDTO> list = new ArrayList<>();
for (Object j : jsonArr) {
JSONObject json = JSONObject.parseObject(j.toString());
ExpressDescDTO expressDescDTO = new ExpressDescDTO();
if (json.getString(descKey) == null || json.getString(dateKey) == null) {
return expressSearchResponse;
}
expressDescDTO.setDesc(json.getString(descKey));
expressDescDTO.setDate(json.getString(dateKey));
list.add(expressDescDTO);
}
list = list.stream().sorted(Comparator.comparing(ExpressDescDTO::getDate).reversed()).collect(Collectors.toList());
expressSearchResponse.setDescList(list);
return expressSearchResponse;
}
/**
* 组装返回实体类
*
* @param expressSearchResponse 返回信息
* @param jsonArr json数组
* @param descKey 描述
* @param dateKey 时间
* @return 组装返回实体类
*/
public ExpressSearchResponse controllerZto(ExpressSearchResponse expressSearchResponse, JSONArray jsonArr,
String descKey, String dateKey) {
if (jsonArr == null || jsonArr.isEmpty()) {
return expressSearchResponse;
}
List<ExpressDescDTO> list = new ArrayList<>();
for (Object j : jsonArr) {
JSONObject json = JSONObject.parseObject(j.toString());
ExpressDescDTO expressDescDTO = new ExpressDescDTO();
if (json.getString(descKey) == null || json.getString(dateKey) == null) {
return expressSearchResponse;
}
expressDescDTO.setDesc(json.getString(descKey));
expressDescDTO.setDate(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(Long.parseLong(json.getString(dateKey)))));
list.add(expressDescDTO);
}
list = list.stream().sorted(Comparator.comparing(ExpressDescDTO::getDate).reversed()).collect(Collectors.toList());
expressSearchResponse.setDescList(list);
return expressSearchResponse;
}
}
通用查询快递方法
/**
* 查询快递
*
* @param sn 快递单号
* @param name 快递公司名称
* @param code 快递公司编码
* @return 结果
*/
public ExpressSearchResponse queryExpress(String sn, String name, String code) {
ExpressSearchResponse response;
if (StringUtils.isBlank(sn)) {
return new ExpressSearchResponse();
}
Express express = selectExpress.get(code);
ExpressSearchRequest request = new ExpressSearchRequest();
request.setExpressName(name);
request.setLogisticsNo(sn);
request.setExpressCode(code);
return express.logisticsSearch(request);
}
HttpClientUtils工具类
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
@Component
public class HttpClientUtils {
/**
* http get
*
* @param url 可带参数的 url 链接
* @param heads http 头信息
*/
public String get(String url, Map<String, String> heads) {
org.apache.http.client.HttpClient httpClient = HttpClients.createDefault();
HttpResponse httpResponse = null;
String result = "";
HttpGet httpGet = new HttpGet(url);
if (heads != null) {
Set<String> keySet = heads.keySet();
for (String s : keySet) {
httpGet.addHeader(s, heads.get(s));
}
}
try {
httpResponse = httpClient.execute(httpGet);
HttpEntity httpEntity = httpResponse.getEntity();
if (httpEntity != null) {
result = EntityUtils.toString(httpEntity, "utf-8");
}
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
/**
* http post
*/
public String post(String url, String data, Map<String, String> heads) {
org.apache.http.client.HttpClient httpClient = HttpClients.createDefault();
HttpResponse httpResponse = null;
String result = "";
HttpPost httpPost = new HttpPost(url);
if (heads != null) {
Set<String> keySet = heads.keySet();
for (String s : keySet) {
httpPost.addHeader(s, heads.get(s));
}
}
try {
StringEntity s = new StringEntity(data, "utf-8");
httpPost.setEntity(s);
httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
if (httpEntity != null) {
result = EntityUtils.toString(httpEntity, "utf-8");
}
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
}
MD5工具类
import com.google.common.collect.Maps;
import org.springframework.stereotype.Component;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
@Component
public class MD5 {
private static int DIGITS_SIZE = 16;
private static char[] digits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
private static Map<Character, Integer> rDigits = Maps.newHashMapWithExpectedSize(16);
static {
for (int i = 0; i < digits.length; ++i) {
rDigits.put(digits[i], i);
}
}
private static MD5 me = new MD5();
private MessageDigest mHasher;
private ReentrantLock opLock = new ReentrantLock();
private MD5() {
try {
mHasher = MessageDigest.getInstance("md5");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static MD5 getInstance() {
return me;
}
public String getMD5String(String content) {
return bytes2string(hash(content));
}
public String getMD5String(byte[] content) {
return bytes2string(hash(content));
}
public byte[] getMD5Bytes(byte[] content) {
return hash(content);
}
/**
* 对字符串进行md5
*
* @param str
* @return md5 byte[16]
*/
public byte[] hash(String str) {
opLock.lock();
try {
byte[] bt = mHasher.digest(str.getBytes(StandardCharsets.UTF_8));
if (null == bt || bt.length != DIGITS_SIZE) {
throw new IllegalArgumentException("md5 need");
}
return bt;
} finally {
opLock.unlock();
}
}
/**
* 对二进制数据进行md5
*
* @param data
* @return md5 byte[16]
*/
public byte[] hash(byte[] data) {
opLock.lock();
try {
byte[] bt = mHasher.digest(data);
if (null == bt || bt.length != DIGITS_SIZE) {
throw new IllegalArgumentException("md5 need");
}
return bt;
} finally {
opLock.unlock();
}
}
/**
* 将一个字节数组转化为可见的字符串
*
* @param bt
* @return
*/
public String bytes2string(byte[] bt) {
int l = bt.length;
char[] out = new char[l << 1];
for (int i = 0, j = 0; i < l; i++) {
out[j++] = digits[(0xF0 & bt[i]) >>> 4];
out[j++] = digits[0x0F & bt[i]];
}
return new String(out);
}
}
MD5加密工具类
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.security.MessageDigest;
@Component
public class Md5Utils {
private static final Logger log = LoggerFactory.getLogger(Md5Utils.class);
private static byte[] md5(String s) {
MessageDigest algorithm;
try {
algorithm = MessageDigest.getInstance("MD5");
algorithm.reset();
algorithm.update(s.getBytes("UTF-8"));
byte[] messageDigest = algorithm.digest();
return messageDigest;
} catch (Exception e) {
log.error("MD5 Error...", e);
}
return null;
}
private static final String toHex(byte hash[]) {
if (hash == null) {
return null;
}
StringBuffer buf = new StringBuffer(hash.length * 2);
int i;
for (i = 0; i < hash.length; i++) {
if ((hash[i] & 0xff) < 0x10) {
buf.append("0");
}
buf.append(Long.toString(hash[i] & 0xff, 16));
}
return buf.toString();
}
public static String hash(String s) {
try {
return new String(toHex(md5(s)).getBytes("UTF-8"), "UTF-8");
} catch (Exception e) {
log.error("not supported charset...{}", e);
return s;
}
}
}
pom.xml——>引入顺丰、申通、众邮快递SDK。引入谷歌工具包:调用com.google.common.collect.Maps。
<dependency>
<groupId>com.express</groupId>
<artifactId>lop-zhongyou-api-sdk</artifactId>
<version>2.0.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.express</groupId>
<artifactId>sf-csim-express-sdk</artifactId>
<version>2.0.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.express</groupId>
<artifactId>sto-link-sdk</artifactId>
<version>2.0.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>22.0</version>
</dependency>
韵达快递——>接收OrderInfo类
import lombok.Data;
@Data
public class OrderInfo {
private String orderid;
private String mailno;
private UserInfo sender;
private UserInfo receiver;
}
韵达快递——>接收子类UserInfo类
import lombok.Data;
@Data
public class UserInfo {
private String name;
private String province;
private String city;
private String county;
private String address;
private String phone;
private String mobile;
}
例1:YdExpress——>韵达快递
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import OrderInfo;
import UserInfo;
import ExpressSearchRequest;
import ExpressSearchResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* 韵达
*/
@Service
public class YdExpress extends ResponseController implements Express {
private static final Logger log = LoggerFactory.getLogger(YdExpress.class);
private static final String TRACK_SERVER_URL = "https://openapi.yundaex.com/openapi/outer/logictis/subscribe";
private static final String SERVER_URL = "https://openapi.yundaex.com/openapi/outer/logictis/query";
private static final String APP_KEY = "123456";
private static final String APP_SECRET = "e10adc3949ba59abbe56e057f20f883e";
@Resource
private RedisTemplate redisTemplate;
private static final String LOGISTICS_TRACK = "logistics::track:{}";
@Override
public String expressCode() {
return "YD";
}
@Override
public ExpressSearchResponse logisticsSearch(ExpressSearchRequest request) {
log.info("韵达快递查询参数[{}]", JSON.toJSONString(request));
JSONArray jsonArray = new JSONArray();
String logisticsTrack = StrUtil.format(LOGISTICS_TRACK, request.getLogisticsNo());
boolean isTrack = false;
try {
if (!redisTemplate.hasKey(logisticsTrack)) {
//物流轨迹订阅
String orderid = request.getOrderNo();
String mailno = request.getLogisticsNo();
String senderName = request.getReceiverName();
String senderProvince = request.getProvinceName();
String senderCity = request.getCityName();
String senderCounty = request.getDistrictName();
String senderAddress = request.getDetailAddress();
String senderPhone = request.getReceiverMobile();
String senderMobile = request.getReceiverMobile();
String receiverName = request.getReceiverName();
String receiverProvince = request.getProvinceName();
String receiverCity = request.getCityName();
String receiverCounty = request.getDistrictName();
String receiverAddress = request.getDetailAddress();
String receiverPhone = request.getReceiverMobile();
String receiverMobile = request.getReceiverMobile();
List<OrderInfo> orderInfoList = new ArrayList<>();
OrderInfo orderInfo = new OrderInfo();
orderInfo.setOrderid(orderid);
orderInfo.setMailno(mailno);
//发货人信息
UserInfo userInfoSender = new UserInfo();
userInfoSender.setName(senderName);
userInfoSender.setProvince(senderProvince);
userInfoSender.setCity(senderCity);
userInfoSender.setCounty(senderCounty);
userInfoSender.setAddress(senderAddress);
userInfoSender.setPhone(senderPhone);
userInfoSender.setMobile(senderMobile);
orderInfo.setSender(userInfoSender);
//接收人信息
UserInfo userInfoReceiver = new UserInfo();
userInfoReceiver.setName(receiverName);
userInfoReceiver.setProvince(receiverProvince);
userInfoReceiver.setCity(receiverCity);
userInfoReceiver.setCounty(receiverCounty);
userInfoReceiver.setAddress(receiverAddress);
userInfoReceiver.setPhone(receiverPhone);
userInfoReceiver.setMobile(receiverMobile);
orderInfo.setReceiver(userInfoReceiver);
orderInfoList.add(orderInfo);
String orders = "{\"orders\":" + JSONObject.toJSONString(orderInfoList) + "}";
String resTrack = doPostJson(TRACK_SERVER_URL, orders);
JSONObject jsonObjTrack = JSON.parseObject(resTrack);
if (jsonObjTrack.getBoolean("result")) {
redisTemplate.expire(logisticsTrack, 60, TimeUnit.DAYS);
isTrack = true;
}
}
if (isTrack) {
String sourceContent = "{\"mailno\":\"" + request.getLogisticsNo() + "\"}";
String res = doPostJson(SERVER_URL, sourceContent);
log.info("请求返回结果[{}]", res);
JSONObject jsonObj = JSON.parseObject(res);
if (jsonObj.containsKey("data")) {
JSONObject json = jsonObj.getJSONObject("data");
if (json.containsKey("steps")) {
jsonArray = json.getJSONArray("steps");
}
}
}
} catch (Exception e) {
log.error("韵达快递查询出错[{}]", e.getMessage());
}
ExpressSearchResponse expressSearchResponse = checkResult(jsonArray, request);
log.info("请求返回[{}]", JSON.toJSONString(controller(expressSearchResponse, jsonArray, "description", "time")));
return controller(expressSearchResponse, jsonArray, "description", "time");
}
/**
* 发送HTTP请求
*
* @param apiUrl 请求URL
* @param jsonParams 请求参数
* @return String
*/
private static String doPostJson(String apiUrl, String jsonParams) {
StringBuffer sbResult = new StringBuffer();
try {
URL url = new URL(apiUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Charset", "UTF-8");
byte[] data = jsonParams.getBytes(StandardCharsets.UTF_8);
conn.setRequestProperty("Content-Length", String.valueOf(data.length));
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("app-key", YdExpress.APP_KEY);
conn.setRequestProperty("req-time", String.valueOf(System.currentTimeMillis()));
conn.setRequestProperty("sign", MD5(jsonParams + "_" + YdExpress.APP_SECRET));
conn.connect();
OutputStream out = new DataOutputStream(conn.getOutputStream());
out.write(data);
out.flush();
out.close();
if (200 == conn.getResponseCode()) {
InputStream inputStream = conn.getInputStream();
try {
String readLine = null;
BufferedReader responseReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
while ((readLine = responseReader.readLine()) != null) {
sbResult.append(readLine).append("\n");
}
responseReader.close();
} catch (Exception var12) {
var12.printStackTrace();
}
}
} catch (Exception var13) {
var13.printStackTrace();
}
return sbResult.toString();
}
/**
* Md5加密算法
*
* @param str
* @return
* @throws Exception
*/
private static String MD5(String str) throws Exception {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(str.getBytes(StandardCharsets.UTF_8));
byte[] result = md.digest();
StringBuffer sb = new StringBuffer(32);
for (int i = 0; i < result.length; ++i) {
int val = result[i] & 255;
if (val <= 15) {
sb.append("0");
}
sb.append(Integer.toHexString(val));
}
return sb.toString().toLowerCase();
}
}
例2:AneExpress——>安能快递
import cn.hutool.core.codec.Base64;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import ExpressSearchRequest;
import ExpressSearchResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.security.NoSuchAlgorithmException;
/**
* 安能
**/
@Service
public class AneExpress extends ResponseController implements Express {
private static final Logger log = LoggerFactory.getLogger(AneExpress.class);
private static String URL = "http://opc.ane56.com/aneop/services/logisticsQuery/new/query";
private static String APPKEY = "e10adc3949ba59abbe56e057f20f883e";
private static String CODE = "ANENG";
@Override
public String expressCode() {
return "ANE";
}
@Override
public ExpressSearchResponse logisticsSearch(ExpressSearchRequest request) throws NoSuchAlgorithmException {
log.info("安能快递查询参数[{}]", JSON.toJSONString(request));
JSONArray jsonArray = new JSONArray();
try {
JSONObject jsonObject = new JSONObject();
JSONObject params = new JSONObject();
params.put("ewbNo", request.getLogisticsNo());
jsonObject.put("params", params.toJSONString());
String digest = Base64.encode(SecureUtil.md5("{\"ewbNo\":\"" + request.getLogisticsNo() + "\"}" + CODE + APPKEY));
jsonObject.put("digest", digest);
jsonObject.put("code", CODE);
String timestamp = Long.toString(System.currentTimeMillis());
jsonObject.put("timestamp", timestamp);
String res = HttpRequest.post(URL).header("Content-type", "application/json").body(jsonObject.toJSONString()).execute().body();
log.info("请求返回结果[{}]", res);
JSONObject resObject = JSONObject.parseObject(res);
jsonArray = resObject.getJSONObject("resultInfo").getJSONArray("traces");
} catch (Exception e) {
log.error("安能快递查询出错[{}]", e.getMessage());
}
ExpressSearchResponse expressSearchResponse = checkResult(jsonArray, request);
log.info("请求返回[{}]", JSON.toJSONString(controller(expressSearchResponse, jsonArray, "desc", "operateTime")));
return controller(expressSearchResponse, jsonArray, "desc", "operateTime");
}
}
例3:BestExpress——>百世快递
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import ExpressSearchRequest;
import ExpressSearchResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
/**
* 百世
*/
@Service
public class BestExpress extends ResponseController implements Express {
private static final Logger log = LoggerFactory.getLogger(BestExpress.class);
private static String url = "http://edi-q9.ns.800best.com/kd/api/process";
private static String partnerKey = "49ba59abbe56";
private static String partnerID = "12345";
private static String serviceType = "KD_TRACE_QUERY";
@Resource
HttpClientUtils httpClientUtils;
@Override
public String expressCode() {
return "HTKY";
}
@Override
public ExpressSearchResponse logisticsSearch(ExpressSearchRequest request) {
log.info("百世快递查询参数[{}]", JSON.toJSONString(request));
JSONArray jsonArr = null;
ExpressSearchResponse expressSearchResponse = null;
try {
//拼接请求头
Map<String, String> headers = new HashMap<>(4);
headers.put("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
headers.put("connection", "keep-alive");
headers.put("user-agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0");
headers.put("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
//组建数据格式
String bizData = "{\"mailNos\": {\"mailNo\": [\"" + request.getLogisticsNo() + "\"]}}";
String sign = Md5Utils.hash(bizData + partnerKey);
String requestData = "partnerID=" + partnerID + "&serviceType=" + serviceType + "&bizData=" + bizData + "&sign=" + sign;
//发送请求并接受返回
String res = httpClientUtils.post(url, requestData, headers);
log.info("请求返回结果[{}]", res);
JSONObject json = JSONObject.parseObject(res);
jsonArr = json.getJSONArray("traceLogs");
//处理返回结果
jsonArr = jsonArr.getJSONObject(0).getJSONObject("traces").getJSONArray("trace");
} catch (Exception e) {
log.error("百世快递查询出错[{}]", e.getMessage());
}
expressSearchResponse = checkResult(jsonArr, request);
log.info("请求返回[{}]", JSON.toJSONString(controller(expressSearchResponse, jsonArray, "remark", "acceptTime")));
return controller(expressSearchResponse, jsonArr, "remark", "acceptTime");
}
}
例4:中国邮政快递——>ChinaPostExpress【线下联系邮政快递人员开通账号信息】
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import ExpressSearchRequest;
import ExpressSearchResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
/**
* 中国邮政
*/
@Service
public class ChinaPostExpress extends ResponseController implements Express {
private static final Logger log = LoggerFactory.getLogger(ChinaPostExpress.class);
@Resource
HttpClientUtils httpClientUtils;
@Override
public String expressCode() {
return "YZPY";
}
@Override
public ExpressSearchResponse logisticsSearch(ExpressSearchRequest request) {
log.info("邮政快递包裹查询参数[{}]", JSON.toJSONString(request));
JSONArray jsonArray = null;
try {
String url = "http://211.156.193.140:8000/cotrackapi/api/track/mail/";
//拼接请求头
Map<String, String> headers = new HashMap<>(2);
headers.put("Version", "ems_track_cn_1.0");
headers.put("authenticate", "E10ADC3949BA59ABBE56E057F20F883E");
//组建数据格式
url = url + request.getLogisticsNo();
//发送请求并接受返回
String res = httpClientUtils.get(url, headers);
//处理返回结果
log.info("请求返回结果[{}]", res);
JSONObject json = JSONObject.parseObject(res);
jsonArray = json.getJSONArray("traces");
} catch (Exception e) {
log.error("邮政快递包裹查询出错[{}]", e.getMessage());
}
ExpressSearchResponse expressSearchResponse = checkResult(jsonArray, request);
log.info("请求返回[{}]", JSON.toJSONString(controller(expressSearchResponse, jsonArray, "remark", "acceptTime")));
return controller(expressSearchResponse, jsonArray, "remark", "acceptTime");
}
}
例5:EMS——>EmsExpress【线下联系邮政快递人员开通账号信息】
import ExpressSearchRequest;
import ExpressSearchResponse;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* EMS
*/
@Service
public class EmsExpress extends ResponseController implements Express {
@Resource
ChinaPostExpress chinaPostExpress;
@Override
public String expressCode() {
return "EMS";
}
@Override
public ExpressSearchResponse logisticsSearch(ExpressSearchRequest request) {
return chinaPostExpress.logisticsSearch(request);
}
}
例6:德邦快递——>DepponExpress
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import ExpressSearchRequest;
import ExpressSearchResponse;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
/**
* 德邦
*/
@Service
public class DepponExpress extends ResponseController implements Express {
private static final Logger log = LoggerFactory.getLogger(DepponExpress.class);
private static String url = "http://dpapi.deppon.com/dop-interface-sync/standard-query/newTraceQuery.action";
private static String companyCode = "ABCDEFGHIJKLM";
private static String appKey = "e10adc3949ba59abbe56e057f20f883e";
@Resource
HttpClientUtils httpClientUtils;
@Override
public String expressCode() {
return "DBL";
}
@Override
public ExpressSearchResponse logisticsSearch(ExpressSearchRequest request) {
JSONArray jsonArray = null;
log.info("德邦快递查询参数[{}]", JSON.toJSONString(request));
try {
//拼接请求头
Map<String, String> headers = new HashMap<>(1);
headers.put("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
//组建数据格式
String timestamp = String.valueOf(System.currentTimeMillis());
String params = "{\"mailNo\":\"" + request.getLogisticsNo() + "\"}";
String digest = Base64.encodeBase64String(DigestUtils.md5Hex(params + appKey + timestamp).getBytes());
String requestData = "params=" + params + "&digest=" + digest + "×tamp=" + timestamp + "&companyCode=" + companyCode;
//发送请求并接受返回
String res = httpClientUtils.post(url, requestData, headers);
//处理返回结果
log.info("请求返回结果[{}]", res);
JSONObject json = JSONObject.parseObject(res);
jsonArray = json.getJSONObject("responseParam").getJSONArray("trace_list");
} catch (Exception e) {
log.error("德邦快递查询出错[{}]", e.getMessage());
}
ExpressSearchResponse expressSearchResponse = checkResult(jsonArray, request);
log.info("请求返回[{}]", JSON.toJSONString(controller(expressSearchResponse, jsonArray, "description", "time")));
return controller(expressSearchResponse, jsonArray, "description", "time");
}
}
例7:极兔快递——>JtExpress
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import ExpressSearchRequest;
import ExpressSearchResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
/**
* 极兔
*/
@Service
public class JtExpress extends ResponseController implements Express {
private static final Logger log = LoggerFactory.getLogger(JtExpress.class);
private static final String API_ACCOUNT = "178337126125932605";
private static final String PRIVATE_KEY = "0258d71b55fc45e3ad7a7f38bf4b201a";
private static final String SERVICE_URL = "https://openapi.jtexpress.com.cn/webopenplatformapi/api/logistics/trace";
@Resource
HttpClientUtils httpClientUtils;
@Override
public String expressCode() {
return "JTSD";
}
@Override
public ExpressSearchResponse logisticsSearch(ExpressSearchRequest request) {
log.info("极兔查询参数[{}]", JSON.toJSONString(request));
JSONArray jsonArray = new JSONArray();
try {
//查询参数
String bizContent = "{\"billCodes\":\"" + request.getLogisticsNo() + "\"}";
//拼接请求头
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
headers.put("apiAccount", API_ACCOUNT);
headers.put("digest", digestForHead(bizContent));
headers.put("timestamp", String.valueOf(System.currentTimeMillis()));
String requestData = "bizContent=" + bizContent;
Map<String, String> jsonMap = new HashMap<>();
jsonMap.put("header", JSON.toJSONString(headers));
jsonMap.put("body", requestData);
log.info("请求参数digest[{}]", digestForHead(bizContent));
log.info("请求参数headers[{}]", JSON.toJSONString(headers));
log.info("请求参数body[{}]", requestData);
log.info("请求jsonMap[{}]", JSON.toJSONString(jsonMap));
//发送请求并接受返回
String res = httpClientUtils.post(SERVICE_URL, requestData, headers);
//处理返回结果
log.info("请求返回结果[{}]", res);
JSONObject json = JSONObject.parseObject(res);
jsonArray = json.getJSONArray("data").getJSONObject(0).getJSONArray("details");
} catch (Exception e) {
log.error("极兔快递查询出错[{}]", e.getMessage());
}
ExpressSearchResponse expressSearchResponse = checkResult(jsonArray, request);
log.info("请求返回[{}]", JSON.toJSONString(controller(expressSearchResponse, jsonArray, "desc", "scanTime")));
return controller(expressSearchResponse, jsonArray, "desc", "scanTime");
}
private static String digestForHead(String json) {
String signStr = json + JtExpress.PRIVATE_KEY;
byte[] encode = (new Base64()).encode(DigestUtils.md5(signStr));
return new String(encode);
}
}
例8:顺丰快递——>SfExpress 【引用顺丰SDK】
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import ExpressSearchRequest;
import ExpressSearchResponse;
import com.sf.csim.express.service.CallExpressServiceTools;
import com.sf.csim.express.service.HttpClientUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* 顺丰
*/
@Service
public class SfExpress extends ResponseController implements Express {
private static final Logger log = LoggerFactory.getLogger(SfExpress.class);
/**
* 顾客编码
*/
private static final String CLIENT_CODE = "ABCDEFGHIJKL";
/**
* 丰桥平台生产校验码
*/
private static final String CHECK_WORD = "E10ADC3949BA59ABBE56E057F20F883E";
/**
* 接口服务代码
*/
private static final String SERVICE_CODE = "EXP_RECE_SEARCH_ROUTES";
/**
* 生产环境的地址
*/
private static final String CALL_URL_PROD = "https://sfapi.sf-express.com/std/service";
@Override
public String expressCode() {
return "SF";
}
@Override
public ExpressSearchResponse logisticsSearch(ExpressSearchRequest request) {
log.info("顺丰查询参数[{}]", JSON.toJSONString(request));
JSONArray jsonArray = new JSONArray();
try {
Map<String, String> params = new HashMap<>();
String msgData = "{" +
" \"language\": 0," +
" \"trackingType\": 1," +
" \"trackingNumber\": [\"" + request.getLogisticsNo() + "\"]," +
" \"methodType\": 1," +
" \"checkPhoneNo\": \"" + request.getReceiverMobile().substring(7) + "\"" +
"}";
String timeStamp = String.valueOf(System.currentTimeMillis());
params.put("partnerID", CLIENT_CODE);
params.put("requestID", UUID.randomUUID().toString().replace("-", ""));
params.put("serviceCode", SERVICE_CODE);
params.put("timestamp", timeStamp);
params.put("msgData", msgData);
params.put("msgDigest", CallExpressServiceTools.getMsgDigest(msgData, timeStamp, CHECK_WORD));
System.out.println(params);
String res = HttpClientUtil.post(CALL_URL_PROD, params);
log.info("请求返回结果[{}]", res);
JSONObject jsonObj = JSON.parseObject(res);
if (jsonObj.containsKey("apiResultData")) {
JSONObject json = jsonObj.getJSONObject("apiResultData");
if (json.containsKey("msgData")) {
json = json.getJSONObject("msgData").getJSONArray("routeResps").getJSONObject(0);
if (json.containsKey("routes")) {
jsonArray = json.getJSONArray("routes");
}
}
}
} catch (Exception e) {
log.error("顺丰查询出错[{}]", e.getMessage());
}
ExpressSearchResponse expressSearchResponse = checkResult(jsonArray, request);
log.info("请求返回[{}]", JSON.toJSONString(controller(expressSearchResponse, jsonArray, "remark", "acceptTime")));
return controller(expressSearchResponse, jsonArray, "remark", "acceptTime");
}
}
例9:申通快递——>StoExpress 【引用申通SDK】
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import ExpressSearchRequest;
import ExpressSearchResponse;
import com.sto.link.request.LinkRequest;
import com.sto.link.util.LinkUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
/**
* 申通
*/
@Service
public class StoExpress extends ResponseController implements Express {
private static final Logger log = LoggerFactory.getLogger(StoExpress.class);
private static String url = "https://cloudinter-linkgatewayonline.sto.cn/gateway/link.do";
private static String api_name = "STO_TRACE_QUERY_COMMON";
private static String from_appkey = "ABCDEFGHIJKLMNO";
private static String from_code = "ABCDEFGHIJKLMNO";
private static String to_appkey = "sto_trace_query";
private static String to_code = "sto_trace_query";
private static String secretKey = "E10ADC3949BA59ABBE56E057F20F883E";
@Override
public String expressCode() {
return "STO";
}
@Override
public ExpressSearchResponse logisticsSearch(ExpressSearchRequest request) {
log.info("申通快递查询参数[{}]", JSON.toJSONString(request));
JSONArray jsonArray = new JSONArray();
try {
LinkRequest data = new LinkRequest();
data.setFromAppkey(from_appkey);
data.setFromCode(from_code);
data.setToAppkey(to_appkey);
data.setToCode(to_code);
data.setApiName(api_name);
JSONObject jsonObject = new JSONObject();
List<String> ll = new ArrayList<>();
ll.add(request.getLogisticsNo());
jsonObject.put("waybillNoList", ll);
data.setContent(jsonObject.toJSONString());
String res = LinkUtils.request(data, url, secretKey);
log.info("请求返回结果[{}]", res);
jsonArray = JSONObject.parseObject(res).getJSONObject("data").getJSONArray(request.getLogisticsNo());
} catch (Exception e) {
log.error("申通快递查询出错[{}]", e.getMessage());
}
ExpressSearchResponse expressSearchResponse = checkResult(jsonArray, request);
log.info("请求返回[{}]", JSON.toJSONString(controller(expressSearchResponse, jsonArray, "memo", "opTime")));
return controller(expressSearchResponse, jsonArray, "memo", "opTime");
}
}
例9:众邮快递——>ZyExpress 【引用众邮SDK】
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jdwl.open.api.sdk.DefaultJdClient;
import com.jdwl.open.api.sdk.JdClient;
import com.jdwl.open.api.sdk.JdException;
import com.jdwl.open.api.sdk.domain.zhongyouex.OrderTraceApi.CommonParam;
import com.jdwl.open.api.sdk.request.zhongyouex.OrderFindTraceInfoByWaybillCodeLopRequest;
import com.jdwl.open.api.sdk.response.zhongyouex.OrderFindTraceInfoByWaybillCodeResponse;
import ExpressSearchRequest;
import ExpressSearchResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
/**
* 众邮
*/
@Service
public class ZyExpress extends ResponseController implements Express {
private static final Logger log = LoggerFactory.getLogger(ZyExpress.class);
private static String serverUrl = "https://api.zhongyouex.com/routerjson";
private static String accessToken = "E10ADC3949BA59ABBE56E057F20F883E";
private static String appKey = "E10ADC3949BA59ABBE56E057F20F883E";
private static String appSecret = "E10ADC3949BA59ABBE56E057F20F883E";
private static String appCode = "EXPRESS_100";
private static String source = "1234";
private static String userCode = "zhangsan123";
@Override
public String expressCode() {
return "ZY";
}
@Override
public ExpressSearchResponse logisticsSearch(ExpressSearchRequest request) {
log.info("众邮快递查询参数[{}]", JSON.toJSONString(request));
JSONArray jsonArray = new JSONArray();
try {
JdClient client = new DefaultJdClient(serverUrl, accessToken, appKey, appSecret);
OrderFindTraceInfoByWaybillCodeLopRequest lopRequest = new OrderFindTraceInfoByWaybillCodeLopRequest();
lopRequest.setWaybillCode(request.getLogisticsNo());
CommonParam commonParam = new CommonParam();
commonParam.setAppCode(appCode);
commonParam.setSource(source);
commonParam.setUserCode(userCode);
lopRequest.setCommonParam(commonParam);
OrderFindTraceInfoByWaybillCodeResponse response = client.execute(lopRequest);
log.info("请求返回结果[{}]", response.getMsg());
JSONObject jsonObject = JSONObject.parseObject(response.getMsg());
jsonArray = jsonObject.getJSONObject("response").getJSONObject("content").getJSONArray("data");
} catch (JdException e) {
log.error("众邮快递查询出错[{}]", e.getErrMsg());
}
ExpressSearchResponse expressSearchResponse = checkResult(jsonArray, request);
log.info("请求返回[{}]", JSON.toJSONString(controller(expressSearchResponse, jsonArray, "content", "operateTime")));
return controller(expressSearchResponse, jsonArray, "content", "operateTime");
}
}
例10:圆通快递——>YtoExpress
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import ExpressSearchRequest;
import ExpressSearchResponse;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.net.URLEncoder;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* 圆通
*/
@Service
public class YtoExpress extends ResponseController implements Express {
private static final Logger log = LoggerFactory.getLogger(YtoExpress.class);
private static String url = "http://openapi.yto.net.cn/service/waybill_query/v1/X1FKbA";
private static String user_id = "YTOTEST";
private static String app_key = "sF1Jzn";
private static String secret_key = "1QLlIZ";
private static String v = "1.01";
private static String method = "yto.Marketing.WaybillTrace";
@Resource
HttpClientUtils httpClientUtils;
@Override
public String expressCode() {
return "YTO";
}
@Override
public ExpressSearchResponse logisticsSearch(ExpressSearchRequest request) {
log.info("圆通快递查询参数[{}]", JSON.toJSONString(request));
JSONArray jsonArray = new JSONArray();
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("Number", request.getLogisticsNo());
String timestamp = DateFormatUtils.format(new Date(), "yyyy-mm-dd HH:mm:ss");
String sign = secret_key + "app_key" + app_key + "formatJSONmethod" + method + "timestamp"
+ timestamp + "user_id" + user_id + "v" + v;
sign = MD5.getInstance().getMD5String(sign).toUpperCase();
String params = "sign=" + sign + "&app_key=" + app_key + "&format=JSON&method=" + method + "×tamp="
+ timestamp + "&user_id=" + user_id + "&v=" + v + "¶m=" + URLEncoder.encode(jsonObject.toJSONString(), "UTF-8");
Map<String, String> headers = new HashMap<>(1);
headers.put("Content-Type", "application/x-www-form-urlencoded");
String res = httpClientUtils.post(url, params, headers);
log.info("请求返回结果[{}]", res);
jsonArray = JSONObject.parseArray(res);
} catch (Exception e) {
log.error("圆通快递查询出错[{}]", e.getMessage());
}
ExpressSearchResponse expressSearchResponse = checkResult(jsonArray, request);
log.info("请求返回[{}]", JSON.toJSONString(controller(expressSearchResponse, jsonArray, "processInfo", "upload_Time")));
return controller(expressSearchResponse, jsonArray, "processInfo", "upload_Time");
}
}
例11:中通快递——>ZtoExpress【旧版】
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import ExpressSearchRequest;
import ExpressSearchResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.Base64Utils;
import javax.annotation.Resource;
import java.net.URLEncoder;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
/**
* 中通
*/
@Component
public class ZtoExpress extends ResponseController implements Express {
private static final Logger log = LoggerFactory.getLogger(ZtoExpress.class);
private static String url = "https://japi.zto.com/traceInterfaceNewTraces";
private static String companyId = "e10adc3949ba59abbe56e057f20f883e";
private static String key = "abcdefghijkl";
private static String msg_type = "NEW_TRACES";
@Resource
HttpClientUtils httpClientUtils;
@Override
public String expressCode() {
return "ZTO";
}
@Override
public ExpressSearchResponse logisticsSearch(ExpressSearchRequest request) throws NoSuchAlgorithmException {
JSONArray jsonArray = null;
log.info("中通快递查询参数[{}]", JSON.toJSONString(request));
try {
//组建数据格式
String strToDigest = "data=['" + request.getLogisticsNo() + "']&company_id=" + companyId + "&msg_type=" + msg_type + key;
String dataDigest = Base64Utils.encodeToString(MD5.getInstance().hash(strToDigest));
String requestData = "data=" + URLEncoder.encode("['" + request.getLogisticsNo() + "']", "UTF-8") +
"&company_id=" + companyId + "&msg_type=" + msg_type;
//拼接请求头
Map<String, String> headers = new HashMap<>(3);
headers.put("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
headers.put("x-companyId", companyId);
headers.put("x-dataDigest", dataDigest);
//发送请求并接受返回
String res = httpClientUtils.post(url, requestData, headers);
//处理返回结果
log.info("请求返回结果[{}]", res);
JSONObject json = JSONObject.parseObject(res);
jsonArray = json.getJSONArray("data").getJSONObject(0).getJSONArray("traces");
} catch (Exception e) {
log.error("中通快递查询出错[{}]", e.getMessage());
}
ExpressSearchResponse expressSearchResponse = checkResult(jsonArray, request);
log.info("请求返回[{}]", JSON.toJSONString(controller(expressSearchResponse, jsonArray, "desc", "scanDate")));
return controller(expressSearchResponse, jsonArray, "desc", "scanDate");
}
}
例12:中通快递——>ZtoExpress【新版】
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;;
import ExpressSearchRequest;
import ExpressSearchResponse;
import zop.EncryptionType;
import zop.ZopClient;
import zop.ZopPublicRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
/**
* 中通
*/
@Component
public class ZtoExpress extends ResponseController implements Express {
private static final Logger log = LoggerFactory.getLogger(ZtoExpress.class);
private static String url = "https://japi.zto.com/zto.merchant.waybill.track.query";
private static String appKey = "ea8a706c4c34a168abcde";
private static String appSecret = "827ccb0eea8a706c4c34a16891f84e7b";
@Override
public String expressCode() {
return "ZTO";
}
@Override
public ExpressSearchResponse logisticsSearch(ExpressSearchRequest request) throws NoSuchAlgorithmException {
JSONArray jsonArray = null;
log.info("中通快递查询参数[{}]", JSON.toJSONString(request));
ZopClient client = new ZopClient(appKey, appSecret);
ZopPublicRequest zopPublicRequest = new ZopPublicRequest();
String mobilePhone = request.getReceiverMobile().substring(request.getReceiverMobile().length() - 4);
zopPublicRequest.setBody("{\"billCode\":\"" + request.getLogisticsNo() + "\",\"mobilePhone\":\"" + mobilePhone + "\"}");
zopPublicRequest.setUrl(url);
zopPublicRequest.setBase64(true);
zopPublicRequest.setEncryptionType(EncryptionType.MD5);
zopPublicRequest.setTimestamp(null);
try {
String res = client.execute(zopPublicRequest);
//处理返回结果
log.info("请求返回结果[{}]", res);
JSONObject json = JSONObject.parseObject(res);
jsonArray = json.getJSONArray("result");
log.info("请求返回结果jsonArray[{}]", jsonArray);
} catch (IOException e) {
log.error("中通快递查询出错[{}]", e.getMessage());
}
ExpressSearchResponse expressSearchResponse = checkResult(jsonArray, request);
log.info("中通快递返回数据[{}]", JSON.toJSONString(controllerZto(expressSearchResponse, jsonArray, "desc", "scanDate")));
return controllerZto(expressSearchResponse, jsonArray, "desc", "scanDate");
}
}
zop :中通快递新版所需公共资源包
zop 之 EncryptionType 枚举类
public enum EncryptionType {
MD5,
SHA256,
HmacSHA256
}
zop 之 HttpUtil 工具类
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Map;
public class HttpUtil {
private static final int DEFAULT_TIMEOUT = 3000;
public static String post(String interfaceUrl, Map<String, String> headers, String queryString) throws IOException {
URL url = new URL(interfaceUrl);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
con.setDoOutput(true);
con.setConnectTimeout(DEFAULT_TIMEOUT);
con.setReadTimeout(DEFAULT_TIMEOUT);
for (Map.Entry<String, String> e : headers.entrySet()) {
con.setRequestProperty(e.getKey(), e.getValue());
}
DataOutputStream out = null;
BufferedReader in = null;
try {
out = new DataOutputStream(con.getOutputStream());
out.write(queryString.getBytes(Charset.forName("UTF-8")));
out.flush();
in = new BufferedReader(
new InputStreamReader(con.getInputStream(), "UTF-8"));
String inputLine;
StringBuilder content = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
content.append(inputLine);
}
return content.toString();
} finally {
if (out != null) {
try {
out.close();
} catch (Exception ignored) {
}
}
if (in != null) {
try {
in.close();
} catch (Exception ignored) {
}
}
}
}
public static String postJson(String interfaceUrl, Map<String, String> headers, String json) throws IOException {
URL url = new URL(interfaceUrl);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type", "application/json; charset=utf-8");
con.setDoOutput(true);
con.setConnectTimeout(DEFAULT_TIMEOUT);
con.setReadTimeout(DEFAULT_TIMEOUT);
for (Map.Entry<String, String> e : headers.entrySet()) {
con.setRequestProperty(e.getKey(), e.getValue());
}
DataOutputStream out = null;
BufferedReader in = null;
try {
out = new DataOutputStream(con.getOutputStream());
out.write(json.getBytes(Charset.forName("UTF-8")));
out.flush();
in = new BufferedReader(
new InputStreamReader(con.getInputStream(), "UTF-8"));
String inputLine;
StringBuilder content = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
content.append(inputLine);
}
return content.toString();
} finally {
if (out != null) {
try {
out.close();
} catch (Exception ignored) {
}
}
if (in != null) {
try {
in.close();
} catch (Exception ignored) {
}
}
}
}
}
zop 之 ZopClient 工具类
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
public class ZopClient {
private final ZopProperties properties;
public ZopClient(ZopProperties properties) {
this.properties = properties;
}
public ZopClient(String appKey, String appSecret) {
this.properties = new ZopProperties(appKey, appSecret);
}
public String execute(ZopPublicRequest request) throws IOException {
String jsonBody = request.getBody();
if (jsonBody == null) {
Map<String, String> params = request.getParams();
StringBuilder queryBuilder = new StringBuilder();
StringBuilder strToDigestBuilder = new StringBuilder();
for (Map.Entry<String, String> e : params.entrySet()) {
strToDigestBuilder.append(e.getKey()).append("=").append(e.getValue()).append("&");
queryBuilder.append(urlEncode(e.getKey())).append("=").append(urlEncode(e.getValue())).append("&");
}
String queryString = queryBuilder.substring(0, queryBuilder.length() - 1);
String strToDigest = strToDigestBuilder.substring(0, strToDigestBuilder.length() - 1);
strToDigest = strToDigest + properties.getKey();
Map<String, String> headers = new HashMap<String, String>();
headers.put("x-companyid", properties.getCompanyId());
headers.put("x-datadigest", ZopDigestUtil.digest(strToDigest, request.getBase64(), request.getEncryptionType(), request.getTimestamp(), request.getSecretKey()));
if (request.getTimestamp() != null) {
headers.put("x-timestamp", String.valueOf(request.getTimestamp()));
}
return HttpUtil.post(request.getUrl(), headers, queryString);
} else {
Map<String, String> headers = new HashMap<>();
String strToDigest = jsonBody + properties.getKey();
headers.put("x-companyid", properties.getCompanyId());
headers.put("x-datadigest", ZopDigestUtil.digest(strToDigest, request.getBase64(), request.getEncryptionType(), request.getTimestamp(), request.getSecretKey()));
if (request.getTimestamp() != null) {
headers.put("x-timestamp", String.valueOf(request.getTimestamp()));
}
return HttpUtil.postJson(request.getUrl(), headers, jsonBody);
}
}
private String urlEncode(String str) {
try {
return URLEncoder.encode(str, "UTF-8");
} catch (UnsupportedEncodingException e) {
return str;
}
}
}
zop 之 ZopDigestUtil 工具类
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
public class ZopDigestUtil {
private static final String HMAC_SHA_256 = "HmacSHA256";
private static final Map<String, Mac> MAC_MAP = new ConcurrentHashMap<>();
public static String digest(String str, Boolean isBase64, EncryptionType encryptionType, Long timestamp, String secretKey) {
if (timestamp != null) {
str = timestamp + str;
}
boolean base64 = isBase64 == null || isBase64;
switch (encryptionType) {
case SHA256:
return base64 ? Base64.encodeBase64String(DigestUtils.sha256(str)) : DigestUtils.sha256Hex(str);
case HmacSHA256:
return base64 ? Base64.encodeBase64String(hmacSha256(secretKey, str)) : hmacSha256Str(secretKey, str);
default:
return base64 ? Base64.encodeBase64String(DigestUtils.md5(str)) : DigestUtils.md5Hex(str);
}
}
public static String hmacSha256Str(String key, String body) {
return Hex.encodeHexString(hmacSha256(key, body));
}
public static byte[] hmacSha256(String key, String body) {
if (Objects.isNull(key)) {
key = "";
}
Mac mac = MAC_MAP.get(key);
if (mac == null) {
try {
mac = Mac.getInstance(HMAC_SHA_256);
SecretKey secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), HMAC_SHA_256);
mac.init(secretKey);
MAC_MAP.put(key, mac);
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
throw new RuntimeException(e);
}
}
return mac.doFinal(body.getBytes(StandardCharsets.UTF_8));
}
}
zop 之 ZopProperties 配置类
public class ZopProperties {
private String companyId;
private String key;
public ZopProperties() {
}
public ZopProperties(String appKey, String appSecret) {
this.companyId = appKey;
this.key = appSecret;
}
public String getCompanyId() {
return companyId;
}
public void setCompanyId(String companyId) {
this.companyId = companyId;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
}
zop 之 ZopPublicRequest 请求类
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import java.util.HashMap;
import java.util.Map;
public class ZopPublicRequest {
private String url;
private Map<String, String> params = new HashMap<String, String>();
// 如果body有值,表示使用application/json的方式传值
private String body;
/**
* 签名是否需要base64
*/
private Boolean isBase64;
/**
* 加密方式,MD5或者SHA256
*/
private EncryptionType encryptionType;
/**
* HmacSHA256加密key
*/
private String secretKey;
/**
* 时间戳,如果接口文档未标识使用时间戳请不要传值,否则会导致签名错误
*/
private Long timestamp;
public ZopPublicRequest() {
}
public void setBody(String body) {
this.body = body;
}
public String getBody() {
return body;
}
public void addParam(String k, String v) {
params.put(k, v);
}
public void setData(String data) {
try {
JSONObject jsonObject = JSON.parseObject(data);
for (Map.Entry<String, Object> entry : jsonObject.entrySet()) {
params.put(entry.getKey(), entry.getValue().toString());
}
} catch (Exception e) {
throw new RuntimeException("JSON格式不对,请检查数据", e);
}
}
public void setDataObj(Map<String, String> data) {
params.putAll(data);
}
public void addParam(Map<String, String> p) {
for (Map.Entry<String, String> entry : p.entrySet()) {
params.put(entry.getKey(), entry.getValue());
}
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Map<String, String> getParams() {
return params;
}
public void setParams(Map<String, String> params) {
this.params = params;
}
public Boolean getBase64() {
return isBase64;
}
public void setBase64(Boolean base64) {
isBase64 = base64;
}
public EncryptionType getEncryptionType() {
return encryptionType;
}
public void setEncryptionType(EncryptionType encryptionType) {
this.encryptionType = encryptionType;
}
public String getSecretKey() {
return secretKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
public Long getTimestamp() {
return timestamp;
}
public void setTimestamp(Long timestamp) {
this.timestamp = timestamp;
}
}