我刚开始弄这个的时候,发现网上的文档不是很多,所以就想兄弟们少走点弯路,废话不多说,先上代码开箱即用
package com.ruoyi.system.test;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.system.test.domain.OrderInfo;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.time.LocalDateTime;
import java.time.OffsetTime;
import java.time.format.DateTimeFormatter;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import static java.nio.charset.StandardCharsets.UTF_8;
public class JdSdkUtil {
private static final String HEX_CHARACTERS = "0123456789ABCDEF";
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
/**
* 发送 HTTP 请求
*
* @param baseUri 基础 URI
* @param appKey 应用密钥
* @param appSecret 应用密钥的密码
* @param accessToken 访问令牌
* @param domain 域名
* @param path 路径
* @param method 方法(GET/POST)
* @param algorithm 签名算法
* @param requestBody 请求体
* @return 响应字符串
* @throws GeneralSecurityException 加密异常
* @throws IOException IO 异常
*/
public static String sendHttpRequest(String baseUri, String appKey, String appSecret, String accessToken, String domain, String path, String method, String algorithm, String requestBody) throws GeneralSecurityException, IOException {
String uri = baseUri + path;
String timestamp = DATE_TIME_FORMATTER.format(LocalDateTime.now());
String content = buildContent(appSecret, accessToken, appKey, path, requestBody, timestamp);
String sign = sign(algorithm, content.getBytes(UTF_8), appSecret.getBytes(UTF_8));
Map<String, String> query = new HashMap<>();
query.put("LOP-DN", domain);
query.put("access_token", accessToken);
query.put("app_key", appKey);
query.put("timestamp", timestamp);
query.put("v", "2.0");
query.put("sign", sign);
query.put("algorithm", algorithm);
URL url = new URL(uri + "?" + httpBuildQuery(query));
int offset = OffsetTime.now().getOffset().getTotalSeconds() / 3600;
Map<String, String> headers = new HashMap<>();
headers.put("lop-tz", String.valueOf(offset));
headers.put("User-Agent", "lop-http/java");
headers.put("content-type", "application/json;charset=utf-8");
HttpURLConnection connection = null;
try {
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod(method);
connection.setDoInput(true);
connection.setDoOutput(true);
for (Map.Entry<String, String> header : headers.entrySet()) {
connection.setRequestProperty(header.getKey(), header.getValue());
}
try (OutputStream outputStream = connection.getOutputStream()) {
outputStream.write(requestBody.getBytes(UTF_8));
}
try (InputStream inputStream = connection.getInputStream()) {
return new String(readAllBytes(inputStream), UTF_8);
} catch (IOException e) {
try (InputStream errorStream = connection.getErrorStream()) {
return new String(readAllBytes(errorStream), UTF_8);
}
}
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
static String buildContent(String appSecret, String accessToken, String appKey, String path, String requestBody, String timestamp) {
return String.join("", new String[]{
appSecret,
"access_token", accessToken,
"app_key", appKey,
"method", path,
"param_json", requestBody,
"timestamp", timestamp,
"v", "2.0",
appSecret
});
}
private static String sign(String algorithm, byte[] data, byte[] secret) throws GeneralSecurityException {
if ("md5-salt".equals(algorithm)) {
return bytesToHex(MessageDigest.getInstance("md5").digest(data));
} else if ("HMacMD5".equals(algorithm)) {
Mac mac = Mac.getInstance(algorithm);
mac.init(new SecretKeySpec(secret, algorithm));
return Base64.getEncoder().encodeToString(mac.doFinal(data));
} else if ("HMacSHA1".equals(algorithm)) {
Mac mac = Mac.getInstance(algorithm);
mac.init(new SecretKeySpec(secret, algorithm));
return Base64.getEncoder().encodeToString(mac.doFinal(data));
} else if ("HMacSHA256".equals(algorithm)) {
Mac mac = Mac.getInstance(algorithm);
mac.init(new SecretKeySpec(secret, algorithm));
return Base64.getEncoder().encodeToString(mac.doFinal(data));
} else if ("HMacSHA512".equals(algorithm)) {
Mac mac = Mac.getInstance(algorithm);
mac.init(new SecretKeySpec(secret, algorithm));
return Base64.getEncoder().encodeToString(mac.doFinal(data));
}
throw new GeneralSecurityException("Algorithm " + algorithm + " not supported yet");
}
private static String bytesToHex(byte[] bytes) {
StringBuilder stringBuilder = new StringBuilder(bytes.length * 2);
for (byte b : bytes) {
stringBuilder.append(HEX_CHARACTERS.charAt((b >>> 4) & 0x0F));
stringBuilder.append(HEX_CHARACTERS.charAt(b & 0x0F));
}
return stringBuilder.toString();
}
private static String httpBuildQuery(Map<String, String> query) throws UnsupportedEncodingException {
StringBuilder stringBuilder = new StringBuilder();
boolean first = true;
for (Map.Entry<String, String> entry : query.entrySet()) {
if (!first) {
stringBuilder.append("&");
} else {
first = false;
}
stringBuilder.append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue(), UTF_8.name()));
}
return stringBuilder.toString();
}
private static byte[] readAllBytes(InputStream inputStream) throws IOException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int n;
while ((n = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, n);
}
return outputStream.toByteArray();
}
public static String objectToJson(OrderInfo orderInfo) throws IOException {
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(orderInfo);
}
public static void main(String[] args) throws GeneralSecurityException, IOException {
String baseUri = "https://api.jdl.com";
String appKey = "11111111111111111111";
String appSecret = "111111111111111111111111111111";
String accessToken = "111111111111111111111111";
String domain = "ECAP";
String path = "/ecap/v1/orders/create";
String method = "POST";
String algorithm = "md5-salt";
OrderInfo orderInfo = new OrderInfo();
// String s = objectToJson(orderInfo);
String body = "[\n {\n \"orderId\": \"1233211234567\",\n \"senderContact\": {\n \"name\": \"用户名称(测试)\"," +
"\n \"phone\": \"19128200000\",\n \"fullAddress\": \"广东省广州市黄埔区南岗街道康南路33号京东\"\n }," +
"\n \"receiverContact\": {\n \"name\": \"到付转\",\n \"phone\": \"18696000000\",\n \"fullAddress\": \"广东省广州市黄埔区萝岗街道开创大道星际云汇\"\n }," +
"\n \"orderOrigin\": 1,\n \"customerCode\": \"020K1637506\",\n \"productsReq\": {\n \"productCode\": \"ed-m-0002\"\n },\n \"settleType\": 3," +
"\n \"cargoes\": [\n {\n \"name\": \"手机\",\n \"quantity\": 1,\n \"weight\": 1,\n \"volume\": 1\n }\n ]," +
"\n \"goods\": [\n {\n \"name\": \"苹果手机15\",\n \"code\": \"csclq2024\",\n \"quantity\": 1," +
"\n \"serialNos\": [\n ]\n }\n ],\n \"remark\": \"测试运单,无需揽收\"\n }\n]";
String response = sendHttpRequest(baseUri, appKey, appSecret, accessToken, domain, path, method, algorithm, body);
System.out.println(response);
}
}
这里的东西还是蛮多的,我基本上都封装好了,但是东西实在太多了,再加上要解释,因为我本身是以为耐心比较差的人,我觉得肯定有一些和我一样的,所以我就先把代码贴上去,要看解释的可以继续往下翻
先给大家介绍一个很简单的,我也是利用这个封装的,点击常用开发工具,选择自己使用的产品和语言,输入参数,生成代码
这个是我封装好的配合上面的使用(注意:这里我封装好的只是给大家借鉴,并不是直接能用,只有上面的代码可以直接用)
package com.ruoyi.system.service.impl;
import com.ruoyi.system.domain.SysConfig;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.test.domain.CancelOrder;
import com.ruoyi.system.test.domain.OrderInfo;
import com.ruoyi.system.test.domain.QueryOrderStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.security.GeneralSecurityException;
import static com.ruoyi.system.test.JdSdkUtil.sendHttpRequest;
import static com.ruoyi.system.util.OrderUtli.objectToJson;
@Service
public class JdExpressService {
//基础 URI
public static String BASE_URI = "https://api.jdl.com";
//下单
public static String PATH_1 = "/ecap/v1/orders/create";
//取消
public static String PATH_2 = "/ecap/v1/orders/cancel";
//查询
public static String PATH_3 = "/ecap/v1/orders/status/get";
public static String METHOD_POST = "POST";
public static String DOMAIN = "ECAP";
public static String ALGORITHM = "md5-salt";
@Autowired
private ISysConfigService configService;
/**
* 京东下单
*
* @param baseUri 基础 URI
* @param appKey 应用密钥
* @param appSecret 应用密钥的密码
* @param accessToken 访问令牌
* @param domain 域名
* @param path 路径
* @param algorithm 签名算法
* @param requestBody 请求体
* @return 响应字符串
* @throws GeneralSecurityException 加密异常
* @throws IOException IO 异常
*/
public String PlaceAnOrder(OrderInfo requestBody) throws GeneralSecurityException, IOException {
String body = objectToJson(requestBody);
String b = "["+ body +"]";
String response = sendHttpRequest(BASE_URI, getVal(102L), getVal(103L), getVal(104L), DOMAIN, PATH_1, METHOD_POST, ALGORITHM, b);
System.out.println(response);
return response;
}
/**
* 查询订单状态
* @param requestBody
* @return
* @throws IOException
* @throws GeneralSecurityException
*/
public String QueryOrderStatus(QueryOrderStatus requestBody) throws IOException, GeneralSecurityException {
String body = objectToJson(requestBody);
String b = "["+ body +"]";
String response = sendHttpRequest(BASE_URI, getVal(102L), getVal(103L), getVal(104L), DOMAIN, PATH_3, METHOD_POST, ALGORITHM, b);
System.out.println(response);
return response;
}
/**
* 取消订单
* @param requestBody
* @return
* @throws IOException
* @throws GeneralSecurityException
*/
public String CancelOrder(CancelOrder requestBody) throws IOException, GeneralSecurityException {
String body = objectToJson(requestBody);
String b = "["+ body +"]";
String response = sendHttpRequest(BASE_URI, getVal(102L), getVal(103L), getVal(104L), DOMAIN, PATH_2, METHOD_POST, ALGORITHM, b);
System.out.println(response);
return response;
}
public String getVal(Long Id){
SysConfig sysConfig = configService.selectConfigById(Id);
return sysConfig.getConfigValue();
}
}
聪明的小伙伴就看见了,我们其实只换了参数,对应产品调用路径
那么我们来介绍参数
1:每个方法接收的实体类(这个不是我不提供实在太多了,只能辛苦大家自己到开放平台在api文档里面吧参数写进去了)
2:每个方法中的 body 我们把实体类转换为json数据传进去objectToJson这个方法在最上面的代码提供了
3:然后就是sendHttpRequest方法中的参数了其实在最上面的代码里面解释了以及这个代码里面的static
4:其次大家就想问了为什么 body要用[]包裹起来(可以看见官方的要求就是这样的)
备注:其实就下单的参数比较多,其他的都没多少