1.快递查询API接口
对于现在的网上购物,“我买的东西发到哪了?”这是每个买家越来越关心的问题,“我商城的物流信息跟踪服务客户的体验效果还满意吗?”这是每个卖家越来越操心的问题,因为在现代社会中,人们不仅仅在乎商品本身的价值,而且在乎甚至更在乎服务的价值体现!
而目前快递查询API的模式有两种,一种是即时查询,也就是说发出请求就会返回数据;另一种是订阅查询, 当所订阅的快递单号有物流信息的跟新时就会返回数据,不需要发出请求。目前在国内快递查询API接口做得好的有快递鸟、菜鸟等。
今天我们主要分享的就是快递鸟快递单号查询接口的对接指南,快递单号查询接口对接的应用场景有很多,很多场景会遇到,最主要的就是电商网站用户打开“我的订单”时调用此 API 显示物流信息详情,电商管理后台的物流系统,客服在对账前查询所有运单的签收状态,并追踪问题,电商平台对商家物流管控,要求必须在多久快递必须发出要看到揽件状态,多久必须收到货物看到签收状态,根据这些状态对商家管控从而提升用户的整体满意度。
注册快递鸟账号并申请认证http://www.kdniao.com/reg
快递鸟根据单号和快递公司查询到物流轨迹状态
快递鸟将查询到的物流轨迹状态反馈給电商平台或 ISV 服务商
电商平台或 ISV 服务商接收数据并实时处理做数据展示或应用
快递鸟功能非常强大,免费,可以随时查询快递轨迹,也可以推送快递状态,很强大很方便。直接上实现代码。直接上代码:这是开发的快递鸟推送的快递信息接口,接收数据处理数据。这里 method 一定要 post
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 |
@RequestMapping
(value =
"tuisong"
,method=RequestMethod.POST)
@ResponseBody
public
Map<String,Object> tuisong(String RequestData,String RequestType,String DataSign) {
RequestData=Encodes.unescapeHtml(RequestData); Map<String,Object> result=
new
HashMap<String,Object>();
//判断是从快递鸟进入
if
(!(RequestType.equals(
"101"
) && KdniaoUtils.isFromKdniao(RequestData, DataSign))){
result.put(
"Success"
,
false
);
result.put(
"Reason"
,
"不是快递鸟推送来的数据。"
);
return
result;
}
JSONObject jsonObj=
new
JSONObject(RequestData);
result.put(
"EBusinessID"
,jsonObj.getString(
"EBusinessID"
));
result.put(
"UpdateTime"
,jsonObj.getString(
"PushTime"
));
try
{
JSONArray jsonArray=jsonObj.getJSONArray(
"Data"
);
List<Ship> shipList=Lists.newArrayList();
Ship ship=
null
;
for
(
int
i=
0
;i<jsonArray.length();i++){
jsonObj=jsonArray.getJSONObject(i);
if
(!jsonObj.getBoolean(
"Success"
)){
continue
;
}
ship=
new
Ship();
ship.setExpress(ErpUtils.getExpressByKdniao(jsonObj.getString(
"ShipperCode"
)));
ship.setExpressNo(jsonObj.getString(
"LogisticCode"
)); String state=jsonObj.getString(
"State"
);
ship.setStatus(KdniaoUtils.getShipStatus(state));
if
(ship.getStatus().equals(Ship.STATUS_SIGN)){
JSONArray array=jsonObj.getJSONArray(
"Traces"
);
JSONObject obj=array.getJSONObject(array.length()-
1
); String time=obj.getString(
"AcceptTime"
);
ship.setSignTime(DateUtils.parseDate(time,
"yyyy-MM-dd HH:mm:ss"
));
}
shipList.add(ship);
}
shipService.updateStatus(shipList);
result.put(
"Success"
,
true
);
}
catch
(Exception e) {
result.put(
"Success"
,
false
);
result.put(
"Reason "
,
"解析数据失败。"
);
e.printStackTrace();
}
return
result; |
这里是个工具类,提供静态方法。KdniaoUtils.java
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224 |
public
class
KdniaoUtils {
//DEMO
public
static
void
main(String[] args)
throws
UnsupportedEncodingException, Exception {
}
//电商 ID
private
static
String EBusinessID=
"1283391"
;
//电商加密私钥,快递鸟提供,注意保管,不要泄漏
private
static
String AppKey=
"9df9507a-62fa-47f3-9227-bdd02b95ccf1"
;
//请求 url
private
static
String ReqURL=
"http://api.kdniao.cc/Ebusiness/EbusinessOrderHandle.aspx"
;
public
static
Map<String,String> StateMap=
new
HashMap<String,String>();
static
{
StateMap.put(
"0"
,
"没有记录"
);
StateMap.put(
"1"
,
"已揽收"
);
StateMap.put(
"2"
,
"运输途中"
);
StateMap.put(
"201"
,
"到达目的城市"
);
StateMap.put(
"3"
,
"已签收"
);
StateMap.put(
"4"
,
"问题件"
);
}
// 物流状态: 0-无轨迹,1-已揽收,2-在途中 201-到达派件城市,3-签收,4-问题件
public
static
int
getShipStatus(String state){
switch
(state){
case
"0"
:
return
Ship.STATUS_SHIPPED;
case
"1"
:
return
Ship.STATUS_SHIPPED;
case
"2"
:
return
Ship.STATUS_ONTHEWAY;
case
"201"
:
return
Ship.STATUS_PAISONG;
case
"3"
:
return
Ship.STATUS_SIGN;
case
"4"
:
return
Ship.STATUS_DIFFICULT;
default
:
return
Ship.STATUS_SHIPPED;
}
}
/**
* 快递物流轨迹跟踪
* @param ship
* @return
*/
public
static
Map<String, Object> trace(Ship ship){ Map<String, Object> map =
new
HashMap<String, Object>();
try
{ String result=getOrderTracesByJson(ship.getExpress().getKdniao(),ship.getExpressNo());
JSONObject dataJson =
new
JSONObject(result);
if
(dataJson.getBoolean(
"Success"
)){
map.put(
"errCode"
,
0
); String state=dataJson.getString(
"state"
);
map.put(
"status"
,getShipStatus(state));
map.put(
"statusName"
,StateMap.containsKey(state)?StateMap.get(state):state);
JSONArray list = (JSONArray) dataJson.get(
"Traces"
);
if
(list!=
null
&&list.length()>
0
) {
List<Map<String, String>> dataList =
new
ArrayList<Map<String, String>>();
for
(
int
i =
0
; i < list.length(); i++) {
JSONObject dataMapJson = (JSONObject) list.get(i); Map<String, String> dataMap =
new
HashMap<String, String>();
dataMap.put(
"time"
, dataMapJson.getString(
"AcceptTime"
));
// 每条跟踪信息的时间
dataMap.put(
"content"
, dataMapJson.getString(
"AcceptStation"
));
// 每条跟综信息的描述
dataList.add(dataMap);
}
map.put(
"dataList"
, dataList);
}
}
else
{
map.put(
"errCode"
,
1
);
map.put(
"errMsg"
, dataJson.getString(
"Reason"
));
}
}
catch
(Exception e) {
map.put(
"errMsg"
,
"快递接口调用出错。"
);
e.printStackTrace();
}
return
map;
}
/**
* 发送订阅信息
*/
public
static
Map<String, Object> subscribe(Ship ship){ Map<String, Object> map =
new
HashMap<String, Object>();
try
{ String result=orderTracesSubByJson(ship.getExpress().getKdniao(),ship.getExpressNo());
JSONObject dataJson =
new
JSONObject(result);
if
(dataJson.getBoolean(
"Success"
)){
map.put(
"success"
,
true
);
}
else
{
map.put(
"success"
,
false
);
map.put(
"errMsg"
, dataJson.getString(
"Reason"
));
}
}
catch
(Exception e) {
map.put(
"errMsg"
,
"快递接口调用出错。"
);
e.printStackTrace();
}
return
map;
}
/**
* Json 方式 查询订单物流轨迹
* @throws Exception
*/
public
static
String getOrderTracesByJson(String expCode, String expNo)
throws
Exception{ String requestData=
"{'OrderCode':'','ShipperCode':'"
+ expCode +
"','LogisticCode':'"
+ expNo +
"'}"
; Map<String, String> params =
new
HashMap<String, String>();
params.put(
"RequestData"
, urlEncoder(requestData,
"UTF-8"
));
params.put(
"EBusinessID"
, EBusinessID);
params.put(
"RequestType"
,
"1002"
); String dataSign=encrypt(requestData, AppKey,
"UTF-8"
);
params.put(
"DataSign"
, urlEncoder(dataSign,
"UTF-8"
));
params.put(
"DataType"
,
"2"
); String result=sendPost(ReqURL, params);
return
result;
}
/**
* Json 方式 物流信息订阅
* @throws Exception
*/
public
static
String orderTracesSubByJson(String expCode, String expNo)
throws
Exception{ String requestData=
"{'OrderCode':'','ShipperCode':'"
+ expCode +
"','LogisticCode':'"
+ expNo +
"'}"
; Map<String, String> params =
new
HashMap<String, String>();
params.put(
"RequestData"
, urlEncoder(requestData,
"UTF-8"
));
params.put(
"EBusinessID"
, EBusinessID);
params.put(
"RequestType"
,
"1008"
); String dataSign=encrypt(requestData, AppKey,
"UTF-8"
);
params.put(
"DataSign"
, urlEncoder(dataSign,
"UTF-8"
));
params.put(
"DataType"
,
"2"
); String result=sendPost(ReqURL, params);
return
result;
}
/**
* 判断是否从快递鸟进入的推送数据
* @param RequestData
* @param DataSign
* @return
*/
public
static
boolean
isFromKdniao(String RequestData,String DataSign){
try
{
return
encrypt(RequestData, AppKey,
"UTF-8"
).equals(DataSign);
}
catch
(UnsupportedEncodingException e) {
e.printStackTrace();
}
catch
(Exception e) {
e.printStackTrace();
}
return
false
;
}
/**
* MD5 加密
* @param str 内容
* @param charset 编码方式
* @throws Exception
*/
@SuppressWarnings
(
"unused"
)
private
static
String MD5(String str, String charset)
throws
Exception {
MessageDigest md = MessageDigest.getInstance(
"MD5"
);
md.update(str.getBytes(charset));
byte
[] result = md.digest();
StringBuffer sb =
new
StringBuffer(
32
);
for
(
int
i =
0
; i < result.length; i++) {
int
val = result[i] &
0xff
;
if
(val <=
0xf
) {
sb.append(
"0"
);
}
sb.append(Integer.toHexString(val));
}
return
sb.toString().toLowerCase();
}
/**
* base64 编码
* @param str 内容
* @param charset 编码方式
* @throws UnsupportedEncodingException
*/
private
static
String base64(String str, String charset)
throws
UnsupportedEncodingException{ String encoded = base64Encode(str.getBytes(charset));
return
encoded;
}
@SuppressWarnings
(
"unused"
)
private
static
String urlEncoder(String str, String charset)
throws
UnsupportedEncodingException{ String result = URLEncoder.encode(str, charset);
return
result;
}
/**
* 电商 Sign 签名生成
* @param content 内容
* @param keyValue Appkey
* @param charset 编码方式
* @throws UnsupportedEncodingException ,Exception
* @return DataSign 签名
*/
@SuppressWarnings
(
"unused"
)
private
static
String encrypt (String content, String keyValue, String charset)
throws
UnsupportedEncodingException, Exception
{
if
(keyValue !=
null
)
{
return
base64(MD5(content + keyValue, charset), charset);
}
return
base64(MD5(content, charset), charset);
}
/**
* 向指定 URL 发送 POST 方法的请求
* @param url 发送请求的 URL
* @param params 请求的参数集合
* @return 远程资源的响应结果
*/
@SuppressWarnings
(
"unused"
)
private
static
String sendPost(String url, Map<String, String> params) {
OutputStreamWriter out =
null
;
BufferedReader in =
null
;
StringBuilder result =
new
StringBuilder();
try
{
URL realUrl =
new
URL(url);
HttpURLConnection conn =(HttpURLConnection) realUrl.openConnection();
// 发送 POST 请求必须设置如下两行
conn.setDoOutput(
true
);
conn.setDoInput(
true
);
// POST 方法
conn.setRequestMethod(
"POST"
);
// 设置通用的请求属性
conn.setRequestProperty(
"accept"
,
"*/*"
);
conn.setRequestProperty(
"connection"
,
"Keep-Alive"
);
conn.setRequestProperty(
"user-agent"
,
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"
);
conn.setRequestProperty(
"Content-Type"
,
"application/x-www-form-urlencoded"
);
conn.connect();
// 获取 URLConnection 对象对应的输出流
out =
new
OutputStreamWriter(conn.getOutputStream(),
"UTF-8"
);
// 发送请求参数
if
(params !=
null
) {
StringBuilder param =
new
StringBuilder();
for
(Map.Entry<String, String> entry : params.entrySet()) {
if
(param.length()>
0
){
param.append(
"&"
);
}
param.append(entry.getKey());
param.append(
"="
);
param.append(entry.getValue());
//System.out.println(entry.getKey()+":"+entry.getValue());
}
//System.out.println("param:"+param.toString());
out.write(param.toString());
}
// flush 输出流的缓冲
out.flush();
// 定义 BufferedReader 输入流来读取 URL 的响应
in =
new
BufferedReader(
new
InputStreamReader(conn.getInputStream(),
"UTF-8"
)); String line;
while
((line = in.readLine()) !=
null
) {
result.append(line);
}
}
catch
(Exception e) {
e.printStackTrace();
}
//使用 finally 块来关闭输出流、输入流
finally
{
try
{
if
(out!=
null
){
out.close();
}
if
(in!=
null
){ in.close();
}
}
catch
(IOException ex){
ex.printStackTrace();
}
}
return
result.toString();
}
private
static
char
[] base64EncodeChars =
new
char
[] {
'A'
,
'B'
,
'C'
,
'D'
,
'E'
,
'F'
,
'G'
,
'H'
,
'I'
,
'J'
,
'K'
,
'L'
,
'M'
,
'N'
,
'O'
,
'P'
,
'Q'
,
'R'
,
'S'
,
'T'
,
'U'
,
'V'
,
'W'
,
'X'
,
'Y'
,
'Z'
,
'a'
,
'b'
,
'c'
,
'd'
,
'e'
,
'f'
,
'g'
,
'h'
,
'i'
,
'j'
,
'k'
,
'l'
,
'm'
,
'n'
,
'o'
,
'p'
,
'q'
,
'r'
,
's'
,
't'
,
'u'
,
'v'
,
'w'
,
'x'
,
'y'
,
'z'
,
'0'
,
'1'
,
'2'
,
'3'
,
'4'
,
'5'
,
'6'
,
'7'
,
'8'
,
'9'
,
'+'
,
'/'
};
private
static
String base64Encode(
byte
[] data) {
StringBuffer sb =
new
StringBuffer();
int
len = data.length;
int
i =
0
;
int
b1, b2, b3;
while
(i < len) {
b1 = data[i++] &
0xff
;
if
(i == len)
{
sb.append(base64EncodeChars[b1 >>>
2
]);
sb.append(base64EncodeChars[(b1 &
0x3
) <<
4
]);
sb.append(
"=="
);
break
;
}
b2 = data[i++] &
0xff
;
if
(i == len)
{
sb.append(base64EncodeChars[b1 >>>
2
]);
sb.append(base64EncodeChars[((b1 &
0x03
) <<
4
) | ((b2 &
0xf0
) >>>
4
)]);
sb.append(base64EncodeChars[(b2 &
0x0f
) <<
2
]);
sb.append(
"="
);
break
;
}
b3 = data[i++] &
0xff
;
sb.append(base64EncodeChars[b1 >>>
2
]);
sb.append(base64EncodeChars[((b1 &
0x03
) <<
4
) | ((b2 &
0xf0
) >>>
4
)]);
sb.append(base64EncodeChars[((b2 &
0x0f
) <<
2
) | ((b3 &
0xc0
) >>>
6
)]);
sb.append(base64EncodeChars[b3 &
0x3f
]);
}
return
sb.toString();
}}
|
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69945342/viewspace-2666558/ ,如需转载,请注明出处,否则将追究法律责任。