Bladeren bron

feat(unionPay): 集成银联商务小程序支付功能

新增银联支付工具类 UnionPayUtils,支持签名生成、参数构建及 POST 请求发送。
- 添加 Apache HttpClient 和 FastJSON2 依赖。- 实现签名验证和 URL 参数格式化方法。
- 提供测试用 main 方法,模拟支付请求调用。
- 更新类注释,增加文档链接信息。

refactor(order): 注释掉订单支付结果处理逻辑
wzq 4 uur geleden
bovenliggende
commit
a187f1b638

+ 1 - 1
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/impl/OrderServiceImpl.java

@@ -1181,7 +1181,7 @@ public class OrderServiceImpl implements IOrderService {
         if ((ObjectUtil.isNotEmpty(appOrder.getOrderOrFree()) && appOrder.getOrderOrFree() == 1) || appOrder.getPrice().compareTo(BigDecimal.ZERO)== 0) {
             payForm.setOrPayOrder(0);
         } else {
-            Map<String, String> result = payment(appOrder.getId());
+//            Map<String, String> result = payment(appOrder.getId());
 //            payForm.setParams(result);
 
             //发布任务到redission延迟队列(16分钟)

+ 124 - 13
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/pay/unionPay/UnionPayUtils.java

@@ -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;
     }
-
 }