美文网首页
调用外部接口实现快递查询

调用外部接口实现快递查询

作者: 那就省略号吧 | 来源:发表于2018-12-20 23:00 被阅读0次

    前两天需要做一个快递查询的需求,由于也是第一次做,完全不懂,但是还是明白这必定是需要调用外部接口来实现,并且应该不是调用快递公司所给的接口,于是便上网查询了能够提供快递查询接口的公司.提供查询接口的公司我查询到的有5家,分别是:1).快递鸟,2).快递100,3).快递网,4).爱查快递,5).爱快递;通过分别阅读5家公司的api文档,快递鸟与快递100两家公司除快递查询之外,还提供了其他的服务接口,也更加完善,其余的三家只提供快递查询功能,且他们能查询的物流公司数量也有所不同.如果想在将来对自己产品的快递查询业务进行功能完善,个人推荐选择快递鸟和快递100,本人公司选择的是快递鸟(https://www.kdniao.com),所以就以快递鸟作为案例进行解说吧.

    注册快递鸟账号

    注册这里就不演示了,注册完成后登入,进入到个人中心,这里需要进行一个实名认证,按公司产品的类型进行一个选择,展示页面如图1,认证完成后在我的产品服务中选择自己所需要的服务,当然对于初创型公司来说选择免费版就够了,等到业务做大时再选择其他产品服务.还有就是在个人中心中如图2所示,我们需要记住的是用户ID,和API key(不要泄露),这将是我们进行接口调用时需要用到的, 图1.jpg 图2.jpg

    调用接口文档

    说完了上面的,接下来我们就开始调用API进行开发吧,打开首页中API文档,选择即时查询,我们可以看到它对改接口的介绍,我们来看看对于参数的说明,图3是在发送请求时所需的参数 图3.jpg 图4是进行接口请求时需要用的参数,这里需要说明下,每个所提供接口的公司他们对物流公司的编码都不同,可以下载他们提供的编码文档进行查询,避免出现错误,当然快递鸟也有提供根据物流单号查询智能查询快递公司以及编码,下面我会一起详细介绍 图4.jpg 图5是请求成功后返回的数据 图5.jpg 我们可以下载他们写好的分别是即时查询接口demo和单号识别接口demo进行更改,这里就不打开demo了,我直接讲解我修改后的,并且也不讲解前端代码,大家只要根据文档来进行数据传输就可以了.后端代码这里建议大家将以下数据抽取出来单独建一个类,方便以后信息修改:
    公共信息
    /*快递鸟查询快递信息*/
    public class ShoppingCricleLogisticKey {
        //电商ID
        public static final String EBusinessID="***";
        //电商加密私钥,快递鸟提供,注意保管,不要泄漏
        public static final String AppKey="*****";
        //根据单号和快递公司编码来查询物流信息接口
        public static final String ReqURL="http://api.kdniao.com/Ebusiness/EbusinessOrderHandle.aspx";
        //通过单号识别来查询快递公司接口
        public static final String OrderReqURL="http://api.kdniao.com/Ebusiness/EbusinessOrderHandle.aspx";
    }
    
    controller层
    @RestController
    @RequestMapping("/api/logistics")
    public class LogisticController {
        @Autowired
        private LogisticService logisticService;//及时查询
        @Autowired
        private OrderDistinguishService orderDistinguishService;//单号识别
    // String shipperCode//物流单号(必须),String logisticCode//快递公司编码(必须)
        @PostMapping("/findOne")
        public Object findOne(@RequestBody Map<String,Object> params){
            String shipperCode =String.valueOf(params.get("shipperCode"));
            String logisticCode =String.valueOf(params.get("logisticCode"));
            try {
                return JSON.parse(logisticService.getOrderTracesByJson(shipperCode,logisticCode));
    
            } catch (Exception e) {
                throw new ServiceException("未查到该单号信息,请确认单号信息是否准确");
            }
        }
        //根据快递单号查询快递公司以及快递公司编码
        @GetMapping("/findCompany/{logisticCode}")
        public Object findCompany(@PathVariable("logisticCode")String logisticCode){
            try {
                return JSON.parse(orderDistinguishService.getOrderTracesByJson(logisticCode));
            } catch (Exception e) {
                throw new ServiceException("未查到该单号信息,请确认单号信息是否准确");
            }
        }
    }
    

    由于即时查询接口demo和单号识别接口demo它们中的部分方法有所重复,故对它们重复的方法进行抽取,作为公共的方法:

    公共方法类
    public class LogisticsUntil {
        public 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();
        }
    
    
        public 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());
                    }
                    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();
        }
    
        public 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();
        }
    }
    
    service层
    @Service
    public class LogisticService {
        /**
         * Json方式 查询订单物流轨迹
         * @throws Exception
         */
        public String getOrderTracesByJson(String shipperCode, String logisticCode) throws Exception{
            String requestData= "{'OrderCode':'','ShipperCode':'" + shipperCode + "','LogisticCode':'" + logisticCode + "'}";
    
            Map<String, String> params = new HashMap<String, String>();
            params.put("RequestData", urlEncoder(requestData, "UTF-8"));
            params.put("EBusinessID", ShoppingCricleLogisticKey.EBusinessID);
            params.put("RequestType", "1002");
            String dataSign=encrypt(requestData, ShoppingCricleLogisticKey.AppKey, "UTF-8");
            params.put("DataSign", urlEncoder(dataSign, "UTF-8"));
            params.put("DataType", "2");
    
            String result=sendPost(ShoppingCricleLogisticKey.ReqURL, params);
    
            //根据公司业务处理返回的信息......
    
            return result;
        }
    
        /**
         * MD5加密
         * @param str 内容
         * @param charset 编码方式
         * @throws Exception
         */
        @SuppressWarnings("unused")
        private String MD5(String str, String charset) throws Exception {
            return LogisticsUntil.MD5(str,charset);
        }
    
        /**
         * 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")
        public String sendPost(String url, Map<String, String> params) {
            return LogisticsUntil.sendPost(url,params);
        }
    
        public static String base64Encode(byte[] data) {
            return LogisticsUntil.base64Encode(data);
        }
    }
    
    @Service
    public class OrderDistinguishService {
        public String getOrderTracesByJson(String expNo) throws Exception{
            String requestData= "{'LogisticCode':'" + expNo + "'}";
    
            Map<String, String> params = new HashMap<String, String>();
            params.put("RequestData", urlEncoder(requestData, "UTF-8"));
            params.put("EBusinessID", ShoppingCricleLogisticKey.EBusinessID);
            params.put("RequestType", "2002");
            String dataSign=encrypt(requestData, ShoppingCricleLogisticKey.AppKey, "UTF-8");
            params.put("DataSign", urlEncoder(dataSign, "UTF-8"));
            params.put("DataType", "2");
    
            String result=sendPost(ShoppingCricleLogisticKey.OrderReqURL, params);
    
            //根据公司业务处理返回的信息......
    
            return result;
        }
    
        /**
         * MD5加密
         * @param str 内容
         * @param charset 编码方式
         * @throws Exception
         */
        @SuppressWarnings("unused")
        private String MD5(String str, String charset) throws Exception {
          return LogisticsUntil.MD5(str,charset);
        }
    
        /**
         * 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) {
           return LogisticsUntil.sendPost(url,params);
        }
    
        public static String base64Encode(byte[] data) {
            return LogisticsUntil.base64Encode(data);
        }
    }
    
    

    这里测试返回的数据大家可以参考API所提供的数据,形式就跟我们在支付宝上查询的物流信息一样,美化的话就需要靠前端了,这里就不给大家展示了.

    相关文章

      网友评论

          本文标题:调用外部接口实现快递查询

          本文链接:https://www.haomeiwen.com/subject/qlnukqtx.html