圆通接口调用java_圆通对接文档

使用Java调用圆通接口进行运单报文和订单创建
这篇博客演示了如何使用Java调用圆通的API进行运单报文的封装和订单创建。首先,展示了如何构建运单报文并进行AES加密,然后利用Hutool库的HTTP工具发送POST请求到圆通接口。接着,展示了订单创建的过程,包括构造XML请求数据、MD5签名和Base64编码。整个过程详细地解释了所需参数和加密解密步骤。

package com.eureka.provider;

import java.io.UnsupportedEncodingException;

import java.net.URLEncoder;

import java.util.ArrayList;

import java.util.Arrays;

import java.util.Date;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import org.junit.jupiter.api.Test;

import org.springframework.boot.test.context.SpringBootTest;

import cn.hutool.core.codec.Base64;

import cn.hutool.core.lang.Console;

import cn.hutool.core.lang.UUID;

import cn.hutool.core.util.XmlUtil;

import cn.hutool.crypto.SecureUtil;

import cn.hutool.http.HttpRequest;

import cn.hutool.json.JSONUtil;

@SpringBootTest

public class ProviderApplicationTests {

@Test

void contextLoads() {

}

public static void main(String[] args) {

orderCreate();

// waybillDeclare();

}

public static void waybillDeclare() {

String CHANNEL_CODE = "CN037102";

String CLIENT_KEY = "YT00160001";

String AESKEY = "w4tb3o5aTT9npey7ZGC9TvCdMKA8DiQtDGo145eE77n";

String URL = "http://customs.yto.net.cn/api/waybill/declare/test/1210/message";

// 1. 封装运单报文:跟实际运单情况填写

HashMap waybillMessage = new HashMap();

waybillMessage.put("appType", null);

waybillMessage.put("logisticsCode", null);

waybillMessage.put("logisticsName", null);

waybillMessage.put("logisticsNo", null);

waybillMessage.put("billNo", null);

waybillMessage.put("orderNo", null);

waybillMessage.put("freight", null);

waybillMessage.put("insuredFee", null);

waybillMessage.put("currency", null);

waybillMessage.put("weight", null);

waybillMessage.put("packNo", 1);

waybillMessage.put("goodsInfo", null);

waybillMessage.put("consignee", null);

waybillMessage.put("consigneeAddress", null);

waybillMessage.put("consigneeTelephone", null);

waybillMessage.put("note", null);

HashMap extra = new HashMap();

extra.put("voyageNo", null);

extra.put("ieType", null);

extra.put("tradeMode", null);

extra.put("netWeight", null);

extra.put("shipper", null);

extra.put("shipperAddress", null);

extra.put("shipperTelephone", null);

extra.put("shipperCountry", null);

extra.put("consigneeCountry", null);

extra.put("buyerIdType", 1);

extra.put("buyerIdNumber", null);

extra.put("trasfNo", null);

extra.put("ebpCode", null);

extra.put("ebpName", null);

extra.put("currencyCiq", 156);

extra.put("note", null);

waybillMessage.put("extra", extra);

// 3.封装请求参数

String encrypt = AesUtils.encrypt(JSONUtil.toJsonStr(waybillMessage), AESKEY);

// 生成随机数

String nonce = UUID.randomUUID().toString().toUpperCase();

Date date = new Date();

// 获取签名信息

String[] array = new String[] { CLIENT_KEY, CHANNEL_CODE, String.valueOf(date.getTime()), nonce, encrypt };

StringBuilder sb = new StringBuilder();

// 字符串排序

Arrays.sort(array);

for (int i = 0; i < 5; i++) {

sb.append(array[i]);

}

HashMap message = new HashMap();

message.put("clientKey", CLIENT_KEY);

message.put("ChannelCode", CHANNEL_CODE);

message.put("timestamp", date);

message.put("nonce", nonce);

message.put("data", encrypt);

message.put("signature", SecureUtil.sha1(sb.toString()));

String jsonStr = JSONUtil.toJsonStr(message);

String body = HttpRequest.post(URL).contentType("application/json").body(jsonStr, "application/json")

.timeout(20000)// 超时,毫秒

.execute().body();

Console.log("接口返回数据:{}", body);

}

public static void orderCreate() {

Map data = new HashMap();

data.put("clientID", "K21000119");

data.put("logisticProviderID", "YTO");

data.put("customerId", "K21000119");

data.put("txLogisticID", "WP151831179108113");

data.put("tradeNo", "1");

data.put("totalServiceFee", "1");

data.put("codSplitFee", "1");

data.put("orderType", "1");

data.put("serviceType", "1");

data.put("flag", "1");

Map sender = new HashMap();

sender.put("name", "发件人姓名");

sender.put("phone", "021-12345678");

sender.put("prov", "上海");

sender.put("city", "上海市,青浦区");

sender.put("address", "华徐公路3029弄28号");

data.put("sender", sender);

Map receiver = new HashMap();

receiver.put("name", "收件人姓名");

receiver.put("phone", "18089666766");

receiver.put("prov", "上海");

receiver.put("city", "上海市,青浦区");

sender.put("address", "华徐公路3029弄28号");

data.put("receiver", receiver);

data.put("sendStartTime", "2015-12-12 12:12:12");

data.put("sendEndTime", "2015-12-12 12:12:12");

data.put("goodsValue", "1");

List> items = new ArrayList>();

Map itemDt = new HashMap();

itemDt.put("itemName", "商品");

itemDt.put("number", "1");

itemDt.put("itemValue", "2");

Map item = new HashMap();

item.put("item", itemDt);

items.add(item);

data.put("items", items);

data.put("insuranceValue", 1);

data.put("special", 1);

data.put("remark", 1);

String logistics_interface = XmlUtil.mapToXmlStr(data, "RequestOrder")

.replace("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>", "");

Console.log("要发送的xml内容: [{}]", logistics_interface);

String partnerId = "123456";

String url = "http://opentestapi.yto.net.cn/service/e_order_create/v1/BAHrhW";

try {

Map paramMap = new HashMap();

paramMap.put("logistics_interface", URLEncoder.encode(logistics_interface, "utf-8"));

paramMap.put("data_digest",

URLEncoder.encode(Base64.encode(SecureUtil.md5(logistics_interface + partnerId)), "utf-8"));

paramMap.put("clientId", URLEncoder.encode("K21000119", "utf-8"));

paramMap.put("type", URLEncoder.encode("offline", "utf-8"));

System.out.println(paramMap);

String body = HttpRequest.post(url)//

.form(paramMap)// 表单内容

.timeout(20000)// 超时,毫秒

.execute().body();

Map xmlToMap = XmlUtil.xmlToMap(body);

Console.log("接口返回数据:{}", xmlToMap);

} catch (UnsupportedEncodingException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

package com.eureka.provider;

import java.nio.charset.Charset;

import java.util.ArrayList;

import java.util.Arrays;

import javax.crypto.Cipher;

import javax.crypto.spec.IvParameterSpec;

import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.lang.CharEncoding;

import org.apache.commons.lang.RandomStringUtils;

import org.springframework.util.Base64Utils;

/**

* 前后端数据传输加密工具类

*

* @author monkey

*

*/

public class AesUtils {

private static final Charset CHARSET = Charset.forName(CharEncoding.UTF_8);

/**

* 加密

*

* @param content 加密的字符串

* @param encryptKey key值

* @return

* @throws Exception

*/

public static String encrypt(String text, String aesKey) {

ByteGroup byteCollector = new ByteGroup();

byte[] randomStrBytes = RandomStringUtils.randomAlphanumeric(16).getBytes(CHARSET);

byte[] textBytes = text.getBytes(CHARSET);

byte[] networkBytesOrder = getNetworkBytesOrder(textBytes.length);

// randomStr + networkBytesOrder + text

byteCollector.addBytes(randomStrBytes);

byteCollector.addBytes(networkBytesOrder);

byteCollector.addBytes(textBytes);

// ... + pad: 使用自定义的填充方式对明文进行补位填充

byte[] padBytes = encode(byteCollector.size());

byteCollector.addBytes(padBytes);

// 获得最终的字节流, 未加密

byte[] unencrypted = byteCollector.toBytes();

return aesCbc(unencrypted,Base64Utils.decodeFromString(aesKey + "="));

}

private static String aesCbc(byte[] unencrypted, byte[] aesKey) {

try {

// 设置加密模式为AES的CBC模式

Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");

SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");

IvParameterSpec iv = new IvParameterSpec(aesKey, 0, 16);

cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);

// 加密

byte[] encrypted = cipher.doFinal(unencrypted);

// 使用BASE64对加密后的字符串进行编码

return Base64Utils.encodeToString(encrypted);

} catch (Exception e) {

return "";

}

}

// 生成4个字节的网络字节序

static byte[] getNetworkBytesOrder(int sourceNumber) {

byte[] orderBytes = new byte[4];

orderBytes[3] = (byte) (sourceNumber & 0xFF);

orderBytes[2] = (byte) (sourceNumber >> 8 & 0xFF);

orderBytes[1] = (byte) (sourceNumber >> 16 & 0xFF);

orderBytes[0] = (byte) (sourceNumber >> 24 & 0xFF);

return orderBytes;

}

// 还原4个字节的网络字节序

private static int recoverNetworkBytesOrder(byte[] orderBytes) {

int sourceNumber = 0;

for (int i = 0; i < 4; i++) {

sourceNumber <<= 8;

sourceNumber |= orderBytes[i] & 0xff;

}

return sourceNumber;

}

/**

* 解密

*

* @param encryptStr 解密的字符串

* @param decryptKey 解密的key值

* @return

* @throws Exception

*/

public static String decrypt(String encryptedMsg, String aesKey) {

try {

if (aesKey.length() != 43) {

return "";

}

byte[] decodeFromString = Base64Utils.decodeFromString(aesKey + "=");

byte[] original;

try {

// 设置解密模式为AES的CBC模式

Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");

SecretKeySpec keySpec = new SecretKeySpec(decodeFromString, "AES");

IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(decodeFromString, 0, 16));

cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);

// 使用BASE64对密文进行解码

byte[] encrypted = Base64Utils.decodeFromString(encryptedMsg);

// 解密

original = cipher.doFinal(encrypted);

} catch (Exception e) {

return "";

}

String xmlContent;

try {

// 去除补位字符

byte[] bytes = decode(original);

// 分离16位随机字符串,网络字节序

byte[] networkOrder = Arrays.copyOfRange(bytes, 16, 20);

int xmlLength = recoverNetworkBytesOrder(networkOrder);

xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET);

} catch (Exception e) {

return "";

}

return xmlContent;

} catch (Exception e) {

return "";

}

}

