【分享】電商網站快速對接物流快遞鳥單號查詢 API 介面申請案例

愛程式的小猿發表於2019-12-02

1.快遞查詢API介面

       對於現在的網上購物,“我買的東西發到哪了?”這是每個買家越來越關心的問題,“我商城的物流資訊跟蹤服務客戶的體驗效果還滿意嗎?”這是每個賣家越來越操心的問題,因為在現代社會中,人們不僅僅在乎商品本身的價值,而且在乎甚至更在乎服務的價值體現!

而目前快遞查詢API的模式有兩種,一種是即時查詢,也就是說發出請求就會返回資料;另一種是訂閱查詢,        當所訂閱的快遞單號有物流資訊的跟新時就會返回資料,不需要發出請求。目前在國內快遞查詢API介面做得好的有快遞鳥、菜鳥等。

今天我們主要分享的就是快遞鳥快遞單號查詢介面的對接指南,快遞單號查詢介面對接的應用場景有很多,很多場景會遇到,最主要的就是電商網站使用者開啟“我的訂單”時呼叫此 API 顯示物流資訊詳情,電商管理後臺的物流系統,客服在對賬前查詢所有運單的簽收狀態,並追蹤問題,電商平臺對商家物流管控,要求必須在多久快遞必須發出要看到攬件狀態,多久必須收到貨物看到簽收狀態,根據這些狀態對商家管控從而提升使用者的整體滿意度。

對接使用流程

  1. 註冊快遞鳥賬號並申請認證

  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= " ;    
     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部落格 ” ,連結:http://blog.itpub.net/69945342/viewspace-2666558/,如需轉載,請註明出處,否則將追究法律責任。

相關文章