电商网站物流快递单号查询 API 接口申请案例

  • 2019 年 10 月 4 日
  • 笔记

场景需求描述

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

对接使用流程

  1. 注册快递鸟账号并申请认证
  2. 快递鸟根据单号和快递公司查询到物流轨迹状态
  3. 快递鸟将查询到的物流轨迹状态反馈给电商平台或 ISV 服务商
  4. 电商平台或 ISV 服务商接收数据并实时处理做数据展示或应用

快递鸟功能非常强大,免费,可以随时查询快递轨迹,也可以推送快递状态,很强大很方便。直接上实现代码。直接上代码:这是开发的快递鸟推送的快递信息接口,接收数据处理数据。这里 method 一定要 post

@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;              
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();      }  }