private static final int ZERO = 0;

private static final int BLOCK_SIZE = 32;

/**

* 获得对明文进行补位填充的字节.

*

* @param count 需要进行填充补位操作的明文字节个数

* @return 补齐用的字节数组

*/

static byte[] encode(int count) {

// 计算需要填充的位数

int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);

if (amountToPad == 0) {

amountToPad = BLOCK_SIZE;

}

// 获得补位所用的字符

char padChr = chr(amountToPad);

String tmp = new String();

for (int index = 0; index < amountToPad; index++) {

tmp += padChr;

}

return tmp.getBytes(CHARSET);

}

/**

* 删除解密后明文的补位字符

*

* @param decrypted 解密后的明文

* @return 删除补位字符后的明文

*/

static byte[] decode(byte[] decrypted) {

int pad = (int) decrypted[decrypted.length - 1];

if (pad < 1 || pad > BLOCK_SIZE) {

pad = 0;

}

return Arrays.copyOfRange(decrypted, ZERO, decrypted.length - pad);

}

/**

* 将数字转化成ASCII码对应的字符,用于对明文进行补码

*

* @param a 需要转化的数字

* @return 转化得到的字符

*/

static char chr(int a) {

byte target = (byte) (a & 0xFF);

return (char) target;

}

}

class ByteGroup {

ArrayList byteContainer = new ArrayList();

byte[] toBytes() {

byte[] bytes = new byte[byteContainer.size()];

for (int i = 0; i < byteContainer.size(); i++) {

bytes[i] = byteContainer.get(i);

}

return bytes;

}

ByteGroup addBytes(byte[] bytes) {

for (byte b : bytes) {

byteContainer.add(b);

}

return this;

}

int size() {

return byteContainer.size();

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值