zoukankan      html  css  js  c++  java
  • 物流即使查询API

    上一篇文章我们介绍了一个物流服务提供商,推荐大家使用快递鸟接口,主要介绍了如何注册账号,获得密钥,找不到注册地址的,我在发一下:

    http://kdniao.com/reg

    之前也聊过如何利用快递鸟提供的接口来实现即时查询。也提供了C#代码,这次我们用Java来实现接口对接,

    在开发之前,我们先来了解一下什么是即时查询,按我的理解就是,我们提供运单号和快递公司编码,然后调用快递鸟提供的查询接口,即可查询运单号的发货情况,我们可以通过这个接口获悉到包裹的收件时间,派送时间,签收时间,签收人,如果体验做的更好一点,通过大数据可以分析这个包裹的预计派送时间。

    以下是我通过调用快递鸟接口提供的即时查询接口获得的内容:

     

    外观显示效果可以忽略,这是我项目应用的截图,我们得到轨迹信息以后,可以按自己的页面风格最终呈现给客户。

    好了,现在我们来聊一聊具体实现吧!

    首先我们准备好需要用到的资源,

    测试商户ID:

    test1617571

     

    测试API key:

    554343b2-7252-439b-b4eb-1af42c8f2175(此Key仅限测试环境使用)

     

    API测试地址:

    http://sandboxapi.kdniao.com:8080/kdniaosandbox/gateway/exterfaceInvoke.json

    我们先来解读一下快递鸟官网提供的接口文档说明

     

     

    这个使用流程图我是在快递鸟官网截图的,我们先来梳理一下几个角色

    1,          用户,这个很好理解,就是我们这群开发人员,苦逼的程序员

    2,          快递鸟,这个写的也很清楚了,就是物流服务提供商

    3,          客户,这是我们自己的客户,我们得到快递鸟的数据以后是需要内部封装,通过各种界面展示给我们真正的上帝看的,客户看到的是我们再次封装的信息,当然如果你想把快递鸟返回的信息直接暴露给你的客户看,我也不反对。只能说,你是最棒的。

    接下来,我们讲解一下请求参数

    请求系统级参数说明:

     

    备注:R-必填(Required),O-可选(Optional),C-报文中该参数在一定条件下可选(Conditional)

    这里提到了系统级参数,也相当于是公用参数,这些参数是调用每个接口都是必须要传参的。

    接口参数:

     

    接口参数,也叫业务参数,请求的业务接口不同,参数的字段,内容也不同,是跟着业务变化的,这里我们实现的是即时查询接口,快递鸟官网要求必须传递快递公司编码和物流单号

    物流单号很好理解,就是快递面单上的运单号,快递公司编码是必须传递快递鸟支持的编码,你可能会问,我如何能知道快递鸟支持哪些快递公司,不急,马上告诉你。

    下载快递公司编码:

    http://www.kdniao.com/documents

    上一篇文章有提到,下载下来你就秒懂了,哈哈!

    正如我前面的轨迹截图,是一个中通的轨迹数据,中通快递的编码是ZTO,物流单号是78120038107849

    业务参数报文组合如下:

    {'OrderCode':'','ShipperCode':'ZTO','LogisticCode':'78120038107849'}

    请求的完整报文:

    RequestData=%7b%27OrderCode%27%3a%27%27%2c%27ShipperCode%27%3a%27ZTO%27%2c%27LogisticCode%27%3a%2778120038107849%27%7d&EBusinessID=1617571&RequestType=1002&DataSign=YzBmYTViYmExZmFhOGY1ZTY3MWY5OGFjYWRhNWVjNjU%3d&DataType=2

    返回的报文信息:

    { "LogisticCode" : "78120038107849", "ShipperCode" : "ZTO", "Traces" : [ { "AcceptStation" : "【济源市】 【济源】(0391-6965909) 的 张霞(18839032214) 已揽收", "AcceptTime" : "2020-01-16 18:30:33" }, { "AcceptStation" : "【济源市】 快件离开 【济源】 已发往 【深圳中心】", "AcceptTime" : "2020-01-16 18:36:41" }, { "AcceptStation" : "【新乡市】 快件已经到达 【新乡中转】", "AcceptTime" : "2020-01-16 22:45:49" }, { "AcceptStation" : "【新乡市】 快件离开 【新乡中转】 已发往 【深圳中心】", "AcceptTime" : "2020-01-16 22:47:48" }, { "AcceptStation" : "【深圳市】 快件已经到达 【深圳中心】", "AcceptTime" : "2020-01-18 04:05:46" }, { "AcceptStation" : "【深圳市】 快件离开 【深圳中心】 已发往 【深圳龙华】", "AcceptTime" : "2020-01-18 08:34:46" }, { "AcceptStation" : "【深圳市】 快件已经到达 【深圳龙华】", "AcceptTime" : "2020-01-18 13:14:10" }, { "AcceptStation" : "【深圳市】 【深圳龙华】 的陈智龙-王颖(13923773902) 正在第1次派件, 请保持电话畅通,并耐心等待(95720为中通快递员外呼专属号码,请放心接听)", "AcceptTime" : "2020-01-18 16:38:35" }, { "AcceptStation" : "【深圳市】 快件已由【丰巢的鑫茂花园A区(丰巢智能快递柜)】代签收, 如有问题请电联(13923773902 / 4000633333,18025858922), 感谢您使用中通快递, 期待再次为您服务!", "AcceptTime" : "2020-01-18 17:32:15" } ], "State" : "3", "EBusinessID" : "1617571", "Success" : true }

    Java关键代码:

    import java.io.BufferedReader;

    import java.io.IOException;

    import java.io.InputStreamReader;

    import java.io.OutputStreamWriter;

    import java.io.UnsupportedEncodingException;

    import java.net.HttpURLConnection;

    import java.net.URL;

    import java.net.URLEncoder;

    import java.security.MessageDigest;

    import java.util.HashMap;

    import java.util.Map;

     

    /**

    *

    * 快递鸟物流轨迹即时查询接口

    *

    * @技术QQ群: 456320272

    * @see: http://www.kdniao.com/YundanChaxunAPI.aspx

    * @copyright: 深圳市快金数据技术服务有限公司

    *

    * DEMO中的电商ID与私钥仅限测试使用,正式环境请单独注册账号

    * 单日超过500单查询量,建议接入我方物流轨迹订阅推送接口

    *

    * ID和Key请到官网申请:http://www.kdniao.com/ServiceApply.aspx

    */

     

    public class KdniaoTrackQueryAPI {

     

    //DEMO

    public static void main(String[] args) {

    KdniaoTrackQueryAPI api = new KdniaoTrackQueryAPI();

    try {

    String result = api.getOrderTracesByJson("ANE", "210001633605");

    System.out.print(result);

     

    } catch (Exception e) {

    e.printStackTrace();

    }

    }

     

    //电商ID

    private String EBusinessID="请到快递鸟官网申请http://www.kdniao.com/ServiceApply.aspx";

    //电商加密私钥,快递鸟提供,注意保管,不要泄漏

    private String AppKey="请到快递鸟官网申请http://www.kdniao.com/ServiceApply.aspx";

    //请求url

    private String ReqURL="http://api.kdniao.com/Ebusiness/EbusinessOrderHandle.aspx";

     

    /**

    * Json方式 查询订单物流轨迹

    * @throws Exception

    */

    public 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;

    }

     

    /**

    * MD5加密

    * @param str 内容

    * @param charset 编码方式

    * @throws Exception

    */

    @SuppressWarnings("unused")

    private 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 String base64(String str, String charset) throws UnsupportedEncodingException{

    String encoded = base64Encode(str.getBytes(charset));

    return encoded;

    }

     

    @SuppressWarnings("unused")

    private 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 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 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', '+', '/' };

     

    public 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();

    }

    }

    附上详细的接口文档给大家:

    http://www.kdniao.com/documents

  • 相关阅读:
    Linnia学习记录
    漫漫考研路
    ENS的学习记录
    KnockoutJS 3.X API 第四章 数据绑定(4) 控制流with绑定
    KnockoutJS 3.X API 第四章 数据绑定(3) 控制流if绑定和ifnot绑定
    KnockoutJS 3.X API 第四章 数据绑定(2) 控制流foreach绑定
    KnockoutJS 3.X API 第四章 数据绑定(1) 文本及样式绑定
    KnockoutJS 3.X API 第三章 计算监控属性(5) 参考手册
    KnockoutJS 3.X API 第三章 计算监控属性(4)Pure computed observables
    KnockoutJS 3.X API 第三章 计算监控属性(3) KO如何实现依赖追踪
  • 原文地址:https://www.cnblogs.com/51api/p/12297420.html
Copyright © 2011-2022 走看看