|
@@ -2,14 +2,21 @@ package org.jeecg.modules.pay.unionPay;
|
|
|
|
|
|
import cn.hutool.core.date.DateUtil;
|
|
|
import cn.hutool.core.util.RandomUtil;
|
|
|
+import com.alibaba.fastjson2.JSONObject;
|
|
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
|
import com.fasterxml.jackson.databind.JsonNode;
|
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.apache.commons.lang.StringUtils;
|
|
|
+import org.apache.http.client.methods.CloseableHttpResponse;
|
|
|
+import org.apache.http.client.methods.HttpPost;
|
|
|
+import org.apache.http.entity.StringEntity;
|
|
|
+import org.apache.http.util.EntityUtils;
|
|
|
import org.jeecg.common.constant.CommonConstant;
|
|
|
|
|
|
-import java.io.UnsupportedEncodingException;
|
|
|
+import java.io.*;
|
|
|
+import java.net.HttpURLConnection;
|
|
|
+import java.net.URL;
|
|
|
import java.net.URLEncoder;
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
|
|
@@ -17,12 +24,15 @@ import java.text.SimpleDateFormat;
|
|
|
import java.util.*;
|
|
|
|
|
|
/**
|
|
|
- * @author wzq
|
|
|
+ * 银联商务API调用工具类
|
|
|
+ * @link <a href="http://dhjt.chinaums.com/online-pay-doc/html/mini/pay.html">银联商务大华捷通综合支付小程序支付接口文档</a>
|
|
|
+ * @author wangzq
|
|
|
+ * @date 2025/09/23
|
|
|
*/
|
|
|
@Slf4j
|
|
|
public class UnionPayUtils {
|
|
|
|
|
|
- public static void main(String[] args) throws UnsupportedEncodingException {
|
|
|
+ public static void main(String[] args) throws Exception {
|
|
|
String jsonString = "{\n" +
|
|
|
" \"id\": \"\",\n" +
|
|
|
" \"name\": \"test\",\n" +
|
|
@@ -34,13 +44,116 @@ public class UnionPayUtils {
|
|
|
String secretKey = "udik876ehjde32dU61edsxsf";
|
|
|
boolean isValid = verifySignature(jsonString, secretKey);
|
|
|
log.info("签名验证结果: {}", isValid ? "通过" : "不通过");
|
|
|
+
|
|
|
+ TreeMap<String, String> treeMap = new TreeMap<>();
|
|
|
+ treeMap.put("version", "20191031");
|
|
|
+ treeMap.put("msgId", "4217");
|
|
|
+ treeMap.put("msgType", "wx.appPreOrder");
|
|
|
+ treeMap.put("requestTimestamp", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
|
|
|
+ treeMap.put("expireTime", "");
|
|
|
+ treeMap.put("merOrderId", "4217" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()));
|
|
|
+ treeMap.put("mid", "8981200539800CH");
|
|
|
+ treeMap.put("tid", "01672395");
|
|
|
+ treeMap.put("instMid", "APPDEFAULT");
|
|
|
+ treeMap.put("attachedData", "");
|
|
|
+ treeMap.put("orderDesc", "");
|
|
|
+ treeMap.put("originalAmount", "");
|
|
|
+ treeMap.put("totalAmount", "1");
|
|
|
+ treeMap.put("notifyUrl", "https://dhjt-uat.chinaums.com/test/notify");
|
|
|
+ treeMap.put("signType", "SHA256");
|
|
|
+
|
|
|
+ String s = sendPost(treeMap);
|
|
|
+ log.info("响应结果: {}", s);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 银联支付接口地址
|
|
|
+ * 银联密钥
|
|
|
+ */
|
|
|
+ public static final String UNION_SECRET_KEY = "udik876ehjde32dU61edsxsf";
|
|
|
+ /**
|
|
|
+ * 银联统一请求接口地址
|
|
|
*/
|
|
|
public static final String UNION_PAY_URL = "https://dhjt-uat.chinaums.com/queryService/UmsWebPayPlugins";
|
|
|
|
|
|
+ /**
|
|
|
+ * 发送POST请求
|
|
|
+ *
|
|
|
+ * @param paramsMap 请求参数
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static String sendPost(Map<String, String> paramsMap)
|
|
|
+ throws Exception {
|
|
|
+ URL u = null;
|
|
|
+ HttpURLConnection con = null;
|
|
|
+
|
|
|
+ OutputStreamWriter osw = null;
|
|
|
+ BufferedReader br = null;
|
|
|
+
|
|
|
+ //排序参数并构建待签名字符串
|
|
|
+ String stringA = buildStringToSign(paramsMap, UNION_SECRET_KEY);
|
|
|
+
|
|
|
+ String localSign = generateSignature(stringA);
|
|
|
+ //localSign转大写
|
|
|
+ String sign = localSign.toUpperCase();
|
|
|
+ //添加参数sign
|
|
|
+ paramsMap.put("sign", sign);
|
|
|
+ String params = formatUrlParam(paramsMap);
|
|
|
+ log.info("请求地址连接:{},参数:{}", UNION_PAY_URL,params);
|
|
|
+
|
|
|
+ try {
|
|
|
+ u = new URL(UNION_PAY_URL);
|
|
|
+ con = (HttpURLConnection) u.openConnection();
|
|
|
+ con.setConnectTimeout(30000);
|
|
|
+ con.setReadTimeout(700000);
|
|
|
+ con.setRequestMethod("POST");
|
|
|
+ con.setDoOutput(true);
|
|
|
+ con.setDoInput(true);
|
|
|
+ con.setUseCaches(false);
|
|
|
+ con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
|
|
|
+ con.setRequestProperty("Charset", "UTF-8");
|
|
|
+ osw = new OutputStreamWriter(con.getOutputStream(), StandardCharsets.UTF_8);
|
|
|
+ osw.write(params);
|
|
|
+ osw.flush();
|
|
|
+ } catch (Exception e) {
|
|
|
+ throw new Exception();
|
|
|
+ } finally {
|
|
|
+ try {
|
|
|
+ if (osw != null) {
|
|
|
+ osw.close();
|
|
|
+ }
|
|
|
+ } catch (IOException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ StringBuffer buffer = new StringBuffer();
|
|
|
+ try {
|
|
|
+ br = new BufferedReader(new InputStreamReader(con.getInputStream(),
|
|
|
+ StandardCharsets.UTF_8));
|
|
|
+ String temp;
|
|
|
+ while ((temp = br.readLine()) != null) {
|
|
|
+ buffer.append(temp);
|
|
|
+ buffer.append("\n");
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ throw new Exception();
|
|
|
+ } finally {
|
|
|
+ try {
|
|
|
+ if (osw != null) {
|
|
|
+ osw.close();
|
|
|
+ }
|
|
|
+ if (br != null) {
|
|
|
+ br.close();
|
|
|
+ }
|
|
|
+ if (con != null) {
|
|
|
+ con.disconnect();
|
|
|
+ }
|
|
|
+ } catch (Exception ex) {
|
|
|
+ ex.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return buffer.toString();
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 验证JSON字符串的签名
|
|
|
* @param jsonString 待验证的JSON字符串
|
|
@@ -187,11 +300,9 @@ public class UnionPayUtils {
|
|
|
* 遍历集合M,取出全部的参数key,将参数key字典序排列,根据排序后的参数key获取对应的value,将非空的参数key和参数value用"="拼接,多个参数之间用"&"拼接
|
|
|
*
|
|
|
* @param param 参数
|
|
|
- * @param encode 编码
|
|
|
- * @param isLower 是否小写
|
|
|
* @return
|
|
|
*/
|
|
|
- public static String formatUrlParam(Map<String, String> param, String encode, boolean isLower) {
|
|
|
+ public static String formatUrlParam(Map<String, String> param) {
|
|
|
String params = "";
|
|
|
|
|
|
try {
|
|
@@ -206,13 +317,14 @@ public class UnionPayUtils {
|
|
|
if (StringUtils.isNotBlank(item.getKey())) {
|
|
|
String key = item.getKey();
|
|
|
String val = item.getValue();
|
|
|
- val = URLEncoder.encode(val, encode);
|
|
|
- if (isLower) {
|
|
|
- sb.append(key.toLowerCase()).append("=").append(val);
|
|
|
- } else {
|
|
|
+ val = URLEncoder.encode(val, StandardCharsets.UTF_8);
|
|
|
+ // 跳过空值参数
|
|
|
+ if (val != null && !val.trim().isEmpty()) {
|
|
|
+ if (sb.length() > 0) {
|
|
|
+ sb.append("&");
|
|
|
+ }
|
|
|
sb.append(key).append("=").append(val);
|
|
|
}
|
|
|
- sb.append("&");
|
|
|
}
|
|
|
}
|
|
|
// 删除末尾多余的&号和空格
|
|
@@ -225,5 +337,4 @@ public class UnionPayUtils {
|
|
|
}
|
|
|
return params;
|
|
|
}
|
|
|
-
|
|
|
}
|