|
@@ -1,46 +1,18 @@
|
|
|
package common.utils.tl;
|
|
package common.utils.tl;
|
|
|
|
|
|
|
|
-import cn.hutool.core.util.RandomUtil;
|
|
|
|
|
-import cn.hutool.crypto.SmUtil;
|
|
|
|
|
-import cn.hutool.crypto.asymmetric.SM2;
|
|
|
|
|
-import cn.hutool.json.JSONObject;
|
|
|
|
|
-import cn.hutool.json.JSONUtil;
|
|
|
|
|
-import com.jfinal.kit.HttpKit;
|
|
|
|
|
-import com.jfinal.kit.StrKit;
|
|
|
|
|
-import java.net.URLEncoder;
|
|
|
|
|
-import java.nio.charset.StandardCharsets;
|
|
|
|
|
import java.util.*;
|
|
import java.util.*;
|
|
|
-import java.util.Base64;
|
|
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 通联支付SDK
|
|
|
|
|
|
|
+ * 通联支付SDK - 使用现有工具类实现
|
|
|
* 支持H5收银台支付功能
|
|
* 支持H5收银台支付功能
|
|
|
*
|
|
*
|
|
|
* @author skyff
|
|
* @author skyff
|
|
|
* @date 2024
|
|
* @date 2024
|
|
|
*/
|
|
*/
|
|
|
public class AllinpaySDK {
|
|
public class AllinpaySDK {
|
|
|
- // 商户配置信息
|
|
|
|
|
- private static final String VERSION = "12";
|
|
|
|
|
- private static final String SIGN_TYPE = "SM2";
|
|
|
|
|
- private static final String APP_ID = "00375513";
|
|
|
|
|
- private static final String CUS_ID = "660222053994DLK";
|
|
|
|
|
-
|
|
|
|
|
- // SM2密钥对
|
|
|
|
|
- private static final String SM2_PRIVATE_KEY = System.getenv("TL_SM2_PRIVATE_KEY");
|
|
|
|
|
-
|
|
|
|
|
- // 通联公钥(用于验签,实际使用时需要从通联获取)
|
|
|
|
|
- private static final String ALLINPAY_PUBLIC_KEY = System.getenv("TL_SM2_PUBLIC_KEY");
|
|
|
|
|
-
|
|
|
|
|
- // 生产环境配置
|
|
|
|
|
- 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 SM2 sm2 = SmUtil.sm2(SM2_PRIVATE_KEY, ALLINPAY_PUBLIC_KEY);
|
|
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * H5收银台支付
|
|
|
|
|
|
|
+ * H5收银台支付 - 使用现有工具类实现
|
|
|
*
|
|
*
|
|
|
* @param trxamt 交易金额(分)
|
|
* @param trxamt 交易金额(分)
|
|
|
* @param reqsn 商户订单号
|
|
* @param reqsn 商户订单号
|
|
@@ -59,69 +31,80 @@ public class AllinpaySDK {
|
|
|
String notify_url, String returl, String charset,
|
|
String notify_url, String returl, String charset,
|
|
|
Integer validtime, String limit_pay, String truename, String idno) {
|
|
Integer validtime, String limit_pay, String truename, String idno) {
|
|
|
try {
|
|
try {
|
|
|
- // 1. 构建请求参数
|
|
|
|
|
- Map<String, String> params = new TreeMap<>();
|
|
|
|
|
- params.put("cusid", CUS_ID);
|
|
|
|
|
- params.put("appid", APP_ID);
|
|
|
|
|
- params.put("version", VERSION);
|
|
|
|
|
|
|
+ // 使用HttpConnectionUtil发送H5支付请求
|
|
|
|
|
+ HttpConnectionUtil http = new HttpConnectionUtil(SybConstants.SYB_APIURL + "/h5unionpay/unionorder");
|
|
|
|
|
+ http.init();
|
|
|
|
|
+
|
|
|
|
|
+ // 构建请求参数
|
|
|
|
|
+ TreeMap<String, String> params = new TreeMap<>();
|
|
|
|
|
+ if (!SybUtil.isEmpty(SybConstants.SYB_ORGID)) {
|
|
|
|
|
+ params.put("orgid", SybConstants.SYB_ORGID);
|
|
|
|
|
+ }
|
|
|
|
|
+ params.put("cusid", SybConstants.SYB_CUSID);
|
|
|
|
|
+ params.put("appid", SybConstants.SYB_APPID);
|
|
|
|
|
+ params.put("version", SybConstants.VERSION);
|
|
|
params.put("trxamt", String.valueOf(trxamt));
|
|
params.put("trxamt", String.valueOf(trxamt));
|
|
|
- params.put("signtype", SIGN_TYPE);
|
|
|
|
|
- params.put("randomstr", RandomUtil.randomString(8));
|
|
|
|
|
params.put("reqsn", reqsn);
|
|
params.put("reqsn", reqsn);
|
|
|
params.put("body", body);
|
|
params.put("body", body);
|
|
|
params.put("remark", remark);
|
|
params.put("remark", remark);
|
|
|
- params.put("returl", returl);
|
|
|
|
|
|
|
+ params.put("notify_url", notify_url);
|
|
|
|
|
+ params.put("randomstr", SybUtil.getValidatecode(8));
|
|
|
|
|
+ params.put("signtype", SybConstants.SIGN_TYPE);
|
|
|
|
|
|
|
|
// 添加可选参数
|
|
// 添加可选参数
|
|
|
- if (StrKit.notBlank(returl)) params.put("returl", returl);
|
|
|
|
|
- if (StrKit.notBlank(charset)) params.put("charset", charset);
|
|
|
|
|
|
|
+ if (!SybUtil.isEmpty(returl)) params.put("returl", returl);
|
|
|
|
|
+ if (!SybUtil.isEmpty(charset)) params.put("charset", charset);
|
|
|
if (validtime != null) params.put("validtime", String.valueOf(validtime));
|
|
if (validtime != null) params.put("validtime", String.valueOf(validtime));
|
|
|
- if (StrKit.notBlank(limit_pay)) params.put("limit_pay", limit_pay);
|
|
|
|
|
- if (StrKit.notBlank(truename)) params.put("truename", truename);
|
|
|
|
|
- if (StrKit.notBlank(idno)) params.put("idno", idno);
|
|
|
|
|
|
|
+ if (!SybUtil.isEmpty(limit_pay)) params.put("limit_pay", limit_pay);
|
|
|
|
|
+ if (!SybUtil.isEmpty(truename)) params.put("truename", truename);
|
|
|
|
|
+ if (!SybUtil.isEmpty(idno)) params.put("idno", idno);
|
|
|
|
|
|
|
|
- // 2. 生成签名
|
|
|
|
|
- String sign = generateSign(params);
|
|
|
|
|
- params.put("sign", sign);
|
|
|
|
|
|
|
+ // 生成签名
|
|
|
|
|
+ String appkey = getAppKey();
|
|
|
|
|
+ params.put("sign", SybUtil.unionSign(params, appkey, SybConstants.SIGN_TYPE));
|
|
|
|
|
|
|
|
- // 3. 发送请求
|
|
|
|
|
- String response = sendPostRequest(H5_PAY_URL, params);
|
|
|
|
|
|
|
+ // 发送请求
|
|
|
|
|
+ byte[] responseBytes = http.postParams(params, true);
|
|
|
|
|
+ String response = new String(responseBytes, "UTF-8");
|
|
|
|
|
+
|
|
|
|
|
+ http.destory();
|
|
|
|
|
|
|
|
- // 4. 解析响应
|
|
|
|
|
- return parsePaymentResponse(response);
|
|
|
|
|
|
|
+ // 处理响应
|
|
|
|
|
+ Map<String, String> resultMap = SybPayService.handleResult(response);
|
|
|
|
|
+
|
|
|
|
|
+ if ("SUCCESS".equals(resultMap.get("retcode"))) {
|
|
|
|
|
+ String payUrl = resultMap.get("payinfo");
|
|
|
|
|
+ return PaymentResult.success(payUrl, "H5支付链接生成成功");
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return PaymentResult.error("H5支付失败: " + resultMap.get("retmsg"));
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
e.printStackTrace();
|
|
e.printStackTrace();
|
|
|
- return PaymentResult.error("支付请求失败: " + e.getMessage());
|
|
|
|
|
|
|
+ return PaymentResult.error("H5支付请求失败: " + e.getMessage());
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 查询支付结果
|
|
|
|
|
|
|
+ * 查询支付结果 - 使用现有工具类实现
|
|
|
*
|
|
*
|
|
|
* @param reqsn 商户交易单号
|
|
* @param reqsn 商户交易单号
|
|
|
* @return 查询结果
|
|
* @return 查询结果
|
|
|
*/
|
|
*/
|
|
|
public static QueryResult queryPayment(String reqsn) {
|
|
public static QueryResult queryPayment(String reqsn) {
|
|
|
try {
|
|
try {
|
|
|
- // 1. 构建请求参数
|
|
|
|
|
- Map<String, String> params = new TreeMap<>();
|
|
|
|
|
- params.put("appid", APP_ID);
|
|
|
|
|
- params.put("cusid", CUS_ID);
|
|
|
|
|
- params.put("version", VERSION);
|
|
|
|
|
- params.put("signtype", SIGN_TYPE);
|
|
|
|
|
- params.put("randomstr", RandomUtil.randomString(8));
|
|
|
|
|
- params.put("reqsn", reqsn);
|
|
|
|
|
-
|
|
|
|
|
- // 2. 生成签名
|
|
|
|
|
- String sign = generateSign(params);
|
|
|
|
|
- params.put("sign", sign);
|
|
|
|
|
-
|
|
|
|
|
- // 3. 发送请求
|
|
|
|
|
- String response = sendPostRequest(QUERY_URL, params);
|
|
|
|
|
-
|
|
|
|
|
- // 4. 解析响应
|
|
|
|
|
- return parseQueryResponse(response);
|
|
|
|
|
|
|
+ // 直接使用SybPayService的query方法
|
|
|
|
|
+ SybPayService payService = new SybPayService();
|
|
|
|
|
+ Map<String, String> resultMap = payService.query(reqsn, null);
|
|
|
|
|
+
|
|
|
|
|
+ if ("SUCCESS".equals(resultMap.get("retcode"))) {
|
|
|
|
|
+ String trxstatus = resultMap.get("trxstatus");
|
|
|
|
|
+ String trxid = resultMap.get("trxid");
|
|
|
|
|
+ String trxamt = resultMap.get("trxamt");
|
|
|
|
|
+ return QueryResult.success(trxstatus, trxid, trxamt, "查询成功");
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return QueryResult.error("查询失败: " + resultMap.get("retmsg"));
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
e.printStackTrace();
|
|
e.printStackTrace();
|
|
@@ -130,7 +113,7 @@ public class AllinpaySDK {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 处理异步通知
|
|
|
|
|
|
|
+ * 处理异步通知 - 使用现有工具类实现
|
|
|
*
|
|
*
|
|
|
* @param notifyParams 通知参数
|
|
* @param notifyParams 通知参数
|
|
|
* @return 处理结果
|
|
* @return 处理结果
|
|
@@ -139,31 +122,29 @@ public class AllinpaySDK {
|
|
|
try {
|
|
try {
|
|
|
System.out.println("收到异步通知: " + notifyParams);
|
|
System.out.println("收到异步通知: " + notifyParams);
|
|
|
|
|
|
|
|
- // 1. 验证签名
|
|
|
|
|
|
|
+ // 验证签名
|
|
|
String sign = notifyParams.get("sign");
|
|
String sign = notifyParams.get("sign");
|
|
|
- if (sign == null || sign.trim().isEmpty()) {
|
|
|
|
|
|
|
+ if (SybUtil.isEmpty(sign)) {
|
|
|
return NotifyResult.error("签名为空");
|
|
return NotifyResult.error("签名为空");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 构建验签参数
|
|
// 构建验签参数
|
|
|
- Map<String, String> verifyParams = new TreeMap<>();
|
|
|
|
|
|
|
+ TreeMap<String, String> verifyParams = new TreeMap<>();
|
|
|
for (Map.Entry<String, String> entry : notifyParams.entrySet()) {
|
|
for (Map.Entry<String, String> entry : notifyParams.entrySet()) {
|
|
|
- if (!"sign".equals(entry.getKey()) && entry.getValue() != null) {
|
|
|
|
|
|
|
+ if (!"sign".equals(entry.getKey()) && !SybUtil.isEmpty(entry.getValue())) {
|
|
|
verifyParams.put(entry.getKey(), entry.getValue());
|
|
verifyParams.put(entry.getKey(), entry.getValue());
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- String signString = buildSignString(verifyParams);
|
|
|
|
|
- System.out.println("通知验签字符串: " + signString);
|
|
|
|
|
-
|
|
|
|
|
- // 使用通联公钥验签
|
|
|
|
|
- boolean verifyResult = sm2.verify(signString.getBytes(StandardCharsets.UTF_8), sign.getBytes(StandardCharsets.UTF_8), APP_ID.getBytes(StandardCharsets.UTF_8));
|
|
|
|
|
|
|
+ // 使用SybUtil进行签名验证
|
|
|
|
|
+ String appkey = getAppKey();
|
|
|
|
|
+ boolean verifyResult = SybUtil.validSign(verifyParams, appkey, SybConstants.SIGN_TYPE);
|
|
|
|
|
|
|
|
if (!verifyResult) {
|
|
if (!verifyResult) {
|
|
|
return NotifyResult.error("签名验证失败");
|
|
return NotifyResult.error("签名验证失败");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 2. 解析通知内容
|
|
|
|
|
|
|
+ // 解析通知内容
|
|
|
String reqsn = notifyParams.get("reqsn");
|
|
String reqsn = notifyParams.get("reqsn");
|
|
|
String trxstatus = notifyParams.get("trxstatus");
|
|
String trxstatus = notifyParams.get("trxstatus");
|
|
|
String trxid = notifyParams.get("trxid");
|
|
String trxid = notifyParams.get("trxid");
|
|
@@ -178,172 +159,15 @@ public class AllinpaySDK {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 生成SM2签名
|
|
|
|
|
- */
|
|
|
|
|
- private static String generateSign(Map<String, String> params) throws Exception {
|
|
|
|
|
- // 1. 排序并拼接参数(排除sign字段)
|
|
|
|
|
- String signString = buildSignString(params);
|
|
|
|
|
- System.out.println("签名字符串: " + signString);
|
|
|
|
|
-
|
|
|
|
|
- // 2. 使用SM2私钥签名
|
|
|
|
|
- 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);
|
|
|
|
|
- return sign;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 构建签名字符串
|
|
|
|
|
- */
|
|
|
|
|
- private static String buildSignString(Map<String, String> params) {
|
|
|
|
|
- StringBuilder sb = new StringBuilder();
|
|
|
|
|
- boolean first = true;
|
|
|
|
|
-
|
|
|
|
|
- for (Map.Entry<String, String> entry : params.entrySet()) {
|
|
|
|
|
- String key = entry.getKey();
|
|
|
|
|
- String value = entry.getValue();
|
|
|
|
|
-
|
|
|
|
|
- // 排除sign字段和空值
|
|
|
|
|
- if (!"sign".equals(key) && value != null && !value.trim().isEmpty()) {
|
|
|
|
|
- if (!first) {
|
|
|
|
|
- sb.append("&");
|
|
|
|
|
- }
|
|
|
|
|
- sb.append(key).append("=").append(value);
|
|
|
|
|
- first = false;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return sb.toString();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 发送POST请求
|
|
|
|
|
- */
|
|
|
|
|
- private static String sendPostRequest(String url, Map<String, String> params) throws Exception {
|
|
|
|
|
- // 构建表单参数
|
|
|
|
|
- StringBuilder formData = new StringBuilder();
|
|
|
|
|
- boolean first = true;
|
|
|
|
|
- for (Map.Entry<String, String> entry : params.entrySet()) {
|
|
|
|
|
- if (!first) {
|
|
|
|
|
- formData.append("&");
|
|
|
|
|
- }
|
|
|
|
|
- formData.append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue(), "UTF-8"));
|
|
|
|
|
- first = false;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 设置请求头
|
|
|
|
|
- Map<String, String> headers = new HashMap<>();
|
|
|
|
|
- headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
|
|
|
|
|
-
|
|
|
|
|
- String finalUrl = url + "?" + formData;
|
|
|
|
|
-
|
|
|
|
|
- // 使用JFinal的HttpKit发送请求
|
|
|
|
|
- String response = HttpKit.post(finalUrl, null, null, headers);
|
|
|
|
|
-
|
|
|
|
|
- if (StrKit.isBlank(response)) {
|
|
|
|
|
- throw new RuntimeException("API响应为空");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return response;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 解析支付响应
|
|
|
|
|
- */
|
|
|
|
|
- private static PaymentResult parsePaymentResponse(String response) {
|
|
|
|
|
- try {
|
|
|
|
|
- System.out.println("支付响应: " + response);
|
|
|
|
|
-
|
|
|
|
|
- JSONObject jsonResponse = JSONUtil.parseObj(response);
|
|
|
|
|
-
|
|
|
|
|
- // 验证响应签名
|
|
|
|
|
- if (!verifyResponseSign(jsonResponse)) {
|
|
|
|
|
- return PaymentResult.error("响应签名验证失败");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- String retcode = jsonResponse.getStr("retcode");
|
|
|
|
|
- String retmsg = jsonResponse.getStr("retmsg");
|
|
|
|
|
-
|
|
|
|
|
- if ("SUCCESS".equals(retcode)) {
|
|
|
|
|
- String payUrl = jsonResponse.getStr("payinfo");
|
|
|
|
|
- return PaymentResult.success(payUrl, "支付链接生成成功");
|
|
|
|
|
- } else {
|
|
|
|
|
- return PaymentResult.error("支付失败: " + retmsg);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- e.printStackTrace();
|
|
|
|
|
- return PaymentResult.error("响应解析失败: " + e.getMessage());
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 解析查询响应
|
|
|
|
|
- */
|
|
|
|
|
- private static QueryResult parseQueryResponse(String response) {
|
|
|
|
|
- try {
|
|
|
|
|
- System.out.println("查询响应: " + response);
|
|
|
|
|
-
|
|
|
|
|
- JSONObject jsonResponse = JSONUtil.parseObj(response);
|
|
|
|
|
-
|
|
|
|
|
- // 验证响应签名
|
|
|
|
|
- if (!verifyResponseSign(jsonResponse)) {
|
|
|
|
|
- return QueryResult.error("响应签名验证失败");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- String retcode = jsonResponse.getStr("retcode");
|
|
|
|
|
- String retmsg = jsonResponse.getStr("retmsg");
|
|
|
|
|
-
|
|
|
|
|
- if ("SUCCESS".equals(retcode)) {
|
|
|
|
|
- String trxstatus = jsonResponse.getStr("trxstatus");
|
|
|
|
|
- String trxid = jsonResponse.getStr("trxid");
|
|
|
|
|
- String trxamt = jsonResponse.getStr("trxamt");
|
|
|
|
|
-
|
|
|
|
|
- return QueryResult.success(trxstatus, trxid, trxamt, "查询成功");
|
|
|
|
|
- } else {
|
|
|
|
|
- return QueryResult.error("查询失败: " + retmsg);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- e.printStackTrace();
|
|
|
|
|
- return QueryResult.error("响应解析失败: " + e.getMessage());
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 验证响应签名
|
|
|
|
|
|
|
+ * 获取签名密钥
|
|
|
*/
|
|
*/
|
|
|
- private static boolean verifyResponseSign(JSONObject response) {
|
|
|
|
|
- try {
|
|
|
|
|
- String sign = response.getStr("sign");
|
|
|
|
|
- if (sign == null || sign.trim().isEmpty()) {
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 构建验签字符串
|
|
|
|
|
- Map<String, String> params = new TreeMap<>();
|
|
|
|
|
- for (String key : response.keySet()) {
|
|
|
|
|
- if (!"sign".equals(key)) {
|
|
|
|
|
- Object value = response.get(key);
|
|
|
|
|
- if (value != null) {
|
|
|
|
|
- params.put(key, value.toString());
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- String signString = buildSignString(params);
|
|
|
|
|
- System.out.println("验签字符串: " + signString);
|
|
|
|
|
-
|
|
|
|
|
- // 使用通联公钥验签
|
|
|
|
|
- boolean result = sm2.verify(signString.getBytes(StandardCharsets.UTF_8), Base64.getDecoder().decode(sign), APP_ID.getBytes(StandardCharsets.UTF_8));
|
|
|
|
|
-
|
|
|
|
|
- System.out.println("验签结果: " + result);
|
|
|
|
|
- return result;
|
|
|
|
|
-
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- e.printStackTrace();
|
|
|
|
|
- return false;
|
|
|
|
|
|
|
+ private static String getAppKey() {
|
|
|
|
|
+ if ("RSA".equals(SybConstants.SIGN_TYPE)) {
|
|
|
|
|
+ return SybConstants.SYB_RSACUSPRIKEY;
|
|
|
|
|
+ } else if ("SM2".equals(SybConstants.SIGN_TYPE)) {
|
|
|
|
|
+ return SybConstants.SYB_SM2PPRIVATEKEY;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return SybConstants.SYB_MD5_APPKEY;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -491,175 +315,184 @@ public class AllinpaySDK {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 测试主方法 - 使用现有工具类进行测试
|
|
|
|
|
|
|
+ * 测试主方法 - 专门测试H5收银台支付
|
|
|
*/
|
|
*/
|
|
|
public static void main(String[] args) {
|
|
public static void main(String[] args) {
|
|
|
- System.out.println("=== 通联支付SDK测试 (使用现有工具类) ===");
|
|
|
|
|
-
|
|
|
|
|
- // 创建SybPayService实例
|
|
|
|
|
- SybPayService payService = new SybPayService();
|
|
|
|
|
|
|
+ System.out.println("=== 通联支付H5收银台测试 ===");
|
|
|
|
|
|
|
|
// 测试参数
|
|
// 测试参数
|
|
|
- String reqsn = "TEST" + System.currentTimeMillis(); // 商户订单号
|
|
|
|
|
- long trxamt = 100L; // 1元(分为单位)
|
|
|
|
|
|
|
+ String reqsn = "H5TEST" + System.currentTimeMillis(); // 商户订单号
|
|
|
|
|
+ Long trxamt = 100L; // 1元(分为单位)
|
|
|
|
|
+ String body = "测试商品";
|
|
|
|
|
+ String remark = "H5收银台测试订单";
|
|
|
|
|
+ String notify_url = "https://dlsh-nft.com.cn/api/notify/allinpay";
|
|
|
|
|
+ String returl = "https://dlsh-nft.com.cn/success.html";
|
|
|
|
|
+ String charset = "UTF-8";
|
|
|
|
|
+ Integer validtime = 30; // 30分钟有效期
|
|
|
|
|
|
|
|
System.out.println("测试订单号: " + reqsn);
|
|
System.out.println("测试订单号: " + reqsn);
|
|
|
- System.out.println("交易金额: " + trxamt + "分");
|
|
|
|
|
|
|
+ System.out.println("交易金额: " + trxamt + "分 (1元)");
|
|
|
|
|
+ System.out.println("商品名称: " + body);
|
|
|
|
|
+ System.out.println("订单备注: " + remark);
|
|
|
|
|
+ System.out.println("异步通知地址: " + notify_url);
|
|
|
|
|
+ System.out.println("同步跳转地址: " + returl);
|
|
|
|
|
+ System.out.println("有效时间: " + validtime + "分钟");
|
|
|
System.out.println("商户ID: " + SybConstants.SYB_CUSID);
|
|
System.out.println("商户ID: " + SybConstants.SYB_CUSID);
|
|
|
System.out.println("应用ID: " + SybConstants.SYB_APPID);
|
|
System.out.println("应用ID: " + SybConstants.SYB_APPID);
|
|
|
System.out.println("API地址: " + SybConstants.SYB_APIURL);
|
|
System.out.println("API地址: " + SybConstants.SYB_APIURL);
|
|
|
|
|
+ System.out.println("签名类型: " + SybConstants.SIGN_TYPE);
|
|
|
|
|
|
|
|
try {
|
|
try {
|
|
|
- // 测试1: 查询支付结果
|
|
|
|
|
- System.out.println("\n=== 测试查询支付结果 ===");
|
|
|
|
|
- try {
|
|
|
|
|
- Map<String, String> queryResult = payService.query(reqsn, null);
|
|
|
|
|
|
|
+ // 测试H5收银台支付
|
|
|
|
|
+ System.out.println("\n=== 开始H5收银台支付测试 ===");
|
|
|
|
|
+ PaymentResult payResult = h5Pay(trxamt, reqsn, body, remark, notify_url,
|
|
|
|
|
+ returl, charset, validtime, null, null, null);
|
|
|
|
|
+
|
|
|
|
|
+ System.out.println("支付结果: " + payResult);
|
|
|
|
|
+
|
|
|
|
|
+ if (payResult.isSuccess()) {
|
|
|
|
|
+ System.out.println("\n✅ H5支付链接生成成功!");
|
|
|
|
|
+ System.out.println("支付链接: " + payResult.getPayUrl());
|
|
|
|
|
+ System.out.println("消息: " + payResult.getMessage());
|
|
|
|
|
+ System.out.println("\n请复制上述链接到浏览器中打开完成支付测试");
|
|
|
|
|
+
|
|
|
|
|
+ // 等待一段时间后查询支付结果
|
|
|
|
|
+ System.out.println("\n=== 等待5秒后查询支付结果 ===");
|
|
|
|
|
+ try {
|
|
|
|
|
+ Thread.sleep(5000); // 等待5秒
|
|
|
|
|
+ } catch (InterruptedException e) {
|
|
|
|
|
+ Thread.currentThread().interrupt();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ QueryResult queryResult = queryPayment(reqsn);
|
|
|
System.out.println("查询结果: " + queryResult);
|
|
System.out.println("查询结果: " + queryResult);
|
|
|
|
|
|
|
|
- if ("SUCCESS".equals(queryResult.get("retcode"))) {
|
|
|
|
|
- System.out.println("查询成功!");
|
|
|
|
|
- System.out.println("交易状态: " + queryResult.get("trxstatus"));
|
|
|
|
|
- System.out.println("交易ID: " + queryResult.get("trxid"));
|
|
|
|
|
- System.out.println("交易金额: " + queryResult.get("trxamt"));
|
|
|
|
|
|
|
+ if (queryResult.isSuccess()) {
|
|
|
|
|
+ System.out.println("✅ 查询成功!");
|
|
|
|
|
+ System.out.println("交易状态: " + queryResult.getTrxstatus());
|
|
|
|
|
+ System.out.println("交易ID: " + queryResult.getTrxid());
|
|
|
|
|
+ System.out.println("交易金额: " + queryResult.getTrxamt());
|
|
|
} else {
|
|
} else {
|
|
|
- System.out.println("查询失败: " + queryResult.get("retmsg"));
|
|
|
|
|
|
|
+ System.out.println("❌ 查询失败: " + queryResult.getMessage());
|
|
|
}
|
|
}
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- System.out.println("查询异常: " + e.getMessage());
|
|
|
|
|
|
|
+
|
|
|
|
|
+ } else {
|
|
|
|
|
+ System.out.println("\n❌ H5支付失败!");
|
|
|
|
|
+ System.out.println("错误信息: " + payResult.getMessage());
|
|
|
|
|
+ System.out.println("错误代码: " + payResult.getErrorCode());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 测试2: 退款操作 (需要有原始交易)
|
|
|
|
|
- System.out.println("\n=== 测试退款操作 ===");
|
|
|
|
|
- String refundReqsn = "REFUND" + System.currentTimeMillis();
|
|
|
|
|
- String oldTrxId = "TL" + (System.currentTimeMillis() - 1000); // 模拟原交易ID
|
|
|
|
|
- String oldReqsn = "OLD" + (System.currentTimeMillis() - 1000); // 模拟原订单号
|
|
|
|
|
-
|
|
|
|
|
- try {
|
|
|
|
|
- Map<String, String> refundResult = payService.refund(trxamt, refundReqsn, oldTrxId, oldReqsn);
|
|
|
|
|
- System.out.println("退款结果: " + refundResult);
|
|
|
|
|
-
|
|
|
|
|
- if ("SUCCESS".equals(refundResult.get("retcode"))) {
|
|
|
|
|
- System.out.println("退款成功!");
|
|
|
|
|
- System.out.println("退款交易ID: " + refundResult.get("trxid"));
|
|
|
|
|
- } else {
|
|
|
|
|
- System.out.println("退款失败: " + refundResult.get("retmsg"));
|
|
|
|
|
- }
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- System.out.println("退款异常: " + e.getMessage());
|
|
|
|
|
|
|
+ // 测试异步通知处理
|
|
|
|
|
+ System.out.println("\n=== 测试异步通知处理 ===");
|
|
|
|
|
+ Map<String, String> notifyParams = new HashMap<>();
|
|
|
|
|
+ notifyParams.put("reqsn", reqsn);
|
|
|
|
|
+ notifyParams.put("trxstatus", "0000"); // 成功状态
|
|
|
|
|
+ notifyParams.put("trxid", "TL" + System.currentTimeMillis());
|
|
|
|
|
+ notifyParams.put("trxamt", String.valueOf(trxamt));
|
|
|
|
|
+ notifyParams.put("cusid", SybConstants.SYB_CUSID);
|
|
|
|
|
+ notifyParams.put("appid", SybConstants.SYB_APPID);
|
|
|
|
|
+
|
|
|
|
|
+ // 生成模拟签名
|
|
|
|
|
+ TreeMap<String, String> signParams = new TreeMap<>(notifyParams);
|
|
|
|
|
+ String appkey = getAppKey();
|
|
|
|
|
+ String sign = SybUtil.unionSign(signParams, appkey, SybConstants.SIGN_TYPE);
|
|
|
|
|
+ notifyParams.put("sign", sign);
|
|
|
|
|
+
|
|
|
|
|
+ NotifyResult notifyResult = handleNotify(notifyParams);
|
|
|
|
|
+ System.out.println("通知处理结果: " + notifyResult);
|
|
|
|
|
+
|
|
|
|
|
+ if (notifyResult.isSuccess()) {
|
|
|
|
|
+ System.out.println("✅ 异步通知处理成功!");
|
|
|
|
|
+ System.out.println("订单号: " + notifyResult.getReqsn());
|
|
|
|
|
+ System.out.println("交易状态: " + notifyResult.getTrxstatus());
|
|
|
|
|
+ System.out.println("交易ID: " + notifyResult.getTrxid());
|
|
|
|
|
+ } else {
|
|
|
|
|
+ System.out.println("❌ 异步通知处理失败: " + notifyResult.getMessage());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 测试3: 撤销操作
|
|
|
|
|
- System.out.println("\n=== 测试撤销操作 ===");
|
|
|
|
|
- String cancelReqsn = "CANCEL" + System.currentTimeMillis();
|
|
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ System.out.println("\n❌ 测试过程中发生异常: " + e.getMessage());
|
|
|
|
|
+ e.printStackTrace();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ System.out.println("\n=== H5收银台测试完成 ===");
|
|
|
|
|
+ System.out.println("注意事项:");
|
|
|
|
|
+ System.out.println("1. 如果支付链接生成成功,请在浏览器中打开进行实际支付测试");
|
|
|
|
|
+ System.out.println("2. 支付完成后可以再次运行查询方法验证支付状态");
|
|
|
|
|
+ System.out.println("3. 异步通知需要配置真实的回调地址才能接收到通联的通知");
|
|
|
|
|
+ System.out.println("4. 生产环境使用时请确保配置正确的商户信息和密钥");
|
|
|
|
|
+
|
|
|
|
|
+ /*
|
|
|
|
|
+ // ========== 以下为其他测试代码,暂时注释 ==========
|
|
|
|
|
+
|
|
|
|
|
+ // 测试2: 退款操作 (需要有原始交易)
|
|
|
|
|
+ System.out.println("\n=== 测试退款操作 ===");
|
|
|
|
|
+ String refundReqsn = "REFUND" + System.currentTimeMillis();
|
|
|
|
|
+ String oldTrxId = "TL" + (System.currentTimeMillis() - 1000); // 模拟原交易ID
|
|
|
|
|
+ String oldReqsn = "OLD" + (System.currentTimeMillis() - 1000); // 模拟原订单号
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ Map<String, String> refundResult = payService.refund(trxamt, refundReqsn, oldTrxId, oldReqsn);
|
|
|
|
|
+ System.out.println("退款结果: " + refundResult);
|
|
|
|
|
|
|
|
- try {
|
|
|
|
|
- Map<String, String> cancelResult = payService.cancel(trxamt, cancelReqsn, oldTrxId, oldReqsn);
|
|
|
|
|
- System.out.println("撤销结果: " + cancelResult);
|
|
|
|
|
-
|
|
|
|
|
- if ("SUCCESS".equals(cancelResult.get("retcode"))) {
|
|
|
|
|
- System.out.println("撤销成功!");
|
|
|
|
|
- System.out.println("撤销交易ID: " + cancelResult.get("trxid"));
|
|
|
|
|
- } else {
|
|
|
|
|
- System.out.println("撤销失败: " + cancelResult.get("retmsg"));
|
|
|
|
|
- }
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- System.out.println("撤销异常: " + e.getMessage());
|
|
|
|
|
|
|
+ if ("SUCCESS".equals(refundResult.get("retcode"))) {
|
|
|
|
|
+ System.out.println("退款成功!");
|
|
|
|
|
+ System.out.println("退款交易ID: " + refundResult.get("trxid"));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ System.out.println("退款失败: " + refundResult.get("retmsg"));
|
|
|
}
|
|
}
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ System.out.println("退款异常: " + e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 测试3: 撤销操作
|
|
|
|
|
+ System.out.println("\n=== 测试撤销操作 ===");
|
|
|
|
|
+ String cancelReqsn = "CANCEL" + System.currentTimeMillis();
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ Map<String, String> cancelResult = payService.cancel(trxamt, cancelReqsn, oldTrxId, oldReqsn);
|
|
|
|
|
+ System.out.println("撤销结果: " + cancelResult);
|
|
|
|
|
|
|
|
- // 测试4: 工具类方法测试
|
|
|
|
|
- System.out.println("\n=== 测试工具类方法 ===");
|
|
|
|
|
-
|
|
|
|
|
- // 测试随机字符串生成
|
|
|
|
|
- String randomCode = SybUtil.getValidatecode(8);
|
|
|
|
|
- System.out.println("生成随机码: " + randomCode);
|
|
|
|
|
|
|
+ if ("SUCCESS".equals(cancelResult.get("retcode"))) {
|
|
|
|
|
+ System.out.println("撤销成功!");
|
|
|
|
|
+ System.out.println("撤销交易ID: " + cancelResult.get("trxid"));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ System.out.println("撤销失败: " + cancelResult.get("retmsg"));
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ System.out.println("撤销异常: " + e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 测试5: HTTP连接工具测试
|
|
|
|
|
+ System.out.println("\n=== 测试HTTP连接工具 ===");
|
|
|
|
|
+ try {
|
|
|
|
|
+ HttpConnectionUtil httpUtil = new HttpConnectionUtil(SybConstants.SYB_APIURL + "/unitorder/query");
|
|
|
|
|
+ httpUtil.init();
|
|
|
|
|
|
|
|
- // 测试MD5加密
|
|
|
|
|
- String testData = "test data for md5";
|
|
|
|
|
- String md5Hash = SybUtil.md5(testData.getBytes());
|
|
|
|
|
- System.out.println("MD5加密测试: " + testData + " -> " + md5Hash);
|
|
|
|
|
|
|
+ TreeMap<String, String> httpParams = new TreeMap<>();
|
|
|
|
|
+ httpParams.put("appid", SybConstants.SYB_APPID);
|
|
|
|
|
+ httpParams.put("cusid", SybConstants.SYB_CUSID);
|
|
|
|
|
+ httpParams.put("version", "11");
|
|
|
|
|
+ httpParams.put("reqsn", reqsn);
|
|
|
|
|
+ httpParams.put("randomstr", SybUtil.getValidatecode(8));
|
|
|
|
|
+ httpParams.put("signtype", SybConstants.SIGN_TYPE);
|
|
|
|
|
|
|
|
- // 测试JSON转换
|
|
|
|
|
- String jsonStr = "{\"name\":\"test\",\"value\":\"123\"}";
|
|
|
|
|
- try {
|
|
|
|
|
- Map<String, String> jsonMap = SybUtil.json2Obj(jsonStr, Map.class);
|
|
|
|
|
- System.out.println("JSON转换测试: " + jsonStr + " -> " + jsonMap);
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- System.out.println("JSON转换异常: " + e.getMessage());
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ String appkey = "MD5".equals(SybConstants.SIGN_TYPE) ? SybConstants.SYB_MD5_APPKEY :
|
|
|
|
|
+ "RSA".equals(SybConstants.SIGN_TYPE) ? SybConstants.SYB_RSACUSPRIKEY :
|
|
|
|
|
+ SybConstants.SYB_SM2PPRIVATEKEY;
|
|
|
|
|
|
|
|
- // 测试签名生成
|
|
|
|
|
- System.out.println("\n=== 测试签名生成 ===");
|
|
|
|
|
- TreeMap<String, String> signParams = new TreeMap<>();
|
|
|
|
|
- signParams.put("cusid", SybConstants.SYB_CUSID);
|
|
|
|
|
- signParams.put("appid", SybConstants.SYB_APPID);
|
|
|
|
|
- signParams.put("version", "11");
|
|
|
|
|
- signParams.put("trxamt", String.valueOf(trxamt));
|
|
|
|
|
- signParams.put("reqsn", reqsn);
|
|
|
|
|
- signParams.put("randomstr", randomCode);
|
|
|
|
|
- signParams.put("signtype", SybConstants.SIGN_TYPE);
|
|
|
|
|
|
|
+ httpParams.put("sign", SybUtil.unionSign(httpParams, appkey, SybConstants.SIGN_TYPE));
|
|
|
|
|
|
|
|
- try {
|
|
|
|
|
- String appkey;
|
|
|
|
|
- if ("RSA".equals(SybConstants.SIGN_TYPE)) {
|
|
|
|
|
- appkey = SybConstants.SYB_RSACUSPRIKEY;
|
|
|
|
|
- } else if ("SM2".equals(SybConstants.SIGN_TYPE)) {
|
|
|
|
|
- appkey = SybConstants.SYB_SM2PPRIVATEKEY;
|
|
|
|
|
- } else {
|
|
|
|
|
- appkey = SybConstants.SYB_MD5_APPKEY;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- String signature = SybUtil.unionSign(signParams, appkey, SybConstants.SIGN_TYPE);
|
|
|
|
|
- System.out.println("签名类型: " + SybConstants.SIGN_TYPE);
|
|
|
|
|
- System.out.println("生成签名: " + signature);
|
|
|
|
|
-
|
|
|
|
|
- // 测试签名验证
|
|
|
|
|
- boolean verifyResult = SybUtil.validSign(signParams, appkey, SybConstants.SIGN_TYPE);
|
|
|
|
|
- System.out.println("签名验证结果: " + verifyResult);
|
|
|
|
|
-
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- System.out.println("签名测试异常: " + e.getMessage());
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ byte[] response = httpUtil.postParams(httpParams, true);
|
|
|
|
|
+ String responseStr = new String(response, "UTF-8");
|
|
|
|
|
+ System.out.println("HTTP请求响应: " + responseStr);
|
|
|
|
|
|
|
|
- // 测试5: HTTP连接工具测试
|
|
|
|
|
- System.out.println("\n=== 测试HTTP连接工具 ===");
|
|
|
|
|
- try {
|
|
|
|
|
- HttpConnectionUtil httpUtil = new HttpConnectionUtil(SybConstants.SYB_APIURL + "/unitorder/query");
|
|
|
|
|
- httpUtil.init();
|
|
|
|
|
-
|
|
|
|
|
- TreeMap<String, String> httpParams = new TreeMap<>();
|
|
|
|
|
- httpParams.put("appid", SybConstants.SYB_APPID);
|
|
|
|
|
- httpParams.put("cusid", SybConstants.SYB_CUSID);
|
|
|
|
|
- httpParams.put("version", "11");
|
|
|
|
|
- httpParams.put("reqsn", reqsn);
|
|
|
|
|
- httpParams.put("randomstr", SybUtil.getValidatecode(8));
|
|
|
|
|
- httpParams.put("signtype", SybConstants.SIGN_TYPE);
|
|
|
|
|
-
|
|
|
|
|
- String appkey = "MD5".equals(SybConstants.SIGN_TYPE) ? SybConstants.SYB_MD5_APPKEY :
|
|
|
|
|
- "RSA".equals(SybConstants.SIGN_TYPE) ? SybConstants.SYB_RSACUSPRIKEY :
|
|
|
|
|
- SybConstants.SYB_SM2PPRIVATEKEY;
|
|
|
|
|
-
|
|
|
|
|
- httpParams.put("sign", SybUtil.unionSign(httpParams, appkey, SybConstants.SIGN_TYPE));
|
|
|
|
|
-
|
|
|
|
|
- byte[] response = httpUtil.postParams(httpParams, true);
|
|
|
|
|
- String responseStr = new String(response, "UTF-8");
|
|
|
|
|
- System.out.println("HTTP请求响应: " + responseStr);
|
|
|
|
|
-
|
|
|
|
|
- httpUtil.destory();
|
|
|
|
|
-
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- System.out.println("HTTP连接测试异常: " + e.getMessage());
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ httpUtil.destory();
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
- System.out.println("测试过程中发生异常: " + e.getMessage());
|
|
|
|
|
- e.printStackTrace();
|
|
|
|
|
|
|
+ System.out.println("HTTP连接测试异常: " + e.getMessage());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- System.out.println("\n=== 测试完成 ===");
|
|
|
|
|
- System.out.println("注意: 部分测试可能因为没有真实的交易数据而失败,这是正常现象。");
|
|
|
|
|
- System.out.println("在实际使用时,请确保:");
|
|
|
|
|
- System.out.println("1. 配置正确的商户信息和密钥");
|
|
|
|
|
- System.out.println("2. 使用真实的交易订单号进行查询、退款、撤销操作");
|
|
|
|
|
- System.out.println("3. 在生产环境中移除测试代码");
|
|
|
|
|
|
|
+ */
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|