|
@@ -7,7 +7,9 @@ import cn.hutool.json.JSONObject;
|
|
|
import cn.hutool.json.JSONUtil;
|
|
import cn.hutool.json.JSONUtil;
|
|
|
import com.jfinal.kit.HttpKit;
|
|
import com.jfinal.kit.HttpKit;
|
|
|
import com.jfinal.kit.StrKit;
|
|
import com.jfinal.kit.StrKit;
|
|
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
import java.util.*;
|
|
import java.util.*;
|
|
|
|
|
+import java.util.Base64;
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 通联支付SDK
|
|
* 通联支付SDK
|
|
@@ -19,9 +21,9 @@ import java.util.*;
|
|
|
public class AllinpaySDK {
|
|
public class AllinpaySDK {
|
|
|
|
|
|
|
|
// 生产环境配置
|
|
// 生产环境配置
|
|
|
- private static final String BASE_URL = "https://syb.allinpay.com";
|
|
|
|
|
- private static final String H5_PAY_URL = BASE_URL + "/apiweb/h5unionpay/unionorder";
|
|
|
|
|
- private static final String QUERY_URL = BASE_URL + "/apiweb/unitorder/query";
|
|
|
|
|
|
|
+ private static final String BASE_URL = "https://vsp.allinpay.com";
|
|
|
|
|
+ private static final String UNIFIED_PAY_URL = BASE_URL + "/apiweb/unitorder/pay";
|
|
|
|
|
+ private static final String QUERY_URL = "https://syb.allinpay.com/apiweb/unitorder/query";
|
|
|
|
|
|
|
|
// 商户配置信息(测试用静态配置)
|
|
// 商户配置信息(测试用静态配置)
|
|
|
private static final String APP_ID = "00000051";
|
|
private static final String APP_ID = "00000051";
|
|
@@ -38,44 +40,56 @@ public class AllinpaySDK {
|
|
|
private static final SM2 sm2 = SmUtil.sm2(SM2_PRIVATE_KEY, ALLINPAY_PUBLIC_KEY);
|
|
private static final SM2 sm2 = SmUtil.sm2(SM2_PRIVATE_KEY, ALLINPAY_PUBLIC_KEY);
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * H5收银台支付
|
|
|
|
|
- *
|
|
|
|
|
- * @param trxamt 交易金额(分)
|
|
|
|
|
- * @param reqsn 商户交易单号
|
|
|
|
|
- * @param body 商品描述
|
|
|
|
|
- * @param remark 备注
|
|
|
|
|
- * @param notify_url 异步通知地址
|
|
|
|
|
- * @param return_url 同步跳转地址
|
|
|
|
|
|
|
+ * 统一支付接口
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param trxamt 交易金额(分)
|
|
|
|
|
+ * @param reqsn 商户交易单号
|
|
|
|
|
+ * @param paytype 交易方式
|
|
|
|
|
+ * @param body 订单标题
|
|
|
|
|
+ * @param remark 备注
|
|
|
|
|
+ * @param acct 支付平台用户标识
|
|
|
|
|
+ * @param notify_url 交易结果通知地址
|
|
|
|
|
+ * @param limit_pay 支付限制
|
|
|
|
|
+ * @param idno 证件号
|
|
|
|
|
+ * @param truename 付款人真实姓名
|
|
|
|
|
+ * @param sub_appid 微信子appid
|
|
|
* @return 支付结果
|
|
* @return 支付结果
|
|
|
*/
|
|
*/
|
|
|
- public static PaymentResult h5Pay(Long trxamt, String reqsn, String body, String remark,
|
|
|
|
|
- String notify_url, String return_url) {
|
|
|
|
|
|
|
+ public static PaymentResult unifiedPay(Long trxamt, String reqsn, String paytype, String body, String remark,
|
|
|
|
|
+ String acct, String notify_url, String limit_pay, String idno,
|
|
|
|
|
+ String truename, String sub_appid) {
|
|
|
try {
|
|
try {
|
|
|
// 1. 构建请求参数
|
|
// 1. 构建请求参数
|
|
|
Map<String, String> params = new TreeMap<>();
|
|
Map<String, String> params = new TreeMap<>();
|
|
|
params.put("appid", APP_ID);
|
|
params.put("appid", APP_ID);
|
|
|
params.put("cusid", CUS_ID);
|
|
params.put("cusid", CUS_ID);
|
|
|
- params.put("version", "12");
|
|
|
|
|
|
|
+ params.put("version", VERSION);
|
|
|
params.put("signtype", SIGN_TYPE);
|
|
params.put("signtype", SIGN_TYPE);
|
|
|
params.put("randomstr", RandomUtil.randomString(8));
|
|
params.put("randomstr", RandomUtil.randomString(8));
|
|
|
params.put("trxamt", String.valueOf(trxamt));
|
|
params.put("trxamt", String.valueOf(trxamt));
|
|
|
params.put("reqsn", reqsn);
|
|
params.put("reqsn", reqsn);
|
|
|
|
|
+ params.put("paytype", paytype);
|
|
|
params.put("body", body);
|
|
params.put("body", body);
|
|
|
params.put("remark", remark);
|
|
params.put("remark", remark);
|
|
|
params.put("notify_url", notify_url);
|
|
params.put("notify_url", notify_url);
|
|
|
- params.put("return_url", return_url);
|
|
|
|
|
- params.put("charset", "UTF-8");
|
|
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 添加可选参数
|
|
|
|
|
+ if (StrKit.notBlank(acct)) params.put("acct", acct);
|
|
|
|
|
+ if (StrKit.notBlank(limit_pay)) params.put("limit_pay", limit_pay);
|
|
|
|
|
+ if (StrKit.notBlank(idno)) params.put("idno", idno);
|
|
|
|
|
+ if (StrKit.notBlank(truename)) params.put("truename", truename);
|
|
|
|
|
+ if (StrKit.notBlank(sub_appid)) params.put("sub_appid", sub_appid);
|
|
|
|
|
+
|
|
|
// 2. 生成签名
|
|
// 2. 生成签名
|
|
|
String sign = generateSign(params);
|
|
String sign = generateSign(params);
|
|
|
params.put("sign", sign);
|
|
params.put("sign", sign);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 3. 发送请求
|
|
// 3. 发送请求
|
|
|
- String response = sendPostRequest(H5_PAY_URL, params);
|
|
|
|
|
-
|
|
|
|
|
|
|
+ String response = sendPostRequest(UNIFIED_PAY_URL, params);
|
|
|
|
|
+
|
|
|
// 4. 解析响应
|
|
// 4. 解析响应
|
|
|
return parsePaymentResponse(response);
|
|
return parsePaymentResponse(response);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
e.printStackTrace();
|
|
e.printStackTrace();
|
|
|
return PaymentResult.error("支付请求失败: " + e.getMessage());
|
|
return PaymentResult.error("支付请求失败: " + e.getMessage());
|
|
@@ -143,7 +157,7 @@ public class AllinpaySDK {
|
|
|
System.out.println("通知验签字符串: " + signString);
|
|
System.out.println("通知验签字符串: " + signString);
|
|
|
|
|
|
|
|
// 使用通联公钥验签
|
|
// 使用通联公钥验签
|
|
|
- boolean verifyResult = sm2.verifyHex(signString, sign);
|
|
|
|
|
|
|
+ boolean verifyResult = sm2.verify(signString.getBytes(StandardCharsets.UTF_8), sign.getBytes(StandardCharsets.UTF_8), APP_ID.getBytes(StandardCharsets.UTF_8));
|
|
|
|
|
|
|
|
if (!verifyResult) {
|
|
if (!verifyResult) {
|
|
|
return NotifyResult.error("签名验证失败");
|
|
return NotifyResult.error("签名验证失败");
|
|
@@ -172,7 +186,8 @@ public class AllinpaySDK {
|
|
|
System.out.println("签名字符串: " + signString);
|
|
System.out.println("签名字符串: " + signString);
|
|
|
|
|
|
|
|
// 2. 使用SM2私钥签名
|
|
// 2. 使用SM2私钥签名
|
|
|
- String sign = sm2.signHex(signString);
|
|
|
|
|
|
|
+ byte[] signBytes = sm2.sign(signString.getBytes(StandardCharsets.UTF_8), APP_ID.getBytes(StandardCharsets.UTF_8));
|
|
|
|
|
+ String sign = Base64.getEncoder().encodeToString(signBytes);
|
|
|
|
|
|
|
|
System.out.println("生成的签名: " + sign);
|
|
System.out.println("生成的签名: " + sign);
|
|
|
return sign;
|
|
return sign;
|
|
@@ -319,7 +334,7 @@ public class AllinpaySDK {
|
|
|
System.out.println("验签字符串: " + signString);
|
|
System.out.println("验签字符串: " + signString);
|
|
|
|
|
|
|
|
// 使用通联公钥验签
|
|
// 使用通联公钥验签
|
|
|
- boolean result = sm2.verifyHex(signString, sign);
|
|
|
|
|
|
|
+ boolean result = sm2.verify(signString.getBytes(StandardCharsets.UTF_8), Base64.getDecoder().decode(sign), APP_ID.getBytes(StandardCharsets.UTF_8));
|
|
|
|
|
|
|
|
System.out.println("验签结果: " + result);
|
|
System.out.println("验签结果: " + result);
|
|
|
return result;
|
|
return result;
|
|
@@ -485,14 +500,13 @@ public class AllinpaySDK {
|
|
|
String body = "测试商品";
|
|
String body = "测试商品";
|
|
|
String remark = "SDK测试订单";
|
|
String remark = "SDK测试订单";
|
|
|
String notify_url = "https://your-domain.com/api/payment/callback";
|
|
String notify_url = "https://your-domain.com/api/payment/callback";
|
|
|
- String return_url = "https://your-domain.com/payment-result";
|
|
|
|
|
|
|
|
|
|
System.out.println("测试订单号: " + reqsn);
|
|
System.out.println("测试订单号: " + reqsn);
|
|
|
System.out.println("交易金额: " + trxamt + "分");
|
|
System.out.println("交易金额: " + trxamt + "分");
|
|
|
|
|
|
|
|
- // 测试1: H5支付
|
|
|
|
|
- System.out.println("\n=== 测试H5支付 ===");
|
|
|
|
|
- PaymentResult payResult = h5Pay(trxamt, reqsn, body, remark, notify_url, return_url);
|
|
|
|
|
|
|
+ // 测试1: 统一支付
|
|
|
|
|
+ System.out.println("\n=== 测试统一支付 ===");
|
|
|
|
|
+ PaymentResult payResult = unifiedPay(trxamt, reqsn, "W02", body, remark, "o9o43wz9sV5x8P-MA2b02mtYw4Co", notify_url, null, null, null, null);
|
|
|
System.out.println("支付结果: " + payResult);
|
|
System.out.println("支付结果: " + payResult);
|
|
|
|
|
|
|
|
if (payResult.isSuccess()) {
|
|
if (payResult.isSuccess()) {
|