ITPub博客

首页 > 嵌入式/内核开发 > 嵌入式/内核开发 > 【分享】电商网站快速对接物流快递鸟单号查询 API 接口申请案例

【分享】电商网站快速对接物流快递鸟单号查询 API 接口申请案例

原创 嵌入式/内核开发 作者:爱程序的小猿 时间:2019-12-02 17:50:28 0 删除 编辑

1.快递查询API接口

       对于现在的网上购物,“我买的东西发到哪了?”这是每个买家越来越关心的问题,“我商城的物流信息跟踪服务客户的体验效果还满意吗?”这是每个卖家越来越操心的问题,因为在现代社会中,人们不仅仅在乎商品本身的价值,而且在乎甚至更在乎服务的价值体现!

而目前快递查询API的模式有两种,一种是即时查询,也就是说发出请求就会返回数据;另一种是订阅查询,        当所订阅的快递单号有物流信息的跟新时就会返回数据,不需要发出请求。目前在国内快递查询API接口做得好的有快递鸟、菜鸟等。

今天我们主要分享的就是快递鸟快递单号查询接口的对接指南,快递单号查询接口对接的应用场景有很多,很多场景会遇到,最主要的就是电商网站用户打开“我的订单”时调用此 API 显示物流信息详情,电商管理后台的物流系统,客服在对账前查询所有运单的签收状态,并追踪问题,电商平台对商家物流管控,要求必须在多久快递必须发出要看到揽件状态,多久必须收到货物看到签收状态,根据这些状态对商家管控从而提升用户的整体满意度。

对接使用流程

  1. 注册快递鸟账号并申请认证http://www.kdniao.com/reg

  2. 快递鸟根据单号和快递公司查询到物流轨迹状态

  3. 快递鸟将查询到的物流轨迹状态反馈給电商平台或 ISV 服务商

  4. 电商平台或 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'