公司开发了一个订单小程序。需要对接物流。查询发货的快递单号。得到物流信息。展示给各地的项目经理。奈何刚接触微信小程序有很多东西都不会。就先用andorid把快递鸟的接口对了一下。非常的容易。首先登录快递鸟的官网注册一个账号。得到一个
EBusinessID="" ApiKey=""
这两个参数登录以后就可以看到。在下面的代码地方改一下。订单号我随便传了一个我公司的订单。安能快递的订单:
ShipperCode是快递公司的代码。LogisticCode是运单号。快递鸟官网有
快递鸟现在支持的快递也很多。本来是非常方便的。一次对接。哪里都能用。但是查询顺丰快递的时候需要传递发货方或者收货方的末尾4位电话号码。并且是必填项。这就很操蛋了。识别出单号容易。可是识别出电话号码后四位很难呀。本来想的是让发快递的同事手动去填。后来觉得这样太娄了。最后我又单独去顺丰官网对接了顺丰的api接口。把传递电话号码后四位这个问题解决了。后期的时候。我在附上顺丰的对接流程。总之对接了4天才对接完。时间都是浪费在小程序上的。java上基本是分分钟解决的。将以下代码复制过去调用即可。此处只需要注意那个 RequestData 组装的参数非常微妙。改动以后md5就出问题了。后期直接把ShipperCode,LogisticCode的value值写一个固定的字符串。用replace方法去替换快递公司和运单号即可。不要动那个字符串。否则会md5校验失败的。
package meiaomie.com.invoicing.utils;
import android.util.Log;
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.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.security.MessageDigest;
import Decoder.BASE64Encoder;
/**
* 即时查询接口
* 此接口用于向快递公司实时查询物流轨迹信息。该功能支持情况需查看技术文档。
* 正式地址:https://api.kdniao.com/Ebusiness/EbusinessOrderHandle.aspx
*
*
* 系统级参数
* RequestData String R 请求内容为JSON格式 详情可参考接口技术文档:https://www.kdniao.com/documents
* EBusinessID String R 用户ID
* RequestType String R 请求接口指令
* DataSign String R 数据内容签名,加密方法为:把(请求内容(未编码)+ApiKey)进行MD5加密--32位小写,然后Base64编码,最后进行URL(utf-8)编码
* DataType String R DataType=2,请求、返回数据类型均为JSON格式
* 应用级参数
* R-必填(Required),O-可选(Optional),C-报文中该参数在一定条件下可选(Conditional)
* OrderCode String(30) O 订单编号
* ShipperCode String(10) R 快递公司编码 详细编码参考《快递鸟接口支持快递公司编码.xlsx》 https://www.kdniao.com/documents
* LogisticCode String(30) R 快递单号
* CustomerName String(50) C ShipperCode为SF时必填,对应寄件人/收件人手机号后四位;ShipperCode为其他快递时,可不填或保留字段,不可传值
* 请求示例
* ZTO请求示例:
* {
* "OrderCode": "",
* "ShipperCode": "ZTO",
* "LogisticCode": "638650888018",
* }
*
* JD请求示例:
* {
* "OrderCode": "",
* "CustomerName": "",
* "ShipperCode": "JD",
* "LogisticCode": "JDVA00003618100",
* }
*
* SF请求示例:
* {
* "OrderCode": "",
* "CustomerName": "1234",
* "ShipperCode": "SF",
* "LogisticCode": "SF00003618100",
* }
*/
public class KdApiSearchDemo {
private String EBusinessID="";//即用户ID,
private String ApiKey="";//即API key,登录快递鸟官网https://www.kdniao.com/UserCenter/v4/UserHome.aspx
//请求url, 正式环境地址
private String ReqURL="https://api.kdniao.com/Ebusiness/EbusinessOrderHandle.aspx";
public static void main() {
try {
KdApiSearchDemo api = new KdApiSearchDemo();
api.orderOnlineByJson();
} catch (Exception e) {
e.printStackTrace();
}
}
Map<String,String> params = new HashMap<String,String>();
String result="";
//即时查询接口
public String orderOnlineByJson() throws Exception{
// 组装应用级参数
String RequestData= "{"+
"'CustomerName':'',"+
"'OrderCode':'',"+
"'ShipperCode':'ANE',"+
"'LogisticCode':'300471491371'"+
"}";
// 组装系统级参数
params.put("RequestData", urlEncoder(RequestData, "UTF-8"));
params.put("EBusinessID", EBusinessID);
params.put("RequestType", "1002");//免费即时查询接口指令1002/在途监控即时查询接口指令8001/地图版即时查询接口指令8003
String dataSign=encrypt(RequestData, ApiKey, "UTF-8");
Log.e("dataSign", dataSign );
params.put("DataSign", urlEncoder(dataSign, "UTF-8"));
params.put("DataType", "2");
// 以form表单形式提交post请求,post请求体中包含了应用级参数和系统级参数
Thread thread=new Thread(new Runnable() {
@Override
public void run() {
result=sendPost(ReqURL, params);
}
});
thread.start();
//根据公司业务处理返回的信息......
return result;
}
/**
* MD5加密
* str 内容
* 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));
}
Log.e("md5", sb.toString().toLowerCase());
return sb.toString().toLowerCase();
}
public static String MD5Encode(String str) {
MessageDigest messageDigest = null;
try {
messageDigest = MessageDigest.getInstance("MD5");
messageDigest.reset();
messageDigest.update(str.getBytes("UTF-8"));
} catch (NoSuchAlgorithmException e) {
System.out.println("NoSuchAlgorithmException caught!");
System.exit(-1);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
byte[] byteArray = messageDigest.digest();
StringBuffer md5StrBuff = new StringBuffer();
for (int i = 0; i < byteArray.length; i++) {
if (Integer.toHexString(0xFF & byteArray[i]).length() == 1)
md5StrBuff.append("0").append(Integer.toHexString(0xFF & byteArray[i]));
else
md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i]));
}
Log.e("md5", md5StrBuff.toString().toLowerCase());
return md5StrBuff.toString();
}
public static String MD5(String str) throws NoSuchAlgorithmException {
Log.e("key", str );
String encode = str;
StringBuilder stringbuilder = new StringBuilder();
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(encode.getBytes());
byte[] str_encoded = md5.digest();
for (int i = 0; i < str_encoded.length; i++) {
if ((str_encoded[i] & 0xff) < 0x10) {
stringbuilder.append("0");
}
stringbuilder.append(Long.toString(str_encoded[i] & 0xff, 16));
}
return stringbuilder.toString();
}
/**
* base64编码
* str 内容
* charset 编码方式
* @throws UnsupportedEncodingException
*/
private String base64(String str, String charset) throws UnsupportedEncodingException{
String encoded = new BASE64Encoder().encode(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签名生成
* content 内容
* keyValue ApiKey
* charset 编码方式
* @throws UnsupportedEncodingException ,Exception
* @return DataSign签名
*/
@SuppressWarnings("unused")
private String encrypt (String content,String keyValue,String charset) throws UnsupportedEncodingException, Exception
{
if (keyValue != null)
{
Log.e("md5", base64(MD5(content + keyValue), charset));
return base64(MD5(content + keyValue), charset);
}
return base64(MD5(content + keyValue), charset);
}
/**
* 向指定 URL 发送POST方法的请求
* url 发送请求的 URL
* 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();
}
}
Log.e( "main: ",result.toString());
return result.toString();
}
}
//在android界面随便写一个button,点击执行这个方法就可以查到快递接口了
KdApiSearchDemo demo=new KdApiSearchDemo();
demo.main();
可以先测试下。下一篇准备写微信小程序对接的过程。