开发者对接文档
**平台入驻:**
1.使用米合的管理员账户,可以在米合开放平台获取开发对接的应用。包括开放平台的clientId与clientSecret,accessToken。accessToken基于oauth2.0颁布,具有一定的使用时效,过期后需要重新获取。用户可以通过第3步的步骤,使用接口调用获取,也可以在开放平台的控制台的***刷新token***按钮进行刷新操作。附米合开放平台地址:[米合开放平台](http://openapi.ruwii.com/api/system)
2.已经获取到上述clientId与clientSecret后,用户可以获取到访问资源服务器的 accessToken,accessToken有一定的有效期,过期后需要重新调用接口获取新的accessToken。接口地址:https://easydoc.net/doc/46112299/BtJWN82i/7A0WVwrx
**开发流程:**
1.使用米合的管理员账户登录[米合开放平台](http://openapi.ruwii.com/api/system)
2.选择控制台,首次登录用户选择创建应用,已经申请过的用户直接可以看到应用信息。每个企业只能申请一个应用。
3.根据第二步拿到的应用Id,应用secret和accessToken,即可调用米合开放平台接口
4.接口调用成功,即返回业务数据,后续按需使用即可。
**API调用文档:**
1.Get请求可以在url拼接参数,==注意:入参包含:[]{}等特殊符号,需要转义后传输,否则无法获取返回。==
2.签名的非字符串参数,在计算签名的时候需要转为字符串加签。以下单接口为例,入参包含ConsigneeInfo对象,需要将ConsigneeInfo的值转为字符串。
3.用户需要按照米合的协议规范拼装一个正确的URL,通过Http请求到米合即能够获取到所需数据。 主要流程包含:填写参数、生成签名、拼装HTTPS请求、发起请求、得到响应结果、解析结果。
4.公共参数
|参数名|必选|类型|说明|
|:---- |:---|:----- |----- |
|accessToken |是 |String | 采用OAuth授权方式获取的accessToken授权码 |
|clientId |是 |String |API应用的clientId |
|sign |是 |String | 签名(算法请看下面的签名详解) |
|timestamp |是 |Long|时间戳,毫秒 |
|v |是 |String | 开放平台的API版本,目前是2.0 |
5.签名算法
为了防止API在调用过程中被恶意者拦截随意篡改,调用API是需要传入签名参数,服务端会根据请求参数对签名进行验证,判断请求参数是否合法。签名规则过程如下:
将所有请求参数(包括公共参数和业务参数)按照字母先后顺序排列,例如:accessToken,clientId,timestamp,v ,这些参数
排序为accessToken,clientId,timestamp,v
把所有参数名和参数值进行拼接,例如(x代表参数的值): accessTokenxxxclientIdxxxtimestampxxxxxxvx
把clientSecret夹在字符串(上一步拼接串)的两端,例如:clientSecret+XXXX+clientSecret
使用MD5进行加密,再转化成大写,即为签名sign。
**签名算法的Java代码实现:**
```java
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import com.alibaba.fastjson.JSON;
public class SignUtil {
public static void main(String[] args) {
String clientId = "通过开放平台获取的clientId";
String clientSecret = "通过开放平台获取的clientSecret";
String accessToken = "通过开放平台授权获取到的accessToken";
//以工具API,获取获取市级列表为例
String v = "2.0";
Long timestamp = System.currentTimeMillis();
//公共参数
Map<String, Object> params = new HashMap<>();
params.put("clientId", clientId);
params.put("accessToken", accessToken);
params.put("timestamp", timestamp.toString());
params.put("v", v);
//业务参数
params.put("provinceCode", 210000);
String buildSign = buildSign(clientSecret, params);
System.out.println("签名为:" + buildSign);
}
//生成签名
public static String buildSign(String clientSecret, Map<String, Object> params) {
// 生成待签字串 和 sign
String preStrNew = buildSignString(params);
String preStrNew_md5Key = clientSecret+ preStrNew + clientSecret;
System.out.println("生成待签字串为:" + preStrNew_md5Key);
String sign = DigestUtils.md5Hex(getContentBytes(preStrNew_md5Key)).toUpperCase();
// 返回结果
return sign;
}
// 构建签名字符串
public static String buildSignString(Map<String, Object> params) {
if (params == null || params.size() == 0) {
return "";
}
List<String> keys = new ArrayList<>(params.size());
for (Entry<String, Object> entry : params.entrySet()) {
if ("sign".equals(entry.getKey()))
continue;
if (StringUtils.isEmpty(entry.getValue() instanceof String? entry.getValue().toString(): JSON.toJSONString(entry.getValue())))
continue;
keys.add(entry.getKey());
}
// 字段排序
Collections.sort(keys);
StringBuilder buf = new StringBuilder();
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
String value = params.get(key) instanceof String? params.get(key).toString(): JSON.toJSONString(params.get(key));
buf.append(key + value);
}
return buf.toString();
}
// 根据编码类型获得签名内容byte[]
public static byte[] getContentBytes(String content) {
try {
return content.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("签名过程中出现错误");
}
}
}
```
6.接口HTTP请求的Java示例代码
本请求示例整合了签名算法,以HttpClient为基础调用接口的示例。
```java
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import com.alibaba.fastjson.JSON;
public class HttpRequestDemo {
public static void main(String[] args) {
String url = "https://openapi.ruwii.com/api/logistics/cityGet";
String clientId = "10000001";
String clientSecret = "GL2zo1DtpRPHrsQu1uEnG4kul6Thh0ZZ";
String accessToken = "f0fdc75c-4a12-4cba-879f-c037906faf8d";
String v = "2.0";
Long timestamp = System.currentTimeMillis();
// 公共参数
Map<String, Object> params = new HashMap<>();
params.put("clientId", clientId);
params.put("accessToken", accessToken);
params.put("timestamp", timestamp.toString());
params.put("v", v);
// 业务参数
params.put("provinceCode", 210000);
//计算签名
String sign = buildSign(clientSecret, params);
System.out.println("签名为:" + sign);
params.put("sign", sign);
StringBuffer paramStringBuffer = new StringBuffer("");
for (Map.Entry<String, Object> m : params.entrySet()) {
paramStringBuffer.append(m.getKey()).append("=").append(m.getValue()).append("&");
}
paramStringBuffer = paramStringBuffer.deleteCharAt(paramStringBuffer.length() - 1);
String paramString = paramStringBuffer.toString();
String result = doGet(url,paramString);
System.out.println("接口返回结果:" + result);
}
// 生成签名
public static String buildSign(String clientSecret, Map<String, Object> params) {
// 生成待签字串 和 sign
String preStrNew = buildSignString(params);
String preStrNew_md5Key = clientSecret + preStrNew + clientSecret;
System.out.println("生成待签字串为:" + preStrNew_md5Key);
String sign = DigestUtils.md5Hex(getContentBytes(preStrNew_md5Key)).toUpperCase();
// 返回结果
return sign;
}
// 构建签名字符串
public static String buildSignString(Map<String, Object> params) {
if (params == null || params.size() == 0) {
return "";
}
List<String> keys = new ArrayList<>(params.size());
for (Entry<String, Object> entry : params.entrySet()) {
if ("sign".equals(entry.getKey()))
continue;
if (StringUtils.isEmpty(entry.getValue() instanceof String ? entry.getValue().toString()
: JSON.toJSONString(entry.getValue())))
continue;
keys.add(entry.getKey());
}
// 字段排序
Collections.sort(keys);
StringBuilder buf = new StringBuilder();
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
String value = params.get(key) instanceof String ? params.get(key).toString()
: JSON.toJSONString(params.get(key));
buf.append(key + value);
}
return buf.toString();
}
// 根据编码类型获得签名内容byte[]
public static byte[] getContentBytes(String content) {
try {
return content.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("签名过程中出现错误");
}
}
public static String doGet(String url, String paramString) {
try {
String openapiUrl = url + "?" + paramString;
System.out.println(openapiUrl);
// 建立连接请求
CloseableHttpClient httpClient = HttpClients.createDefault();
// 创建get请求
HttpGet httpGet = new HttpGet(openapiUrl);
// 设置请求超时时间
RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(1000)
.setSocketTimeout(2000).setConnectTimeout(1000).build();
httpGet.setConfig(requestConfig);
// 发送请求
CloseableHttpResponse response = httpClient.execute(httpGet);
HttpEntity entity = response.getEntity();
if (entity != null) {
String responseString = EntityUtils.toString(entity, "UTF-8");
return responseString;
}
// 资源释放
response.close();
httpClient.close();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
```
7.沙箱
详情请参见:https://easydoc.net/doc/46112299/BtJWN82i/k5qP7Hpd