开发指南
1. 开发规范
1.1 通讯规范
1.2安全规范
1.2.1 签名验签机制
1.2.1.1 报文结构
{
"clientSerialNo":"1661242378542",
"data":"eyJuYW1lIjogIuWwj+aYjiIsICJhZ2UiOiA4fQ==",
"encryptType":"BASE64",
"merchantNo":"123",
"signData":"326c67656b1c0093f93adb53eb352305",
"signType":"MD5",
"timestamp":1661242378542
}
参数 | 名称 | 是否必填 | 类型 | 长度 | 描述 |
---|---|---|---|---|---|
clientSerialNo | 请求流水号 | Y | String | 32 | 保证请求唯一 |
encryptType | 请求报文加密类型 | Y | String | 8 | 固定BASE64 |
merchantNo | 商户编号 | Y | String | 64 | 商户编号,由平台分配 |
signData | 报文签名 | Y | String | 详见下面签名方案 | |
signType | 签名方式 | Y | String | 8 | 固定MD5 |
timestamp | 时间戳 | Y | String | 格式:yyyyMMddHHmmss | |
data | 加密后的业务报文数据 | Y | String | 解密后是一个json报文 |
1.2.1.2 报文加签和验签机制
1.
2.
3.
1.
{
"code":"000000",
"message":"请求成功",
"clientSerialNo":"1661242378542",
"data":"eyJuYW1lIjogIuWwj+aYjiIsICJhZ2UiOiA4fQ==",
"encryptType":"BASE64",
"merchantNo":"123",
"signData":"326c67656b1c0093f93adb53eb352305",
"signType":"MD5",
"timestamp":1661242378542
}
2.
3.
4.
{
"code": "200",
"message": "操作成功",
"result": null
}
1.2.1.3 报文加签和验签机制
1.
2.
3.
1.
{
"code":"000000",
"message":"请求成功",
"clientSerialNo":"1661242378542",
"data":"eyJuYW1lIjogIuWwj+aYjiIsICJhZ2UiOiA4fQ==",
"encryptType":"BASE64",
"merchantNo":"123",
"signData":"326c67656b1c0093f93adb53eb352305",
"signType":"MD5",
"timestamp":1661242378542
}
2.
3.
4.
{
"code": "200",
"message": "操作成功",
"result": null
}
1.2.2 请求DEMO(java版)
1.2.2.1 maven依赖
<!-- 引用工具包 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.22</version>
</dependency>
1.2.2.2 DEMO
/**
* 发票开具结果查询
*/
public void getInvoiceInfo(String requestNo) throws Exception{
if(StringUtils.isEmpty(requestNo)){
return;
}
// 商户编号(标普智元分配)
String MERCHANT_NO="xxx";
// 请求秘钥(标普智元分配)
String API_KEY="xxx";
Map<String,Object> dataMap = new HashMap<>();
// 订单请求流水号
dataMap.put("requestNo",requestNo);
String encodeReqData = new String(Base64.encodeBase64(JSONUtil.toJsonStr(dataMap).getBytes("UTF-8")));
String signData = getStringMD5(API_KEY+encodeReqData);
Map<String,Object> reqMap = new HashMap<>();
reqMap.put("clientSerialNo","123456");
reqMap.put("encryptType","BASE64");
reqMap.put("merchantNo",MERCHANT_NO);
reqMap.put("signType","MD5");
reqMap.put("data",encodeReqData);
reqMap.put("signData",signData);
reqMap.put("timestamp",String.valueOf(System.currentTimeMillis()));
log.info("发票开具结果查询,请求报文:{}", JSONUtil.toJsonStr(reqMap));
HttpResponse response = HttpRequest.post("http://ibms-test.wecube.com/ibms/invoice/v1/etax/getInvoiceInfo").body(JSONUtil.toJsonStr(reqMap))
.contentType("application/json;charset=utf-8").timeout(30000).execute();
log.info("发票开具结果查询,响应报文:{}", JSONUtil.toJsonStr(response));
String result = response.body();
Map<String, Object> rspMap = JSONUtil.toBean(result, Map.class);
if (isSuccessResult(API_KEY, rspMap)) {
String data = rspMap.get("data").toString();
String rspData = new String(Base64.decodeBase64(data), Charset.forName("UTF-8"));
log.info("发票开具结果查询,响应业务对象:{}", rspData);
} else {
log.info("发票开具结果查询失败");
}
}
/**
* 获取字符串的MD5
* @param input
* @return
*/
public String getStringMD5(String input){
try {
// get MD5 digest
MessageDigest mDigest = MessageDigest.getInstance("MD5");
byte[] inputArr = input.getBytes();
mDigest.update(inputArr);
byte[] resultArr = mDigest.digest();
//
return byteArrToHex(resultArr).toLowerCase();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
/**
* 将字节数组转换为16进制字符串
* @return 16进制字符串
*/
private String byteArrToHex(byte[] byteArr) {
char[] hexDigits = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
char[] resultCharArr = new char[byteArr.length*2];
int index = 0;
for (byte b : byteArr) {
resultCharArr[index++] = hexDigits[b>>> 4 & 0xf];
resultCharArr[index++] = hexDigits[b & 0xf];
}
return new String(resultCharArr);
}
/**
* 判断验签结果是否正确
*/
public boolean isSuccessResult(String apiKey, Map<String, Object> rspMap) {
try {
StringBuffer sb = new StringBuffer(apiKey).append(rspMap.get("data"));
String encodeSignData = getStringMD5(sb.toString());
return encodeSignData.equals(rspMap.get("signData"));
} catch (Exception e) {
return false;
}
}
1.3请求地址
环境 | 地址 |
---|---|
测试 | http://ibms-test.wecube.com/ |
生产 | https://ibms.biaopu.cloud |