From 6acf6357094588946b5528f1ef1ed84a0f1037fd Mon Sep 17 00:00:00 2001
From: huliguo <2023611923@qq.com>
Date: 星期五, 13 六月 2025 19:45:27 +0800
Subject: [PATCH] 小程序收付款

---
 ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/wx/HttpUtil.java                |   98 +
 ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/wechat/PayMoneyUtil.java        | 1295 ++++++++++++++++++++
 ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/wx/vo/PayResult.java            |   16 
 ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/wx/WechatPayService.java        |  742 +++++++++++
 ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/util/payment/wx/XMLUtil.java                 |   52 
 ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/wx/vo/UnifiedOrderResult.java   |   38 
 ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/OrderController.java              |   61 
 ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/OrderServiceImpl.java           |  207 ++
 ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/util/payment/wx/WechatPayService.java        |  734 +++++++++++
 ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/wx/WechatPayConfig.java         |   26 
 ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/util/payment/wx/PayResult.java               |   16 
 ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/service/impl/AppUserServiceImpl.java     |   10 
 ruoyi-service/pom.xml                                                                                |    2 
 ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/domain/ShopWithdraw.java                 |    2 
 ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/service/impl/ShopServiceImpl.java            |   10 
 ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/wx/XMLUtil.java                 |   52 
 ruoyi-service/ruoyi-order/pom.xml                                                                    |   21 
 ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/ShopWithdrawController.java       |   60 
 ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/PaymentUtil.java                |   10 
 ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/OrderService.java                    |    8 
 ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/util/payment/wx/WechatPayConfig.java         |   26 
 ruoyi-service/ruoyi-other/pom.xml                                                                    |   17 
 ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/util/payment/wx/RefundCallbackResult.java    |   38 
 ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/util/payment/wx/HttpUtil.java                |   99 +
 ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/wx/vo/RefundCallbackResult.java |   38 
 25 files changed, 3,557 insertions(+), 121 deletions(-)

diff --git a/ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/domain/ShopWithdraw.java b/ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/domain/ShopWithdraw.java
index d19a884..b00313e 100644
--- a/ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/domain/ShopWithdraw.java
+++ b/ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/domain/ShopWithdraw.java
@@ -106,7 +106,7 @@
     @TableField("receiverAccountType")
     private Integer receiverAccountType;
 
-    @ApiModelProperty("收款账户联行号")
+    @ApiModelProperty("收款方开户行编号")
     @TableField("receiverBankChannelNo")
     private String receiverBankChannelNo;
 
diff --git a/ruoyi-service/pom.xml b/ruoyi-service/pom.xml
index 7d28d6e..9efe6e9 100644
--- a/ruoyi-service/pom.xml
+++ b/ruoyi-service/pom.xml
@@ -32,7 +32,7 @@
         <dependency>
             <groupId>cn.hutool</groupId>
             <artifactId>hutool-all</artifactId>
-            <version>5.0.3</version>
+            <version>5.8.25</version>
         </dependency>
         <!--log4j-->
         <dependency>
diff --git a/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/service/impl/AppUserServiceImpl.java b/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/service/impl/AppUserServiceImpl.java
index e2a7611..d71fa38 100644
--- a/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/service/impl/AppUserServiceImpl.java
+++ b/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/service/impl/AppUserServiceImpl.java
@@ -136,6 +136,10 @@
 			appUser.setDelFlag(false);
 			appUser.setCreateTime(LocalDateTime.now());
 			this.save(appUser);
+		}else {
+			//从订单导入的,将openid导入
+			appUser.setWxOpenid(openid);
+			this.updateById(appUser);
 		}
 		//账户被冻结,给出提示
 		if(2 == appUser.getStatus()){
@@ -175,7 +179,7 @@
 		//查询用户是否注册,没有注册则跳转到注册页面
 		AppUser appUser = this.getOne(new LambdaQueryWrapper<AppUser>().eq(AppUser::getPhone, mobileLogin.getPhone())
 				.ne(AppUser::getStatus, 3).eq(AppUser::getDelFlag, 0));
-		if(null == appUser){
+		if(null == appUser||null ==appUser.getWxOpenid()){
 			LoginVo loginVo = new LoginVo();
 			loginVo.setSkipPage(2);
 			loginVo.setPhone(mobileLogin.getPhone());
@@ -304,8 +308,8 @@
 		if(null != appUser1 && StringUtils.isNotEmpty(appUser1.getWxOpenid())){
 			return R.fail("手机号已注册,请直接登录!");
 		}
-		if(null != appUser1 && appUser1.getStatus() == 1){
-			return R.fail("手机号已注册,请直接登录!");
+		if(null != appUser1 && appUser1.getStatus() == 2){
+			return R.fail("该手机号已被冻结!");
 		}
 
 		String avatar = registerAccount.getAvatar();
diff --git a/ruoyi-service/ruoyi-order/pom.xml b/ruoyi-service/ruoyi-order/pom.xml
index 1d2c7a2..1123cfc 100644
--- a/ruoyi-service/ruoyi-order/pom.xml
+++ b/ruoyi-service/ruoyi-order/pom.xml
@@ -15,6 +15,12 @@
     </description>
 
     <dependencies>
+        <dependency>
+            <groupId>com.alipay.sdk</groupId>
+            <artifactId>alipay-sdk-java</artifactId>
+            <version>4.8.10.ALL</version>
+        </dependency>
+
         <!--网易邮件-->
         <dependency>
             <groupId>javax.mail</groupId>
@@ -170,6 +176,21 @@
             <artifactId>geodesy</artifactId>
             <version>1.1.3</version>
         </dependency>
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-http</artifactId>
+            <version>5.8.25</version>
+        </dependency>
+        <dependency>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcprov-jdk15on</artifactId>
+            <version>1.70</version>
+        </dependency>
+        <dependency>
+            <groupId>dom4j</groupId>
+            <artifactId>dom4j</artifactId>
+            <version>1.6.1</version>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/OrderController.java b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/OrderController.java
index c08a457..9594278 100644
--- a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/OrderController.java
+++ b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/OrderController.java
@@ -24,6 +24,9 @@
 import com.ruoyi.order.service.OrderService;
 import com.ruoyi.order.util.payment.model.RefundCallbackResult;
 import com.ruoyi.order.util.payment.model.UniPayCallbackResult;
+import com.ruoyi.order.util.payment.wechat.PayMoneyUtil;
+import com.ruoyi.order.util.payment.wx.WechatPayService;
+import com.ruoyi.order.util.payment.wx.vo.PayResult;
 import com.ruoyi.order.util.vo.MapTrackKD100Vo;
 import com.ruoyi.order.util.vo.ShopAnalysisVO;
 import com.ruoyi.order.vo.*;
@@ -37,10 +40,12 @@
 import com.ruoyi.system.api.model.LoginUser;
 import io.swagger.annotations.*;
 import org.apache.ibatis.annotations.Param;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.util.CollectionUtils;
 import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.io.PrintWriter;
@@ -82,7 +87,10 @@
 
     @Resource
     private ShopClient shopClient;
-
+    @Resource
+    private PayMoneyUtil payMoneyUtil;
+    @Resource
+    private WechatPayService wechatPayService;
 
 
     @ResponseBody
@@ -104,12 +112,19 @@
      * 订单支付回调通知
      */
     @ResponseBody
-    @GetMapping("/orderPaymentCallback")
-    public void orderPaymentCallback(UniPayCallbackResult uniPayCallbackResult, HttpServletResponse response){
-        String jsonString = JSONObject.toJSONString(uniPayCallbackResult);
+    @PostMapping("/orderPaymentCallback")
+    public void orderPaymentCallback(HttpServletRequest request, HttpServletResponse response){
+//        String jsonString = JSONObject.toJSONString(uniPayCallbackResult);
+        System.err.println("1111111111111");
+        PayResult  payResult= null;
+        try {
+            payResult = wechatPayService.processNotify(request);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
         System.out.println("1111111111111111111111");
-        System.out.println(jsonString);
-        R callback = orderService.orderPaymentCallback(uniPayCallbackResult);
+//        System.out.println(jsonString);
+        R callback = orderService.orderPaymentCallback(payResult);
         if(callback.getCode() == 200){
             response.setStatus(200);
             PrintWriter out = null;
@@ -406,26 +421,16 @@
 */
     /**
      * 订单取消支付回退
-     *
-     * @param refundCallbackResult
-     * @param response
-     * @return
      */
     @ResponseBody
-    @GetMapping("/refundPayMoneyCallback")
-    public void refundPayMoneyCallback(RefundCallbackResult refundCallbackResult, HttpServletResponse response) {
-        R callback = orderService.refundPayMoneyCallback(refundCallbackResult);
+    @PostMapping("/refundPayMoneyCallback")
+    public String refundPayMoneyCallback( @RequestBody(required = false) String xmlData) {
+        R callback = orderService.refundPayMoneyCallback(xmlData);
         if (callback.getCode() == 200) {
-            response.setStatus(200);
-            PrintWriter out = null;
-            try {
-                out = response.getWriter();
-            } catch (IOException e) {
-                throw new RuntimeException(e);
-            }
-            out.println("success");
-            out.flush();
-            out.close();
+          return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
+        }else {
+            System.err.println("支付回退错误:"+callback.getMsg());
+            return "<xml><return_code><![CDATA[FAIL]]></return_code></xml>";
         }
     }
 
@@ -778,5 +783,15 @@
         return R.ok(orderService.getMap(queryWrapper));
     }
 
+    /**
+     * 获取商户RSA加密公钥
+     */
+
+    @GetMapping("/getRsaPublicKey")
+    public R<Void> getRsaPublicKey(){
+        wechatPayService.getRsaPublicKey();
+        return R.ok();
+    }
+
 }
 
diff --git a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/OrderService.java b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/OrderService.java
index 0ea0d30..65464b7 100644
--- a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/OrderService.java
+++ b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/OrderService.java
@@ -7,12 +7,16 @@
 import com.ruoyi.order.model.Order;
 import com.ruoyi.order.util.payment.model.RefundCallbackResult;
 import com.ruoyi.order.util.payment.model.UniPayCallbackResult;
+import com.ruoyi.order.util.payment.wx.vo.PayResult;
 import com.ruoyi.order.vo.*;
 import org.springframework.web.multipart.MultipartFile;
 
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.util.List;
+import java.util.Map;
 
 /**
  * <p>
@@ -72,7 +76,7 @@
      * 取消订单后回调处理
      * @return
      */
-    R refundPayMoneyCallback(RefundCallbackResult refundCallbackResult);
+    R refundPayMoneyCallback(String xmlData);
 
 
     /**
@@ -121,7 +125,7 @@
     /**
      * 订单支付回调通知
      */
-    R orderPaymentCallback(UniPayCallbackResult uniPayCallbackResult);
+    R orderPaymentCallback(PayResult payResult);
     /**
      * 定时任务关闭订单
      */
diff --git a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/OrderServiceImpl.java b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/OrderServiceImpl.java
index f632abb..948d8fa 100644
--- a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/OrderServiceImpl.java
+++ b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/OrderServiceImpl.java
@@ -33,6 +33,11 @@
 import com.ruoyi.order.util.payment.PaymentUtil;
 import com.ruoyi.order.util.payment.model.*;
 
+import com.ruoyi.order.util.payment.wechat.PayMoneyUtil;
+import com.ruoyi.order.util.payment.wx.WechatPayConfig;
+import com.ruoyi.order.util.payment.wx.WechatPayService;
+import com.ruoyi.order.util.payment.wx.vo.PayResult;
+import com.ruoyi.order.util.payment.wx.vo.RefundCallbackResult;
 import com.ruoyi.order.vo.*;
 import com.ruoyi.other.api.domain.*;
 import com.ruoyi.other.api.feignClient.*;
@@ -52,6 +57,8 @@
 import org.springframework.util.CollectionUtils;
 
 import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
@@ -122,6 +129,13 @@
     private RegionClient regionClient;
     @Resource
     private ApplicationEventPublisher applicationEventPublisher;
+
+
+    @Resource
+    private PayMoneyUtil payMoneyUtil;
+
+    @Resource
+    private WechatPayService wechatPayService;
 
 
     @Override
@@ -433,10 +447,16 @@
         BigDecimal paymentAmount = order.getPaymentAmount();
         if (BigDecimal.ZERO.compareTo(order.getPaymentAmount()) < 0) {//支付的金额是否大于0
             //微信退款
-            RefundResult refund = PaymentUtil.refund(order.getOrderNumber(), "R" + order.getOrderNumber(), paymentAmount.doubleValue(), "/order/order/refundPayMoneyCallback");
-            if (!"100".equals(refund.getRa_Status())) {
-                return R.fail(refund.getRc_CodeMsg());//退款失败
+            Map<String,String> map = wechatPayService.refund(order.getOrderNumber(), order.getOrderNumber(), order.getPaymentAmount().toString(), order.getPaymentAmount().toString(), "退款", "/order/order/refundPayMoneyCallback");
+
+//            RefundResult refund = PaymentUtil.refund(order.getOrderNumber(), "R" + order.getOrderNumber(), paymentAmount.doubleValue(), "/order/order/refundPayMoneyCallback");
+            if (!"SUCCESS".equals(map.get("return_code"))) {
+                return R.fail(map.get("return_msg"));//退款失败
             }
+            //这里申请成功后先返回,等待微信退款成功再返回积分这些
+            order.setRefundStatus(1);
+            this.updateById(order);
+            return R.ok();
         }
         //退款成功再回退积分
         AppUser appUser = appUserClient.getAppUserById(order.getAppUserId());
@@ -516,16 +536,90 @@
      * @return
      */
     @Override
-    public R refundPayMoneyCallback(RefundCallbackResult refundCallbackResult) {
-        String code = refundCallbackResult.getR3_RefundOrderNo().substring(1);
-        Order order = this.getOne(new LambdaQueryWrapper<Order>().eq(Order::getOrderNumber, code));
-        if (null == order || order.getPayStatus() == 1 || order.getOrderStatus() == 6) {
+    public R refundPayMoneyCallback(String xmlData) {
+
+        RefundCallbackResult result = wechatPayService.processRefundCallback(xmlData);
+    if (!result.isSuccess()) {
+        return R.fail(result.getMsg());
+    }
+
+        Order order = this.getOne(new LambdaQueryWrapper<Order>().eq(Order::getOrderNumber, result.getOrderNo()));
+        if (null == order || order.getPayStatus() == 1 || order.getRefundStatus() == 2) {
             return R.ok();
         }
-        order.setRefundCode(refundCallbackResult.getR5_RefundTrxNo());
+//        order.setRefundCode(refundCallbackResult.getR5_RefundTrxNo());
+        order.setRefundCode(result.getRefundNo());
         order.setRefundStatus(2);
         order.setRefundTime(LocalDateTime.now());
         this.updateById(order);
+
+        //退款成功再回退积分
+        AppUser appUser = appUserClient.getAppUserById(order.getAppUserId());
+        if (order.getPoint()>0) {
+            if(null==appUser.getCancelPoint()){
+                appUser.setCancelPoint(0);
+            }
+            //返回订单抵扣积分
+            Integer historicalPoint = appUser.getAvailablePoint();
+            Integer availablePoint = appUser.getAvailablePoint() + order.getPoint();//可用积分
+            Integer cancelPoint = appUser.getCancelPoint() + order.getPoint();//取消订单积分
+
+            appUser.setAvailablePoint(availablePoint);
+            appUser.setCancelPoint(cancelPoint);
+            appUser.setTotalPoint(appUser.getTotalPoint() + order.getPoint());
+            appUserClient.editAppUserById(appUser);
+            //构建积分流水
+            UserPoint userPoint = new UserPoint();
+            userPoint.setType(16);//取消订单
+            userPoint.setHistoricalPoint(historicalPoint);
+            userPoint.setVariablePoint(order.getPoint());
+            userPoint.setBalance(availablePoint);
+            userPoint.setCreateTime(LocalDateTime.now());
+            userPoint.setAppUserId(order.getAppUserId());
+            userPoint.setObjectId(order.getId());
+            userPointClient.saveUserPoint(userPoint);
+        }
+
+        order.setRefundStatus(2);
+        order.setRefundTime(LocalDateTime.now());
+
+        //商品销售数量
+        OrderGood orderGood = orderGoodService.getOne(new LambdaQueryWrapper<OrderGood>().eq(OrderGood::getOrderId, order.getId()));
+        goodsClient.editGoodsNum(orderGood.getGoodsId(), -1);
+        //获取商品json
+        Goods good = JSON.parseObject(orderGood.getGoodJson(), Goods.class);
+        GoodsSeckill goodsSeckill = JSON.parseObject(orderGood.getSeckillJson(), GoodsSeckill.class);
+
+        //门店减少冻结资金 即减少余额, 冻结资金=余额-可用资金
+        Shop shop = shopClient.getShopById(order.getShopId()).getData();
+
+        BigDecimal historicalBalance=shop.getBalance();//历史余额
+        BigDecimal variableAmount=BigDecimal.ZERO;//变动金额
+        if (null != goodsSeckill) {
+            variableAmount=goodsSeckill.getSellingPrice();
+        }else {
+            variableAmount=good.getSellingPrice();
+        }
+
+        BigDecimal balance=shop.getBalance().subtract(variableAmount);//变动后余额
+
+        shop.setBalance(balance);
+        shopClient.updateShop(shop);
+
+        //门店余额流水记录
+        ShopBalanceStatement shopBalanceStatement = new ShopBalanceStatement();
+        shopBalanceStatement.setShopId(shop.getId());
+        shopBalanceStatement.setShopName(shop.getName());
+        shopBalanceStatement.setShopManagerName(shop.getShopManager());
+        shopBalanceStatement.setPhone(shop.getPhone());
+        shopBalanceStatement.setType(6);//变更类型,订单退款
+        shopBalanceStatement.setHistoricalBalance(historicalBalance);
+        shopBalanceStatement.setVariableAmount(variableAmount);
+        shopBalanceStatement.setCreateTime(LocalDateTime.now());
+        shopBalanceStatement.setBalance(balance);
+        shopBalanceStatement.setCreateUserId(appUser.getId());
+        shopBalanceStatement.setObjectId(order.getId());
+        shopBalanceStatementClient.saveShopBalanceStatement(shopBalanceStatement);
         return R.ok();
     }
 
@@ -913,49 +1007,54 @@
         if ( BigDecimal.ZERO.compareTo(paymentMoney) < 0){
             //调起微信支付
             String goodsNames = goods.getName();
-            UniPayResult uniPayResult = PaymentUtil.uniPay(order.getOrderNumber(), paymentMoney.doubleValue(),  "购买单品商品",
-                    goodsNames, "", "/order/order/orderPaymentCallback", appUser.getWxOpenid(), null);
-            if(null == uniPayResult || !"100".equals(uniPayResult.getRa_Code())){
-                //支付失败,积分回退 ,删除订单
-                //检查是否先有过积分抵扣了,是的话要返回订单已抵扣的积分,以及用户积分流水的删除
-                if (order.getPoint()>0) {
-                    //返回订单抵扣积分
-                    AppUser appUser2 = appUserClient.getAppUserById(order.getAppUserId());
-                    Integer availablePoint = appUser2.getAvailablePoint();//可用积分
-                    Integer variablePoint = order.getPoint();//变动积分
-                    Integer balance = appUser2.getAvailablePoint() + order.getPoint();//变动后积分
-                    Integer cancelPoint = appUser2.getCancelPoint() + order.getPoint();//取消订单积分
-                    appUser2.setAvailablePoint(availablePoint);
-                    appUser2.setCancelPoint(cancelPoint);
-                    appUser2.setTotalPoint(appUser2.getTotalPoint() + order.getPoint());
+            try {
+                R r = wechatPayService.unifiedOrder(order.getId().toString(), order.getOrderNumber(), paymentMoney.toString(), "购买单品商品",appUser.getWxOpenid(),"/order/order/orderPaymentCallback");
+                if (null == r || 200 != r.getCode()){
+                    //支付失败,积分回退 ,删除订单
+                    //检查是否先有过积分抵扣了,是的话要返回订单已抵扣的积分,以及用户积分流水的删除
+                    if (order.getPoint()>0) {
+                        //返回订单抵扣积分
+                        AppUser appUser2 = appUserClient.getAppUserById(order.getAppUserId());
+                        Integer availablePoint = appUser2.getAvailablePoint();//可用积分
+                        Integer variablePoint = order.getPoint();//变动积分
+                        Integer balance = appUser2.getAvailablePoint() + order.getPoint();//变动后积分
+                        Integer cancelPoint = appUser2.getCancelPoint() + order.getPoint();//取消订单积分
+                        appUser2.setAvailablePoint(availablePoint);
+                        appUser2.setCancelPoint(cancelPoint);
+                        appUser2.setTotalPoint(appUser2.getTotalPoint() + order.getPoint());
 
-                    //构建积分流水记录
-                    UserPoint userPoint = new UserPoint();
-                    userPoint.setType(16);//取消订单
-                    userPoint.setHistoricalPoint(availablePoint);
-                    userPoint.setVariablePoint(variablePoint);
-                    userPoint.setBalance(balance);
-                    userPoint.setCreateTime(LocalDateTime.now());
-                    userPoint.setAppUserId(appUser2.getId());
-                    userPoint.setObjectId(order.getId());
-                    userPointClient.saveUserPoint(userPoint);
+                        //构建积分流水记录
+                        UserPoint userPoint = new UserPoint();
+                        userPoint.setType(16);//取消订单
+                        userPoint.setHistoricalPoint(availablePoint);
+                        userPoint.setVariablePoint(variablePoint);
+                        userPoint.setBalance(balance);
+                        userPoint.setCreateTime(LocalDateTime.now());
+                        userPoint.setAppUserId(appUser2.getId());
+                        userPoint.setObjectId(order.getId());
+                        userPointClient.saveUserPoint(userPoint);
 
-                    appUserClient.editAppUserById(appUser2);
+                        appUserClient.editAppUserById(appUser2);
 
+
+                    }
                     //删除订单
                     order.setDelFlag(1);
                     orderMapper.updateById(order);
+                    //返回报错信息
+                    return R.fail(null == r ? "支付失败" : r.getMsg());
                 }
-                //返回报错信息
-                return R.fail(null == uniPayResult ? "支付失败" : uniPayResult.getRb_CodeMsg());
+            /*if(null == uniPayResult || !"100".equals(uniPayResult.getRa_Code())){
+
+            }*/
+                //将支付数据添加到redis队列中,便于定时任务去校验是否完成支付,没有完成支付支付,15分钟后关闭订单。
+                long second = LocalDateTime.now().plusMinutes(15).toEpochSecond(ZoneOffset.UTC);
+                redisTemplate.opsForZSet().add("OrderPayment", order.getId(), second);
+                return r;
+            }catch (Exception e){
+                e.printStackTrace();
             }
-            String rc_result = uniPayResult.getRc_Result();
-            JSONObject jsonObject = JSON.parseObject(rc_result);
-            jsonObject.put("orderId", order.getId().toString());
-            //将支付数据添加到redis队列中,便于定时任务去校验是否完成支付,没有完成支付支付,15分钟后关闭订单。
-            long second = LocalDateTime.now().plusMinutes(15).toEpochSecond(ZoneOffset.UTC);
-            redisTemplate.opsForZSet().add("OrderPayment", order.getOrderNumber(), second);
-            return R.ok(jsonObject.toJSONString());
+
 
         }
 
@@ -993,15 +1092,18 @@
         shopBalanceStatement.setCreateUserId(appUser.getId());
         shopBalanceStatement.setObjectId(order.getId());
         shopBalanceStatementClient.saveShopBalanceStatement(shopBalanceStatement);
-        return R.ok(order.getId().toString());
+        Map<String, String> payParams = new HashMap<>();
+        payParams.put("payMethod","3");//给前端标识 3-不需要调微信支付
+        payParams.put("orderId",order.getId().toString());
+        return R.ok(JSON.toJSONString(payParams));
     }
 
     /**
-     * 订单支付回调通知
+     * 订单支付回调 处理业务逻辑
      */
     @Override
-    public R orderPaymentCallback(UniPayCallbackResult uniPayCallbackResult) {
-        Order order = orderMapper.selectOne(new LambdaQueryWrapper<Order>().eq(Order::getOrderNumber, uniPayCallbackResult.getR2_OrderNo()));
+    public R orderPaymentCallback(PayResult payResult) {
+        Order order = orderMapper.selectOne(new LambdaQueryWrapper<Order>().eq(Order::getOrderNumber, payResult.getOrderNumber()));
         if(null == order || order.getPayStatus() == 2){
             return R.ok();
         }
@@ -1017,7 +1119,7 @@
         order.setPayStatus(2);
         //待使用
         order.setOrderStatus(3);
-        String r7TrxNo = uniPayCallbackResult.getR9_BankTrxNo();
+        String r7TrxNo = payResult.getTransactionId();
         order.setSerialNumber(r7TrxNo);
         orderMapper.updateById(order);
 
@@ -1068,18 +1170,17 @@
         long second = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC);
         Set<String> orderPayment = redisTemplate.opsForZSet().rangeByScore("OrderPayment", 0, second);
         if(orderPayment.size() > 0){
-            List<Order> list = orderMapper.selectList(new LambdaQueryWrapper<Order>().in(Order::getOrderNumber, orderPayment));
+            List<Order> list = orderMapper.selectList(new LambdaQueryWrapper<Order>().in(Order::getId, orderPayment));
             for (Order order : list) {
                 if(null == order || order.getPayStatus() != 1){
                     redisTemplate.opsForZSet().remove("OrderPayment", order.getOrderNumber());
                     continue;
                 }
                 //开始执行关闭订单操作
-                CloseOrderResult closeOrderResult = PaymentUtil.closeOrder(order.getOrderNumber());
-                if((null == closeOrderResult || !closeOrderResult.getRa_Status().equals("100")) &&
-                        Arrays.asList("0", "4", "101", "10080000", "10080002", "10083004", "10083005").contains(closeOrderResult.getRb_Code())){
+                Map<String, String> map = wechatPayService.closeOrder(order.getOrderNumber());
+                if((null == map || !map.get("return_code").equals("SUCCESS"))){
                     redisTemplate.opsForZSet().add("OrderPayment", order.getOrderNumber(), 0);
-                    log.error("关闭订单失败:{}---->{}", order.getOrderNumber(), JSON.toJSONString(closeOrderResult));
+                    log.error("关闭订单失败:{}---->{}", order.getOrderNumber(), map.get("return_msg"));
                 }
                 redisTemplate.opsForZSet().remove("OrderPayment", order.getOrderNumber());
                 //关闭订单后,检查是否先有过积分抵扣了,是的话要返回订单已抵扣的积分,以及用户积分流水的删除, 删除订单
diff --git a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/PaymentUtil.java b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/PaymentUtil.java
index 9d0ae2a..776a2c0 100644
--- a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/PaymentUtil.java
+++ b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/PaymentUtil.java
@@ -22,7 +22,7 @@
 	/**
 	 * 商户密钥
 	 */
-	private static final String key = "a2369875124965782f148539657823152";
+	private static final String key = "ss369875124965782f148539657826321";
 	/**
 	 * 商户号
 	 */
@@ -280,10 +280,10 @@
 	
 	
 	public static void main(String[] args) {
-//		UniPayResult uniPayResult = PaymentUtil.uniPay("852963742", 0.01D, "测试商品", "这是用于对接支付测试的商品描述",
-//				"", "/order/shopping-cart/shoppingCartPaymentCallback", "ooOrs64zHLuInkZ_GF0LpIN9_Rxc", "777168500885852");
-//		PaymentUtil.queryOrder("852963742");
-//		PaymentUtil.closeOrder("852963742");
+		UniPayResult uniPayResult = PaymentUtil.uniPay("852963742", 0.01D, "测试商品", "这是用于对接支付测试的商品描述",
+				"", "/order/shopping-cart/shoppingCartPaymentCallback", "ooOrs64zHLuInkZ_GF0LpIN9_Rxc", "777168500885852");
+		PaymentUtil.queryOrder("852963742");
+		PaymentUtil.closeOrder("852963742");
 		
 	}
 }
diff --git a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/wechat/PayMoneyUtil.java b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/wechat/PayMoneyUtil.java
new file mode 100644
index 0000000..6948dc8
--- /dev/null
+++ b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/wechat/PayMoneyUtil.java
@@ -0,0 +1,1295 @@
+package com.ruoyi.order.util.payment.wechat;
+
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
+import cn.hutool.http.HttpUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.alipay.api.AlipayApiException;
+import com.alipay.api.AlipayClient;
+import com.alipay.api.CertAlipayRequest;
+import com.alipay.api.DefaultAlipayClient;
+import com.alipay.api.domain.AlipayTradeAppPayModel;
+import com.alipay.api.domain.AlipayTradeRefundModel;
+import com.alipay.api.request.*;
+import com.alipay.api.response.*;
+import com.ruoyi.common.core.domain.R;
+import com.ruoyi.order.util.payment.MD5AndKL;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.dom4j.Document;
+import org.dom4j.DocumentException;
+import org.dom4j.Element;
+import org.dom4j.io.SAXReader;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Component;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.SecretKeySpec;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.servlet.http.HttpServletRequest;
+import java.io.*;
+import java.math.BigDecimal;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.security.*;
+import java.util.*;
+
+/**
+ * 第三方支付工具类
+ */
+@Component
+public class PayMoneyUtil {
+
+    @Value("${alipay.appid}")
+    private String aliAppid;//支付宝appid
+
+    @Value("${alipay.appPrivateKey}")
+    private String appPrivateKey;//支付宝开发者应用私钥
+
+    @Value("${alipay.alipayPublicKey}")
+    private String alipayPublicKey;//支付宝应用公钥
+
+    @Value("${alipay.alipay_public_key}")
+    private String alipay_public_key;//支付宝支付公钥
+
+    @Value("${wx.appid}")
+    private String appid;//微信appid
+
+    @Value("${wx.appletsAppid}")
+    private String appletsAppid;//微信小程序appid
+
+    @Value("${wx.mchId}")
+    private String mchId;//微信商户号
+
+    @Value("${wx.key}")
+    private String key;//微信商户号
+
+    @Value("${wx.callbackPath}")
+    private String callbackPath;//支付回调网关地址
+
+    @Value(("${wx.certPath}"))
+    private String certPath;//微信证书路径
+
+    private String app_cert_path = "C:/cert/alipay/driver/app_cert_path.crt";//应用公钥证书路径
+
+    private String alipay_cert_path = "C:/cert/alipay/driver/alipay_cert_path.crt";//支付宝公钥证书文件路径
+
+    private String alipay_root_cert_path = "C:/cert/alipay/driver/alipay_root_cert_path.crt";//支付宝CA根证书文件路径
+
+
+
+    private Map<String, JSONObject> order = new HashMap<>();//存储支付订单用于主动查询支付结果
+
+
+    /**
+     * 支付宝支付
+     */
+    public R alipay(String body, String subject, String passbackParams, String outTradeNo, String amount, String notifyUrl){
+        //构造client
+        CertAlipayRequest certAlipayRequest = new CertAlipayRequest ();
+        //设置网关地址
+        certAlipayRequest.setServerUrl("https://openapi.alipay.com/gateway.do");
+        //设置应用Id
+        certAlipayRequest.setAppId(aliAppid);
+        //设置应用私钥
+        certAlipayRequest.setPrivateKey(appPrivateKey);
+        //设置请求格式,固定值json
+        certAlipayRequest.setFormat("json");
+        //设置字符集
+        certAlipayRequest.setCharset("UTF-8");
+        //设置签名类型
+        certAlipayRequest.setSignType("RSA2");
+        //设置应用公钥证书路径
+        certAlipayRequest.setCertPath(app_cert_path);
+        //设置支付宝公钥证书路径
+        certAlipayRequest.setAlipayPublicCertPath(alipay_cert_path);
+        //设置支付宝根证书路径
+        certAlipayRequest.setRootCertPath(alipay_root_cert_path);
+        //构造client
+        AlipayClient alipayClient = null;
+        try {
+            alipayClient = new DefaultAlipayClient(certAlipayRequest);
+        } catch (AlipayApiException e) {
+            e.printStackTrace();
+        }
+        //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
+        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest ();
+        //SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
+        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel ();
+        model.setBody(body);
+        model.setSubject (subject);
+        model.setOutTradeNo (outTradeNo);
+        model.setTimeoutExpress ("30m" );
+        model.setTotalAmount (amount);
+        model.setProductCode ( "QUICK_MSECURITY_PAY" );
+        model.setPassbackParams(passbackParams);//自定义参数
+        request.setBizModel ( model );
+        request.setNotifyUrl (callbackPath + notifyUrl);
+        try  {
+            //这里和普通的接口调用不同,使用的是sdkExecute
+            AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
+            System.out.println(response.getBody());//就是orderString 可以直接给客户端请求,无需再做处理。
+            return R.ok(response.getBody());
+        }  catch (AlipayApiException e ) {
+            e.printStackTrace();
+        }
+
+
+//        //实例化客户端
+//        AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", aliAppid, appPrivateKey, "json", "UTF-8", alipay_public_key, "RSA2");
+//        //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
+//        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
+//        //SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
+//        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
+//        model.setBody(body);//对一笔交易的具体描述信息。如果是多种商品,请将商品描述字符串累加传给body。
+//        model.setSubject(subject);//商品的标题/交易标题/订单标题/订单关键字等。
+//        model.setOutTradeNo(outTradeNo);//商户网站唯一订单号
+//        model.setTimeoutExpress("30m");
+//        model.setTotalAmount(amount);//付款金额
+//        model.setProductCode("QUICK_MSECURITY_PAY");
+//        model.setPassbackParams(passbackParams);//自定义参数
+//        request.setBizModel(model);
+//        request.setNotifyUrl(callbackPath + notifyUrl);
+//        try {
+//            //这里和普通的接口调用不同,使用的是sdkExecute
+//            AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
+//            Map<String, String> map = new HashMap<>();
+//            map.put("orderString", response.getBody());
+//            System.out.println(map);//就是orderString 可以直接给客户端请求,无需再做处理。
+//            return ResultUtil.success(map);
+//        } catch (AlipayApiException e) {
+//            e.printStackTrace();
+//        }
+        return null;
+    }
+
+
+    /**
+     * 支付宝扫码支付下单
+     * @param body
+     * @param subject
+     * @param outTradeNo
+     * @param amount
+     * @param notifyUrl
+     * @return
+     */
+    public R aliScanCodePay(String body, String subject, String outTradeNo, String amount, String notifyUrl){
+        AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", aliAppid, appPrivateKey, "json", "UTF-8", alipay_public_key, "RSA2"); //获得初始化的AlipayClient
+        AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();//创建API对应的request类
+        request.setBizContent("{" +
+                "    \"out_trade_no\":\"" + outTradeNo + "\"," +//商户订单号
+                "    \"total_amount\":\"" + 1 + "\"," +
+                "    \"subject\":\"" + subject + "\"," +
+                "    \"notify_url\":\"" + callbackPath + notifyUrl + "\"," +
+                "    \"body\":\"" + body + "\"," +
+                "    \"store_id\":\"NJ_001\"," +
+                "    \"timeout_express\":\"90m\"}");//订单允许的最晚付款时间
+        AlipayTradePrecreateResponse response = null;
+        try {
+            response = alipayClient.execute(request);
+        } catch (AlipayApiException e) {
+            e.printStackTrace();
+        }
+        JSONObject alipay_trade_precreate_response = JSON.parseObject(response.getBody()).getJSONObject("alipay_trade_precreate_response");
+
+        System.err.print(alipay_trade_precreate_response.getString("qr_code"));
+        return R.ok(alipay_trade_precreate_response.getString("qr_code"));
+    }
+
+
+    /**
+     * 支付成功后的回调处理逻辑
+     * @param request
+     */
+    public Map<String, String> alipayCallback(HttpServletRequest request){
+        //获取支付宝POST过来反馈信息
+        Map<String,String> params = new HashMap<String,String>();
+        Map requestParams = request.getParameterMap();
+        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
+            String name = (String) iter.next();
+            String[] values = (String[]) requestParams.get(name);
+            String valueStr = "";
+            for (int i = 0; i < values.length; i++) {
+                valueStr = (i == values.length - 1) ? valueStr + values[i]
+                        : valueStr + values[i] + "_";
+            }
+            //乱码解决,这段代码在出现乱码时使用。
+            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
+            params.put(name, valueStr);
+        }
+        //切记alipaypublickey是支付宝的公钥,请去open.alipay.com对应应用下查看。
+        //boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
+//        try {
+//            boolean flag = AlipaySignature.rsaCheckV1(params, alipay_public_key, "UTF-8","RSA2");
+//            if(flag){
+//                Map<String, String> map = new HashMap<>();
+//                String out_trade_no = params.get("out_trade_no");
+//                String subject = params.get("subject");
+//                String total_amount = params.get("total_amount");
+//                String trade_no = params.get("trade_no");
+//                String passback_params = params.get("passback_params");
+//                map.put("out_trade_no", out_trade_no);//商家订单号
+//                map.put("subject", subject);
+//                map.put("total_amount", total_amount);
+//                map.put("trade_no", trade_no);//支付宝交易号
+//                map.put("passback_params", passback_params);//回传参数
+//                return map;
+//            }else{
+//                System.err.println("验签失败");
+//            }
+//
+//        } catch (AlipayApiException e) {
+//            e.printStackTrace();
+//        }
+//        return null;
+
+
+        Map<String, String> map = new HashMap<>();
+        String out_trade_no = params.get("out_trade_no");
+        String subject = params.get("subject");
+        String total_amount = params.get("total_amount");
+        String trade_no = params.get("trade_no");
+        String passback_params = params.get("passback_params");
+        map.put("out_trade_no", out_trade_no);//商家订单号
+        map.put("subject", subject);
+        map.put("total_amount", total_amount);
+        map.put("trade_no", trade_no);//支付宝交易号
+        map.put("passback_params", passback_params);//回传参数
+        return map;
+    }
+
+
+    /**
+     * 支付宝查询订单支付状态
+     * @param out_trade_no
+     * @return
+     * @throws Exception
+     */
+    public R queryALIOrder(String out_trade_no) throws Exception{
+        AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do",aliAppid, appPrivateKey,"json","UTF-8", alipay_public_key,"RSA2");
+        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
+        request.setBizContent("{" +
+                "\"out_trade_no\":" + out_trade_no +
+                "  }");
+        AlipayTradeQueryResponse response = alipayClient.execute(request);
+        if(response.isSuccess()){
+            String tradeStatus = response.getTradeStatus();//交易状态:WAIT_BUYER_PAY(交易创建,等待买家付款)、TRADE_CLOSED(未付款交易超时关闭,或支付完成后全额退款)、TRADE_SUCCESS(交易支付成功)、TRADE_FINISHED(交易结束,不可退款)
+            return R.ok(tradeStatus);
+        } else {
+            return R.fail(response.getMsg());
+        }
+    }
+
+
+
+    /**
+     * 微信统一下单
+     * @param body          商品描述
+     * @param attach        附加数据
+     * @param out_trade_no  商户订单号
+     * @param total_fee     标价金额
+     * @param notify_url    通知地址
+     * @param tradeType     交易类型
+     * @return
+     */
+    public R weixinpay(String body, String attach, String out_trade_no, String total_fee, String notify_url, String tradeType, String openId) throws Exception{
+        int i = new BigDecimal(total_fee).multiply(new BigDecimal("100")).intValue();
+        String hostAddress = null;
+        try {
+            hostAddress = InetAddress.getLocalHost().getHostAddress();
+        } catch (UnknownHostException e) {
+            e.printStackTrace();
+        }
+        String nonce_str = UUID.randomUUID().toString();
+        Map<String, Object> map = new HashMap<>();
+        map.put("appid", "APP".equals(tradeType) ? appid : appletsAppid);
+        map.put("mch_id", mchId);
+        map.put("nonce_str", nonce_str);
+        map.put("body", body);
+        map.put("attach", attach);//存储订单id
+        map.put("out_trade_no", out_trade_no);//存储的订单code
+        map.put("total_fee", i);
+        map.put("spbill_create_ip", hostAddress);
+        map.put("notify_url", callbackPath + notify_url);
+        map.put("trade_type", tradeType);
+        if("JSAPI".equals(tradeType)){
+            map.put("openid", openId);
+        }
+        String s = this.weixinSignature(map);
+        map.put("sign", s);
+
+        String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
+        //设置请求头
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_XML);
+        StringBuffer xmlString = new StringBuffer();
+        Set<String> strings = map.keySet();
+        String[] keys = {};
+        keys = strings.toArray(keys);
+        Arrays.sort(keys);
+        xmlString.append("<xml>");
+        for(int l = 0; l < keys.length; l++){
+            xmlString.append("<" + keys[l] + ">" + map.get(keys[l]) + "</" + keys[l] + ">");
+        }
+        xmlString.append("</xml>");
+
+        Map<String, String> map1 = null;
+//        String body1 = httpClientUtil.pushHttpRequsetXml(url, xmlString.toString(), new HashMap<>());
+        String body1 = HttpRequest.post(url)
+                .body(xmlString.toString())
+                .contentType("application/xml; charset=UTF-8")
+                .timeout(5000) // 设置超时时间
+                .execute()
+                .body();
+        //将结果xml解析成map
+        body1 = body1.replaceAll("<!\\[CDATA\\[","");
+        body1 = body1.replaceAll("]]>", "");
+        try {
+            map1 = this.xmlToMap(body1, "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        } catch (DocumentException e) {
+            e.printStackTrace();
+        }
+        String return_code = map1.get("return_code");
+        if("SUCCESS".equals(return_code)){
+            String result_code = map1.get("result_code");
+            if("SUCCESS".equals(result_code)){
+                String type = map1.get("trade_type");
+                String prepay_id = map1.get("prepay_id");
+                switch (type){
+                    case "JSAPI":
+                        //重新进行签名后返回给前端
+                        Map<String, Object> map2 = new HashMap<>();
+                        map2.put("appId", map1.get("appid"));
+                        map2.put("nonceStr", map1.get("nonce_str"));
+                        map2.put("package", "prepay_id=" + prepay_id);
+                        map2.put("signType", "MD5");
+                        map2.put("timeStamp", new Date().getTime() + "");
+                        String s2 = this.weixinSignature(map2);
+
+                        map2.put("prepay_id", prepay_id);
+                        map2.put("mch_id", map1.get("mch_id"));
+                        map2.put("trade_type", map1.get("trade_type"));
+
+                        map2.put("sign", s2);
+                        return R.ok(map2);
+                    case "NATIVE":
+                        String code_url = map1.get("code_url");
+                        return R.ok(code_url);
+                    case "APP":
+                        //重新进行签名后返回给前端
+                        Map<String, Object> map3 = new HashMap<>();
+                        map3.put("appid", appid);
+                        map3.put("noncestr", nonce_str);
+                        map3.put("package", "Sign=WXPay");
+                        map3.put("partnerid", mchId);
+                        map3.put("prepayid", prepay_id);
+                        map3.put("timestamp", new Date().getTime() / 1000);
+                        String s1 = this.weixinSignature(map3);
+                        map3.put("sign", s1);
+                        System.err.println(map3);
+                        return R.ok(map3);
+                }
+                return null;
+            }else{
+                System.err.println(map1.get("err_code_des"));
+                return R.fail(map1.get("err_code_des"));
+            }
+        }else{
+            System.err.println(map1.get("return_msg") + appid + "----" + mchId);
+            return R.fail(map1.get("return_msg"));
+        }
+    }
+
+
+
+
+
+    /**
+     * 微信支付成功后的回调处理
+     * @param request
+     */
+    public Map<String, String> weixinpayCallback(HttpServletRequest request){
+        try {
+            String param = this.getParam(request);
+            param = param.replaceAll("<!\\[CDATA\\[","");
+            param = param.replaceAll("]]>", "");
+            Map<String, String> map = this.xmlToMap(param, "UTF-8");
+            String return_code = map.get("return_code");
+            if("SUCCESS".equals(return_code)){
+                String result_code = map.get("result_code");
+                if("SUCCESS".equals(result_code)){
+                    Map<String, String> map1 = new HashMap<>();
+                    map1.put("nonce_str", map.get("nonce_str"));
+                    map1.put("out_trade_no", map.get("out_trade_no"));//存储的订单code
+                    map1.put("attach", map.get("attach"));//存储订单id
+                    map1.put("total_fee", map.get("total_fee"));
+                    map1.put("transaction_id", map.get("transaction_id"));//微信支付订单号
+                    String result = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
+                    map1.put("result", result);
+                    return map1;
+                }else{
+                    System.err.println(map.get("err_code_des"));
+                }
+            }else{
+                System.err.println(map.get("return_msg"));
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        } catch (DocumentException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+
+    /**
+     * 微信扫码收款
+     * @param body              商品描述
+     * @param attach            附加数据
+     * @param nonce_str         随机字符串
+     * @param out_trade_no      商户订单号
+     * @param total_fee         订单金额
+     * @param auth_code         授权码	扫码支付授权码,设备读取用户微信中的条码或者二维码信息(注:用户付款码条形码规则:18位纯数字,以10、11、12、13、14、15开头)
+     * @return
+     */
+    public R wxScanQRCodePay(String body, String attach, String nonce_str, String out_trade_no, String total_fee, String auth_code){
+        int i = new BigDecimal(total_fee).multiply(new BigDecimal("100")).intValue();
+        String hostAddress = null;
+        try {
+            InetAddress address = InetAddress.getLocalHost();
+            hostAddress = address.getHostAddress();
+        } catch (UnknownHostException e) {
+            e.printStackTrace();
+        }
+        String randomCode = null;
+        try {
+            randomCode = UUID.randomUUID().toString();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        Map<String, Object> map = new HashMap<>();
+        map.put("appid", appid);
+        map.put("mch_id", mchId);
+        map.put("nonce_str", nonce_str);//存储的支付人员id,员工扫描二维码支付的时候存储的是收款员工id
+        map.put("body", body);
+        map.put("attach", attach);//存储的费用月份数据,员工扫描二维码支付的时候存储的是收费项id
+        map.put("out_trade_no", randomCode + "_" + out_trade_no);//存储的房间id
+        map.put("total_fee", i);
+        map.put("spbill_create_ip", hostAddress);
+        map.put("auth_code", auth_code);
+        String s = this.weixinSignature(map);
+        map.put("sign", s);
+
+        String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
+        //设置请求头
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_XML);
+        StringBuffer xmlString = new StringBuffer();
+        Set<String> strings = map.keySet();
+        String[] keys = {};
+        keys = strings.toArray(keys);
+        Arrays.sort(keys);
+        xmlString.append("<xml>");
+        for(int l = 0; l < keys.length; l++){
+            xmlString.append("<" + keys[l] + ">" + map.get(keys[l]) + "</" + keys[l] + ">");
+        }
+        xmlString.append("</xml>");
+
+        Map<String, String> map1 = null;
+//        String body1 = httpClientUtil.pushHttpRequsetXml(url, xmlString.toString(), new HashMap<>());
+        String body1 = HttpRequest.post(url)
+                .body(xmlString.toString())
+                .contentType("application/xml; charset=UTF-8")
+                .timeout(5000) // 设置超时时间
+                .execute()
+                .body();
+
+        //将结果xml解析成map
+        body1 = body1.replaceAll("<!\\[CDATA\\[","");
+        body1 = body1.replaceAll("]]>", "");
+        try {
+            map1 = this.xmlToMap(body1, "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        } catch (DocumentException e) {
+            e.printStackTrace();
+        }
+        String return_code = map1.get("return_code");
+        if("SUCCESS".equals(return_code)){
+            String result_code = map1.get("result_code");
+            if("SUCCESS".equals(result_code)){
+                String type = map1.get("trade_type");
+                switch (type){
+                    case "JSAPI":
+                        break;
+                    case "NATIVE":
+                        String code_url = map1.get("code_url");
+                        return R.ok(code_url);
+                    case "APP":
+                        String prepay_id = map1.get("prepay_id");
+                        //重新进行签名后返回给前端
+                        Map<String, Object> map2 = new HashMap<>();
+                        map2.put("appid", appid);
+                        map2.put("noncestr", nonce_str);
+                        map2.put("package", "Sign=WXPay");
+                        map2.put("partnerid", mchId);
+                        map2.put("prepayid", prepay_id);
+                        map2.put("timestamp", new Date().getTime() + "");
+                        String s1 = this.weixinSignature(map2);
+
+                        map2.put("pac", "Sign=WXPay");
+                        map2.put("sign", s1);
+//                      System.err.println(map2);
+                        return R.ok(map2);
+                }
+                return null;
+            }else{
+//                System.err.println(map1.get("err_code_des"));
+                return R.fail(map1.get("err_code_des"));
+            }
+        }else{
+//            System.err.println(map1.get("return_msg") + appid + "----" + mchId);
+            return R.fail(map1.get("return_msg"));
+        }
+    }
+
+
+    /**
+     * 支付宝扫码收款
+     * @param data
+     * @return
+     */
+    public Object aliScanQRCodePay(String data){
+        return null;
+    }
+
+
+    /**
+     * 微信退款申请
+     * @param transaction_id    微信订单号。微信生成的订单号,在支付通知中有返回
+     * @param out_refund_no     商户退款单号。商户系统内部的退款单号,商户系统内部唯一,只能是数字、大小写字母_-|*@ ,同一退款单号多次请求只退一笔。
+     * @param total_fee         订单金额。订单总金额,单位为分,只能为整数
+     * @param refund_fee        退款金额。退款总金额,订单总金额,单位为分,只能为整数
+     * @param notify_url        退款结果通知url。异步接收微信支付退款结果通知的回调地址,通知URL必须为外网可访问的url,不允许带参数 如果参数中传了notify_url,则商户平台上配置的回调地址将不会生效。
+     * @return
+     */
+    public Map<String, String> wxRefund(String transaction_id, String out_refund_no, String total_fee, String refund_fee, String notify_url){
+        int tf = new BigDecimal(total_fee).multiply(new BigDecimal("100")).intValue();
+        int rf = new BigDecimal(refund_fee).multiply(new BigDecimal("100")).intValue();
+        String nonce_str = UUID.randomUUID().toString();
+        Map<String, Object> map = new HashMap<>();
+        map.put("appid", appid);
+        map.put("mch_id", mchId);
+        map.put("nonce_str", nonce_str);
+        map.put("transaction_id", transaction_id);
+        map.put("out_refund_no", out_refund_no);
+        map.put("total_fee", tf);
+        map.put("refund_fee", rf);
+        map.put("notify_url", callbackPath + notify_url);
+        String s = this.weixinSignature(map, key);
+        map.put("sign", s);
+
+        String url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
+        //设置请求头
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_XML);
+        StringBuffer xmlString = new StringBuffer();
+        Set<String> strings = map.keySet();
+        String[] keys = {};
+        keys = strings.toArray(keys);
+        Arrays.sort(keys);
+        xmlString.append("<xml>");
+        for(int l = 0; l < keys.length; l++){
+            xmlString.append("<" + keys[l] + ">" + map.get(keys[l]) + "</" + keys[l] + ">");
+        }
+        xmlString.append("</xml>");
+
+        Map<String, String> map1 = null;
+        String body1 = null;
+        try {
+            body1 = sendHttpsRequestWithCert(url, xmlString.toString());
+//            String certPath = "E:\\cert\\1523106371_20211206_cert\\apiclient_cert.p12";
+//
+//            body1 = httpClientUtil.pushHttpsRequsetXml(url, xmlString.toString(), new HashMap<>(), "1717539630", certPath, "PKCS12");
+
+        } catch (Exception e) {
+            System.err.println("微信退款请求失败:"+ e.getMessage());
+            e.printStackTrace();
+        }
+        System.err.println(body1);
+        //将结果xml解析成map
+        body1 = body1.replaceAll("<!\\[CDATA\\[","");
+        body1 = body1.replaceAll("]]>", "");
+        try {
+            map1 = this.xmlToMap(body1, "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        } catch (DocumentException e) {
+            e.printStackTrace();
+        }
+        String return_code = map1.get("return_code");
+        Map<String, String> map2 = new HashMap<>();
+        if("SUCCESS".equals(return_code)){
+            String result_code = map1.get("result_code");
+            if("SUCCESS".equals(result_code)){
+                map2.put("return_code", result_code);
+                map2.put("refund_id", String.valueOf(map1.get("refund_id")));//微信退款订单号
+                map2.put("refund_fee", String.valueOf(map1.get("refund_fee")));//退款金额
+                return map2;
+            }else{
+                map2.put("return_code", result_code);
+                map2.put("return_msg", map1.get("err_code_des"));
+                return map2;
+            }
+        }else{
+            map2.put("return_code", return_code);
+            map2.put("return_msg", map1.get("return_msg"));
+            return map2;
+        }
+    }
+
+    /**
+     * 发送带商户证书的 HTTPS 请求
+     */
+    private String sendHttpsRequestWithCert(String url, String xmlBody) throws Exception {
+        KeyStore keyStore = KeyStore.getInstance("PKCS12");
+        try (FileInputStream fis = new FileInputStream(certPath)) {
+            keyStore.load(fis, mchId.toCharArray()); // 证书密码为商户号
+        }
+
+        // 初始化SSL上下文
+        String keyManagerAlgorithm = KeyManagerFactory.getDefaultAlgorithm();
+        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(keyManagerAlgorithm);
+        keyManagerFactory.init(keyStore, mchId.toCharArray());
+        SSLContext sslContext = SSLContext.getInstance("TLS");
+        sslContext.init(
+                keyManagerFactory.getKeyManagers(),  // 客户端密钥管理器(包含商户证书和私钥)
+                null,                                // 信任管理器(使用默认信任库)
+                new SecureRandom()                   // 安全随机数生成器
+        );
+        // 获取SSLSocketFactory
+        SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
+
+        // 发送请求(此处假设使用Hutool的HttpRequest,但需调整SSLSocketFactory设置)
+        // 注意:Hutool的HttpRequest仍可使用,但需传入原生的SSLSocketFactory
+        HttpResponse response = HttpRequest.post(url)
+                .setSSLSocketFactory(sslSocketFactory)  // 传入原生SSLSocketFactory
+                .body(xmlBody)
+                .contentType("application/xml; charset=UTF-8")
+                .timeout(10000)
+                .execute();
+
+
+        if (response.getStatus() != 200) {
+            throw new RuntimeException("HTTP 请求失败,状态码:" + response.getStatus());
+        }
+        return response.body();
+    }
+
+    /**
+     * 微信退款成功后的回调处理
+     * @param request
+     * @return
+     */
+    public Map<String, String> wxRefundCallback(HttpServletRequest request){
+        try {
+            String param = this.getParam(request);
+            param = param.replaceAll("<!\\[CDATA\\[","");
+            param = param.replaceAll("]]>", "");
+            Map<String, String> map = this.xmlToMap(param, "UTF-8");
+            String return_code = map.get("return_code");
+            if("SUCCESS".equals(return_code)){
+                String req_info = map.get("req_info");//加密信息请用商户秘钥进行解密
+                String s = this.wxDecrypt(req_info);
+                s = s.replaceAll("<!\\[CDATA\\[","");
+                s = s.replaceAll("]]>", "");
+                map = this.xmlToMap(s, "UTF-8");
+                Map<String, String> map1 = new HashMap<>();
+                map1.put("refund_id", map.get("refund_id"));
+                map1.put("out_refund_no", map.get("out_refund_no"));
+                String result = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
+                map1.put("result", result);
+                return map1;
+            }else{
+//                System.err.println(map.get("return_msg"));
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        } catch (DocumentException e) {
+            e.printStackTrace();
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+        } catch (InvalidKeyException e) {
+            e.printStackTrace();
+        } catch (NoSuchPaddingException e) {
+            e.printStackTrace();
+        } catch (BadPaddingException e) {
+            e.printStackTrace();
+        } catch (NoSuchProviderException e) {
+            e.printStackTrace();
+        } catch (IllegalBlockSizeException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+
+    /**
+     * 支付宝退款
+     * @param trade_no          支付宝交易号
+     * @param refund_amount     退款金额
+     * @return
+     * @throws AlipayApiException
+     */
+    public Map<String, String> aliRefund(String trade_no, String refund_amount) throws AlipayApiException {
+//        AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", aliAppid, appPrivateKey,"json","UTF-8", alipay_public_key,"RSA2");
+//        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
+//        JSONObject jsonObject = new JSONObject();
+//        jsonObject.put("trade_no", trade_no);
+//        jsonObject.put("refund_amount", refund_amount);
+//        request.setBizContent(jsonObject.toJSONString());
+//        AlipayTradeRefundResponse response = alipayClient.execute(request);
+//        Map<String, String> map = new HashMap<>();
+//        if(response.isSuccess()){
+//            System.out.println("调用成功");
+//            String outTradeNo = response.getOutTradeNo();
+//            map.put("code", response.getCode());//10000
+//            map.put("trade_no", response.getTradeNo());//支付宝交易号
+//            map.put("out_trade_no", outTradeNo);//商户订单号
+//        } else {
+//            System.out.println("调用失败");
+//            map.put("code", response.getCode());
+//            map.put("msg", response.getSubMsg());
+//        }
+//        return map;
+
+
+        //构造client
+        CertAlipayRequest certAlipayRequest = new CertAlipayRequest ();
+        //设置网关地址
+        certAlipayRequest.setServerUrl("https://openapi.alipay.com/gateway.do");
+        //设置应用Id
+        certAlipayRequest.setAppId(aliAppid);
+        //设置应用私钥
+        certAlipayRequest.setPrivateKey(appPrivateKey);
+        //设置请求格式,固定值json
+        certAlipayRequest.setFormat("json");
+        //设置字符集
+        certAlipayRequest.setCharset("UTF-8");
+        //设置签名类型
+        certAlipayRequest.setSignType("RSA2");
+        //设置应用公钥证书路径
+        certAlipayRequest.setCertPath(app_cert_path);
+        //设置支付宝公钥证书路径
+        certAlipayRequest.setAlipayPublicCertPath(alipay_cert_path);
+        //设置支付宝根证书路径
+        certAlipayRequest.setRootCertPath(alipay_root_cert_path);
+        //构造client
+        AlipayClient alipayClient = null;
+        try {
+            alipayClient = new DefaultAlipayClient(certAlipayRequest);
+        } catch (AlipayApiException e) {
+            e.printStackTrace();
+        }
+        //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
+        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest ();
+        //SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
+        AlipayTradeRefundModel model = new AlipayTradeRefundModel ();
+        model.setTradeNo(trade_no);
+        model.setRefundAmount(refund_amount);
+        request.setBizModel ( model );
+        try  {
+            //这里和普通的接口调用不同,使用的是sdkExecute
+            AlipayTradeRefundResponse response = alipayClient.certificateExecute(request);
+            Map<String, String> map = new HashMap<>();
+            if(response.isSuccess()){
+                System.out.println("调用成功");
+                String outTradeNo = response.getOutTradeNo();
+                map.put("code", response.getCode());//10000
+                map.put("trade_no", response.getTradeNo());//支付宝交易号
+                map.put("out_trade_no", outTradeNo);//商户订单号
+            } else {
+                System.out.println("调用失败");
+                map.put("code", response.getCode());
+                map.put("msg", response.getSubMsg());
+            }
+            return map;
+        }  catch (AlipayApiException e ) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+
+    /**
+     * 查询微信支付订单
+     * @return
+     * @throws Exception
+     */
+    public R queryWXOrder() throws Exception{
+        String url = "https://api.mch.weixin.qq.com/pay/orderquery";
+        String nonce_str = UUID.randomUUID().toString();
+        Map<String, Object> map = new HashMap<>();
+        map.put("appid", appid);
+        map.put("mch_id", mchId);
+        map.put("transaction_id", nonce_str);//微信订单号
+        map.put("nonce_str", nonce_str);//随机字符串
+        String s = this.weixinSignature(map);
+        map.put("sign", s);
+
+        //设置请求头
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_XML);
+        StringBuffer xmlString = new StringBuffer();
+        Set<String> strings = map.keySet();
+        String[] keys = {};
+        keys = strings.toArray(keys);
+        Arrays.sort(keys);
+        xmlString.append("<xml>");
+        for(int l = 0; l < keys.length; l++){
+            xmlString.append("<" + keys[l] + ">" + map.get(keys[l]) + "</" + keys[l] + ">");
+        }
+        xmlString.append("</xml>");
+
+        Map<String, String> map1 = null;
+//        String body1 = httpClientUtil.pushHttpRequsetXml(url, xmlString.toString(), new HashMap<>());
+        String body1 = HttpRequest.post(url)
+                .body(xmlString.toString())
+                .contentType("application/xml; charset=UTF-8")
+                .timeout(5000) // 设置超时时间
+                .execute()
+                .body();
+        //将结果xml解析成map
+        body1 = body1.replaceAll("<!\\[CDATA\\[","");
+        body1 = body1.replaceAll("]]>", "");
+        try {
+            map1 = this.xmlToMap(body1, "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        } catch (DocumentException e) {
+            e.printStackTrace();
+        }
+        String return_code = map1.get("return_code");
+        if("SUCCESS".equals(return_code)){
+            String result_code = map1.get("result_code");
+            if("SUCCESS".equals(result_code)){
+                String type = map1.get("trade_type");
+                switch (type){
+                    case "JSAPI":
+                        break;
+                    case "NATIVE":
+                        String code_url = map1.get("code_url");
+                        return R.ok(code_url);
+                    case "APP":
+                        String trade_state = map1.get("trade_state");
+                        String time_end = map1.get("time_end");
+                        Map<String, Object> map2 = new HashMap<>();
+                        map2.put("trade_state", trade_state);//订单状态SUCCESS—支付成功,REFUND—转入退款,NOTPAY—未支付,CLOSED—已关闭,REVOKED—已撤销(刷卡支付),USERPAYING--用户支付中,PAYERROR--支付失败(其他原因,如银行返回失败)
+                        map2.put("time_end", time_end);//订单支付时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。
+                        return R.ok(map2);
+                }
+                return null;
+            }else{
+                System.err.println(map1.get("err_code_des"));
+                return R.fail(map1.get("err_code_des"));
+            }
+        }else{
+            System.err.println(map1.get("return_msg") + appid + "----" + mchId);
+            return R.fail(map1.get("return_msg"));
+        }
+    }
+
+
+
+    /**
+     * 微信转账功能(企业付款到零钱)
+     * @param openid                商户appid下,某用户的openid
+     * @param desc                  企业付款备注,必填。
+     * @param total_fee             企业付款金额
+     * @param partner_trade_no      商户订单号,需保持唯一性
+     * @return
+     */
+    public Map<String, String> wxTransfers(String openid, String desc, String total_fee, String partner_trade_no) throws Exception{
+        int amount = new BigDecimal(total_fee).multiply(new BigDecimal("100")).intValue();
+        String nonce_str = UUID.randomUUID().toString();
+        Map<String, Object> map = new HashMap<>();
+        map.put("mch_appid", appid);//申请商户号的appid或商户号绑定的appid
+        map.put("mchid", mchId);//微信支付分配的商户号
+        map.put("nonce_str", nonce_str);//随机字符串,不长于32位
+        map.put("partner_trade_no", partner_trade_no);//商户订单号,需保持唯一性
+        map.put("openid", openid);//商户appid下,某用户的openid
+        map.put("check_name", "NO_CHECK");//NO_CHECK:不校验真实姓名 FORCE_CHECK:强校验真实姓名
+        map.put("amount", amount);//企业付款金额,单位为分
+        map.put("desc", desc);//企业付款备注,必填。
+        String s = this.weixinSignature(map, key);
+        map.put("sign", s);
+
+        String url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
+        //设置请求头
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_XML);
+        StringBuffer xmlString = new StringBuffer();
+        Set<String> strings = map.keySet();
+        String[] keys = {};
+        keys = strings.toArray(keys);
+        Arrays.sort(keys);
+        xmlString.append("<xml>");
+        for(int l = 0; l < keys.length; l++){
+            xmlString.append("<" + keys[l] + ">" + map.get(keys[l]) + "</" + keys[l] + ">");
+        }
+        xmlString.append("</xml>");
+
+        Map<String, String> map1 = null;
+
+        String certPath = "C:\\cert\\1523106371_20211206_cert\\apiclient_cert.p12";//证书地址
+        String body1 = sendHttpsRequestWithCert(url, xmlString.toString());
+//        String body1 = httpClientUtil.pushHttpsRequsetXml(url, xmlString.toString(), new HashMap<>(), "1523106371", certPath, "PKCS12");
+        //将结果xml解析成map
+        body1 = body1.replaceAll("<!\\[CDATA\\[","");
+        body1 = body1.replaceAll("]]>", "");
+        try {
+            map1 = this.xmlToMap(body1, "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        } catch (DocumentException e) {
+            e.printStackTrace();
+        }
+        String return_code = map1.get("return_code");
+        Map<String, String> map2 = new HashMap<>();
+        if("SUCCESS".equals(return_code)){
+            String result_code = map1.get("result_code");
+            if("SUCCESS".equals(result_code)){
+                map2.put("return_code", result_code);
+                map2.put("payment_no", String.valueOf(map1.get("payment_no")));//付款订单号
+                map2.put("payment_time", String.valueOf(map1.get("payment_time")));//付款时间
+                return map2;
+            }else{
+                map2.put("return_code", result_code);
+                map2.put("err_code", map1.get("err_code"));
+                map2.put("err_code_des", map1.get("err_code_des"));
+                return map2;
+            }
+        }else{
+            map2.put("return_code", return_code);
+            map2.put("return_msg", map1.get("return_msg"));
+            return map2;
+        }
+    }
+
+
+    /**
+     * 微信转账功能(企业付款到银行卡)
+     * @param desc              备注信息
+     * @param total_fee         转账金额
+     * @param partner_trade_no  订单号
+     * @param enc_bank_no       银行卡号
+     * @param enc_true_name     收款方用户名
+     * @param bankName          银行名称
+     * @return
+     * @throws Exception
+     */
+    public Map<String, String> wxPayBank(String desc, String total_fee, String partner_trade_no, String enc_bank_no, String enc_true_name, String bankName) throws Exception{
+        int amount = new BigDecimal(total_fee).multiply(new BigDecimal("100")).intValue();
+        String nonce_str = UUID.randomUUID().toString();
+        Map<String, Object> map = new HashMap<>();
+        map.put("mch_id", mchId);//微信支付分配的商户号
+        map.put("nonce_str", nonce_str);//随机字符串,不长于32位
+        map.put("partner_trade_no", partner_trade_no);//商户订单号,需保持唯一性
+        map.put("enc_bank_no", enc_bank_no);//收款方银行卡号(采用标准RSA算法,公钥由微信侧提供)
+        map.put("enc_true_name", enc_true_name);//收款方用户名(采用标准RSA算法,公钥由微信侧提供)
+        map.put("bank_code", findBankCode(bankName));//
+        map.put("amount", amount);//企业付款金额,单位为分
+        map.put("desc", desc);//企业付款备注,必填。
+        String s = this.weixinSignature(map, key);
+        map.put("sign", s);
+
+        String url = "https://api.mch.weixin.qq.com/mmpaysptrans/pay_bank";
+        //设置请求头
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_XML);
+        StringBuffer xmlString = new StringBuffer();
+        Set<String> strings = map.keySet();
+        String[] keys = {};
+        keys = strings.toArray(keys);
+        Arrays.sort(keys);
+        xmlString.append("<xml>");
+        for(int l = 0; l < keys.length; l++){
+            xmlString.append("<" + keys[l] + ">" + map.get(keys[l]) + "</" + keys[l] + ">");
+        }
+        xmlString.append("</xml>");
+
+        Map<String, String> map1 = null;
+//        String certPath = "C:\\cert\\1523106371_20211206_cert\\apiclient_cert.p12";//证书地址
+//        String body1 = httpClientUtil.pushHttpsRequsetXml(url, xmlString.toString(), new HashMap<>(), "1523106371", certPath, "PKCS12");
+        String body1 = sendHttpsRequestWithCert(url, xmlString.toString());
+        //将结果xml解析成map
+        body1 = body1.replaceAll("<!\\[CDATA\\[","");
+        body1 = body1.replaceAll("]]>", "");
+        try {
+            map1 = this.xmlToMap(body1, "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        } catch (DocumentException e) {
+            e.printStackTrace();
+        }
+        String return_code = map1.get("return_code");
+        Map<String, String> map2 = new HashMap<>();
+        if("SUCCESS".equals(return_code)){
+            String result_code = map1.get("result_code");
+            if("SUCCESS".equals(result_code)){
+                map2.put("return_code", result_code);
+                map2.put("payment_no", String.valueOf(map1.get("payment_no")));//付款订单号
+                map2.put("cmms_amt", String.valueOf(map1.get("cmms_amt")));//手续费金额 RMB:分
+                return map2;
+            }else{
+                map2.put("return_code", result_code);
+                map2.put("err_code", map1.get("err_code"));
+                map2.put("err_code_des", map1.get("err_code_des"));
+                return map2;
+            }
+        }else{
+            map2.put("return_code", return_code);
+            map2.put("return_msg", map1.get("return_msg"));
+            return map2;
+        }
+    }
+
+    /**
+     * 微信转账到银行卡不编号
+     * @param bankName
+     * @return
+     */
+    public String findBankCode(String bankName){
+        String json = "{\"工商银行 \":1002,\"农业银行\":1005,\"建设银行\":1003,\"中国银行\":1026,\"交通银行 \":1020,\"招商银行 \":1001,\"邮储银行\":1066,\"民生银行 \":1006,\"平安银行 \":1010,\"中信银行\":1021,\"浦发银行 \":1004,\"兴业银行 \":1009,\"光大银行 \":1022,\"广发银行\":1027,\"华夏银行\":1025,\"宁波银行\":1056,\"北京银行\":4836,\"上海银行\":1024,\"南京银行\":1054,\"长子县融汇村镇银行\":4755,\"长沙银行\":4216,\"浙江泰隆商业银行\":4051,\"中原银行 \":4753,\"企业银行(中国)\":4761,\"顺德农商银行 \":4036,\"衡水银行\":4752,\"长治银行\":4756,\"大同银行\":4767,\"河南省农村信用社\":4115,\"宁夏黄河农村商业银行\":4150,\"山西省农村信用社\":4156,\"安徽省农村信用社\":4166,\"甘肃省农村信用社\":4157,\"天津农村商业银行\":4153,\"广西壮族自治区农村信用社\":4113,\"陕西省农村信用社\":4108,\"深圳农村商业银行\":4076,\"宁波鄞州农村商业银行\":4052,\"浙江省农村信用社联合社\":4764,\"江苏省农村信用社联合社\":4217,\"江苏紫金农村商业银行股份有限公司 \":4072,\"北京中关村银行股份有限公司 \":4769,\"星展银行( 中国) 有限公司 \":4778,\"枣庄银行股份有限公司 \":4766,\"海口联合农村商业银行股份有限公司 \":4758,\"南洋商业银行( 中国) 有限公司 \":4763}";
+        JSONObject jsonObject = JSON.parseObject(json);
+        Set<String> strings = jsonObject.keySet();
+        for(String key : strings){
+            if(key.indexOf(bankName) >= 0){
+                return jsonObject.getString(key);
+            }
+        }
+        return "";
+    }
+
+
+
+    /**
+     * 支付宝转账
+     * @param out_biz_no        商家侧唯一订单号,由商家自定义。对于不同转账请求,商家需保证该订单号在自身系统唯一。
+     * @param trans_amount      订单总金额,单位为元,精确到小数点后两位
+     * @param order_title       转账业务的标题,用于在支付宝用户的账单里显示
+     * @param identity          参与方的唯一标识(收款方支付宝账号)
+     * @param name              参与方真实姓名,如果非空,将校验收款支付宝账号姓名一致性。
+     * @param remark            业务备注
+     * @return
+     * @throws Exception
+     */
+    public Map<String, Object> aliTransfer(String out_biz_no, Double trans_amount, String order_title, String identity, String name, String remark) throws Exception{
+        CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
+        certAlipayRequest.setServerUrl("https://openapi.alipay.com/gateway.do");  //gateway:支付宝网关(固定)https://openapi.alipay.com/gateway.do
+        certAlipayRequest.setAppId(aliAppid);  //APPID 即创建应用后生成,详情见创建应用并获取 APPID
+        certAlipayRequest.setPrivateKey(appPrivateKey);  //开发者应用私钥,由开发者自己生成
+        certAlipayRequest.setFormat("json");  //参数返回格式,只支持 json 格式
+        certAlipayRequest.setCharset("UTF-8");  //请求和签名使用的字符编码格式,支持 GBK和 UTF-8
+        certAlipayRequest.setSignType("RSA2");  //商户生成签名字符串所使用的签名算法类型,目前支持 RSA2 和 RSA,推荐商家使用 RSA2。
+        certAlipayRequest.setCertPath(app_cert_path); //应用公钥证书路径(app_cert_path 文件绝对路径)
+        certAlipayRequest.setAlipayPublicCertPath(alipay_cert_path); //支付宝公钥证书文件路径(alipay_cert_path 文件绝对路径)
+        certAlipayRequest.setRootCertPath(alipay_root_cert_path);  //支付宝CA根证书文件路径(alipay_root_cert_path 文件绝对路径)
+        AlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest);
+        AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest();
+        request.setBizContent("{" +
+                "\"out_biz_no\":\"" + out_biz_no + "\"," +
+                "\"trans_amount\":" + trans_amount + "," +
+                "\"product_code\":\"TRANS_ACCOUNT_NO_PWD\"," +
+                "\"biz_scene\":\"DIRECT_TRANSFER\"," +
+                "\"order_title\":\"" + order_title + "\"," +
+                "\"payee_info\":{" +
+                "\"identity\":\"" + identity + "\"," +
+                "\"identity_type\":\"ALIPAY_USER_ID\"," +
+                "\"name\":\"" + name + "\"," +
+                "}," +
+                "\"remark\":\"" + remark + "\"" +
+                "}");
+        AlipayFundTransUniTransferResponse response = alipayClient.certificateExecute(request);
+        Map<String, Object> map = new HashMap<>();
+        if(response.isSuccess()){
+            String status = response.getStatus();
+            if(status.equals("SUCCESS")){//成功
+                map.put("code", response.getCode());
+                map.put("order_id", response.getOrderId());//支付宝订单号
+                map.put("pay_fund_order_id", response.getPayFundOrderId());//支付宝流水号
+            }else{
+                map.put("code", response.getCode());
+                map.put("sub_msg", response.getSubMsg());
+            }
+        } else {
+            map.put("code", response.getSubCode());
+            map.put("sub_msg", response.getSubMsg());
+        }
+        return map;
+    }
+
+
+    /**
+     * 获取请求内容
+     * @param request
+     * @return
+     * @throws IOException
+     */
+    private String getParam(HttpServletRequest request) throws IOException {
+        // 读取参数
+        InputStream inputStream;
+        StringBuilder sb = new StringBuilder();
+        inputStream = request.getInputStream();
+        String s;
+        BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
+        while ((s = in.readLine()) != null) {
+            sb.append(s);
+        }
+        in.close();
+        inputStream.close();
+        return sb.toString();
+    }
+
+
+    /**
+     * 微信下单的签名算法
+     * @param map
+     * @return
+     */
+    private String weixinSignature(Map<String, Object> map){
+        try {
+            Set<Map.Entry<String, Object>> entries = map.entrySet();
+            List<Map.Entry<String, Object>> infoIds = new ArrayList<Map.Entry<String, Object>>(entries);
+            // 对所有传入参数按照字段名的 ASCII 码从小到大排序(字典序)
+            Collections.sort(infoIds, new Comparator<Map.Entry<String, Object>>() {
+                public int compare(Map.Entry<String, Object> o1, Map.Entry<String, Object> o2) {
+                    return (o1.getKey()).toString().compareTo(o2.getKey());
+                }
+            });
+            // 构造签名键值对的格式
+            StringBuilder sb = new StringBuilder();
+            for (Map.Entry<String, Object> item : infoIds) {
+                if (item.getKey() != null || item.getKey() != "") {
+                    String key = item.getKey();
+                    Object val = item.getValue();
+                    if (!(val == "" || val == null)) {
+                        sb.append(key + "=" + val + "&");
+                    }
+                }
+            }
+            sb.append("key=" + key);
+            String sign = MD5AndKL.MD5Encode(sb.toString(), "UTF-8").toUpperCase(); //注:MD5签名方式
+            return sign;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+
+    /**
+     * 微信下单的签名算法
+     * @param map
+     * @return
+     */
+    private String weixinSignature(Map<String, Object> map, String key_){
+        try {
+            Set<Map.Entry<String, Object>> entries = map.entrySet();
+            List<Map.Entry<String, Object>> infoIds = new ArrayList<Map.Entry<String, Object>>(entries);
+            // 对所有传入参数按照字段名的 ASCII 码从小到大排序(字典序)
+            Collections.sort(infoIds, new Comparator<Map.Entry<String, Object>>() {
+                public int compare(Map.Entry<String, Object> o1, Map.Entry<String, Object> o2) {
+                    return (o1.getKey()).toString().compareTo(o2.getKey());
+                }
+            });
+            // 构造签名键值对的格式
+            StringBuilder sb = new StringBuilder();
+            for (Map.Entry<String, Object> item : infoIds) {
+                if (item.getKey() != null || item.getKey() != "") {
+                    String key = item.getKey();
+                    Object val = item.getValue();
+                    if (!(val == "" || val == null)) {
+                        sb.append(key + "=" + val + "&");
+                    }
+                }
+            }
+            sb.append("key=" + key_);
+            String sign = MD5AndKL.MD5Encode(sb.toString(), "UTF-8").toUpperCase(); //注:MD5签名方式
+            return sign;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+
+    /**
+     * 微信退款成功后的解密
+     * @param req_info
+     * @return
+     */
+    private String wxDecrypt(String req_info) throws NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException,
+            InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
+        byte[] decode = Base64.getDecoder().decode(req_info);
+        String sign = MD5AndKL.MD5Encode(key, "UTF-8").toLowerCase();
+        if (Security.getProvider("BC") == null){
+            Security.addProvider(new BouncyCastleProvider());
+        }
+        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
+        SecretKeySpec secretKeySpec = new SecretKeySpec(sign.getBytes(), "AES");
+        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
+        return new String(cipher.doFinal(decode));
+    }
+
+
+    public static void main(String[] ages){
+//        PayMoneyUtil payMoneyUtil = new PayMoneyUtil();
+//        payMoneyUtil.weixinpay("测试", "123", "12.5", "");
+    }
+
+
+    /**
+     * xml转map
+     * @param xml
+     * @param charset
+     * @return
+     * @throws UnsupportedEncodingException
+     * @throws DocumentException
+     */
+    public static Map<String, String> xmlToMap(String xml, String charset) throws UnsupportedEncodingException, DocumentException {
+
+        Map<String, String> respMap = new HashMap<String, String>();
+
+        SAXReader reader = new SAXReader();
+        Document doc = reader.read(new ByteArrayInputStream(xml.getBytes(charset)));
+        Element root = doc.getRootElement();
+        xmlToMap(root, respMap);
+        return respMap;
+    }
+
+    public static Map<String, String> xmlToMap(Element tmpElement, Map<String, String> respMap){
+        if (tmpElement.isTextOnly()) {
+            respMap.put(tmpElement.getName(), tmpElement.getText());
+            return respMap;
+        }
+
+        @SuppressWarnings("unchecked")
+        Iterator<Element> eItor = tmpElement.elementIterator();
+        while (eItor.hasNext()) {
+            Element element = eItor.next();
+            xmlToMap(element, respMap);
+        }
+        return respMap;
+    }
+}
diff --git a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/wx/HttpUtil.java b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/wx/HttpUtil.java
new file mode 100644
index 0000000..19ca6ed
--- /dev/null
+++ b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/wx/HttpUtil.java
@@ -0,0 +1,98 @@
+package com.ruoyi.order.util.payment.wx;
+
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
+
+import javax.net.ssl.*;
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+/**
+ * HTTP工具类
+ */
+public class HttpUtil {
+
+    /**
+     * 发送POST请求
+     */
+    public static String post(String urlStr, String data) throws Exception {
+        // 设置超时时间(单位:毫秒)
+        int timeout = 5000; // 5秒
+
+        // 发送 POST 请求
+        try (HttpResponse response = HttpRequest.post(urlStr)
+                .body(data, "application/xml") // 设置 XML 请求体
+                .timeout(timeout)
+                .execute()) {
+
+            // 检查 HTTP 状态码
+            if (!response.isOk()) {
+                throw new RuntimeException("HTTP请求失败,状态码: " + response.getStatus()
+                        + ", 响应: " + response.body());
+            }
+            return response.body();
+        }
+    }
+    
+    /**
+     * 发送HTTPS请求
+     */
+    public static String postHttps(String urlStr, String data, String certPath, String certPassword) throws Exception {
+        // 创建SSL上下文
+        SSLContext sslContext = SSLContext.getInstance("SSL");
+        TrustManager[] trustManagers = {new X509TrustManager() {
+            @Override
+            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+            }
+            
+            @Override
+            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+            }
+            
+            @Override
+            public X509Certificate[] getAcceptedIssuers() {
+                return null;
+            }
+        }};
+        sslContext.init(null, trustManagers, new java.security.SecureRandom());
+        
+        // 创建HTTPS连接
+        URL url = new URL(urlStr);
+        HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
+        conn.setSSLSocketFactory(sslContext.getSocketFactory());
+        conn.setHostnameVerifier(new HostnameVerifier() {
+            @Override
+            public boolean verify(String hostname, SSLSession session) {
+                return true;
+            }
+        });
+        
+        conn.setRequestMethod("POST");
+        conn.setDoOutput(true);
+        conn.setDoInput(true);
+        conn.setUseCaches(false);
+        conn.setRequestProperty("Content-Type", "application/xml");
+        conn.setRequestProperty("Connection", "Keep-Alive");
+        conn.setRequestProperty("Charset", "UTF-8");
+        
+        // 发送请求
+        OutputStream os = conn.getOutputStream();
+        os.write(data.getBytes("UTF-8"));
+        os.flush();
+        os.close();
+        
+        // 获取响应
+        StringBuilder result = new StringBuilder();
+        BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
+        String line;
+        while ((line = br.readLine()) != null) {
+            result.append(line);
+        }
+        br.close();
+        
+        return result.toString();
+    }
+}
diff --git a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/wx/WechatPayConfig.java b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/wx/WechatPayConfig.java
new file mode 100644
index 0000000..b1a1cd1
--- /dev/null
+++ b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/wx/WechatPayConfig.java
@@ -0,0 +1,26 @@
+package com.ruoyi.order.util.payment.wx;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * 微信支付配置类
+ */
+@Data
+@Component
+@ConfigurationProperties(prefix = "wx")
+public class WechatPayConfig {
+    // 小程序APPID
+    private String appId;
+    // 商户号
+    private String mchId;
+    // 商户API密钥
+    private String key;
+    // 支付结果通知地址
+    private String callbackPath;
+    // 证书路径
+    private String certPath;
+    // 商户RAS加密公钥路径
+    private String RASPath;
+}
diff --git a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/wx/WechatPayService.java b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/wx/WechatPayService.java
new file mode 100644
index 0000000..d8ef90b
--- /dev/null
+++ b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/wx/WechatPayService.java
@@ -0,0 +1,742 @@
+package com.ruoyi.order.util.payment.wx;
+
+
+import com.alibaba.fastjson2.JSON;
+import com.ruoyi.common.core.domain.R;
+import com.ruoyi.order.util.payment.MD5AndKL;
+import com.ruoyi.order.util.payment.wx.vo.PayResult;
+import com.ruoyi.order.util.payment.wx.vo.RefundCallbackResult;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.crypto.engines.AESEngine;
+import org.bouncycastle.crypto.paddings.PKCS7Padding;
+import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.openssl.PEMParser;
+import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
+import org.dom4j.DocumentException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+import sun.misc.BASE64Decoder;
+import sun.security.util.DerInputStream;
+import sun.security.util.DerValue;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.*;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.net.UnknownHostException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.*;
+import java.security.spec.RSAPublicKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 微信支付服务类
+ */
+@Service
+public class WechatPayService {
+
+    @Autowired
+    private WechatPayConfig wechatPayConfig;
+    private static final String RSA_PUBLIC_KEY_FILENAME = "wechat_rsa_public_key.pem";
+    private static final String CERT_FOLDER = "cert/";
+    /**
+     * 统一下单
+     * @param orderNumber 订单号
+     * @param totalFee 总金额(分)
+     * @param body 商品描述
+     * @param openid 用户openid
+     * @return 预支付订单信息
+     */
+    public R unifiedOrder(String orderId,String orderNumber, String totalFee, String body, String openid, String callbackPath) throws Exception {
+        int i = new BigDecimal(totalFee).multiply(new BigDecimal("100")).intValue();
+        String hostAddress = null;
+        try {
+            hostAddress = InetAddress.getLocalHost().getHostAddress();
+        } catch (UnknownHostException e) {
+            e.printStackTrace();
+        }
+        // 构建请求参数
+        Map<String, String> params = new HashMap<>();
+        params.put("appid", wechatPayConfig.getAppId());
+        params.put("mch_id", wechatPayConfig.getMchId());
+        params.put("nonce_str", generateNonceStr());
+        params.put("body", body);
+        params.put("out_trade_no", orderNumber);
+        params.put("total_fee", String.valueOf(i) );
+        params.put("spbill_create_ip", "221.182.45.100"); // 实际应用中应获取客户端IP
+        params.put("notify_url", wechatPayConfig.getCallbackPath()+callbackPath);
+        params.put("trade_type", "JSAPI");
+        params.put("openid", openid);
+
+        // 生成签名
+        String sign = weixinSignature(params);
+        params.put("sign", sign);
+
+        // 将参数转换为XML
+        String xmlParams = XMLUtil.mapToXml(params).replaceFirst("^<\\?xml.+?\\?>\\s*", "");
+
+        // 发送请求到微信支付统一下单接口
+        String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
+        String result = HttpUtil.post(url, xmlParams);
+
+        // 解析返回结果
+        Map<String, String> resultMap = XMLUtil.xmlToMap(result);
+
+        // 验证签名
+        if (!verifySign(resultMap, wechatPayConfig.getKey())) {
+            return R.fail("微信支付签名验证失败");
+//            throw new Exception("微信支付签名验证失败");
+        }
+        if (!resultMap.get("return_code").equals("SUCCESS")) {
+            return R.fail(resultMap.get("return_msg"));
+        }
+
+        // 构建小程序支付所需参数
+        Map<String, String> payParams = new HashMap<>();
+        payParams.put("appId", wechatPayConfig.getAppId());
+        payParams.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
+        payParams.put("nonceStr", generateNonceStr());
+        payParams.put("package", "prepay_id=" + resultMap.get("prepay_id"));
+        payParams.put("signType", "MD5");
+
+        // 生成支付签名
+        String paySign = weixinSignature(payParams);
+        payParams.put("paySign", paySign);
+
+        //给前端标识
+        payParams.put("payMethod","1");
+        payParams.put("orderId", orderId);
+        return R.ok(JSON.toJSONString(payParams));
+    }
+    /**
+     * 微信下单的签名算法
+     * @param map
+     * @return
+     */
+    private String weixinSignature(Map<String, String> map){
+        try {
+            Set<Map.Entry<String, String>> entries = map.entrySet();
+            List<Map.Entry<String, String>> infoIds = new ArrayList<Map.Entry<String, String>>(entries);
+            // 对所有传入参数按照字段名的 ASCII 码从小到大排序(字典序)
+            Collections.sort(infoIds, new Comparator<Map.Entry<String, String>>() {
+                public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2) {
+                    return (o1.getKey()).toString().compareTo(o2.getKey());
+                }
+            });
+            // 构造签名键值对的格式
+            StringBuilder sb = new StringBuilder();
+            for (Map.Entry<String, String> item : infoIds) {
+                if (item.getKey() != null || item.getKey() != "") {
+                    String key = item.getKey();
+                    Object val = item.getValue();
+                    if (!(val == "" || val == null)) {
+                        sb.append(key + "=" + val + "&");
+                    }
+                }
+            }
+            sb.append("key=" + wechatPayConfig.getKey());
+            String sign = MD5AndKL.MD5Encode(sb.toString(), "UTF-8").toUpperCase(); //注:MD5签名方式
+            return sign;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 处理支付结果通知
+     * @param request HTTP请求
+     * @return 处理结果
+     */
+    public PayResult processNotify(HttpServletRequest request) throws Exception {
+        // 读取请求内容
+        BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream(), StandardCharsets.UTF_8));
+        String line;
+        StringBuilder xml = new StringBuilder();
+        while ((line = br.readLine()) != null) {
+            xml.append(line);
+        }
+        br.close();
+
+        // 解析XML
+        Map<String, String> resultMap = XMLUtil.xmlToMap(xml.toString());
+
+        // 验证签名
+        if (!verifySign(resultMap, wechatPayConfig.getKey())) {
+            throw new Exception("微信支付签名验证失败");
+        }
+
+        // 验证支付结果
+        if (!"SUCCESS".equals(resultMap.get("return_code")) || !"SUCCESS".equals(resultMap.get("result_code"))) {
+            throw new Exception("微信支付结果异常");
+        }
+
+        // 处理业务逻辑
+        PayResult payResult = new PayResult();
+        payResult.setOrderNumber(resultMap.get("out_trade_no"));
+        payResult.setTransactionId(resultMap.get("transaction_id"));
+        payResult.setTotalFee(resultMap.get("total_fee"));
+
+        return payResult;
+    }
+
+    /**
+     * 生成随机字符串
+     */
+    private String generateNonceStr() {
+        return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
+    }
+
+    /**
+     * 微信支付API V2签名算法
+     * @param params 请求参数
+     * @param apiKey 商户API密钥
+     * @return 签名结果
+     */
+    public static String generateSign(Map<String, String> params, String apiKey) throws Exception {
+        // 1. 过滤空值参数
+        Map<String, String> filteredParams = new HashMap<>();
+        for (Map.Entry<String, String> entry : params.entrySet()) {
+            String key = entry.getKey();
+            String value = entry.getValue();
+            // 排除sign字段和空值字段
+            if (!"sign".equals(key) && value != null && !value.isEmpty()) {
+                filteredParams.put(key, value);
+            }
+        }
+
+        // 2. 按照ASCII码排序参数名
+        List<String> keys = new ArrayList<>(filteredParams.keySet());
+        Collections.sort(keys);
+
+        // 3. 构建签名原始字符串
+        StringBuilder sb = new StringBuilder();
+        for (String key : keys) {
+            String value = filteredParams.get(key);
+            sb.append(key).append("=").append(value).append("&");
+        }
+
+        // 4. 添加API密钥
+        sb.append("key=").append(apiKey);
+
+        // 5. MD5加密并转为大写
+        MessageDigest md = MessageDigest.getInstance("MD5");
+        byte[] digest = md.digest(sb.toString().getBytes("UTF-8"));
+
+        // 6. 转换为十六进制字符串
+        StringBuilder sign = new StringBuilder();
+        for (byte b : digest) {
+            sign.append(String.format("%02x", b & 0xff));
+        }
+
+        return sign.toString().toUpperCase();
+    }
+    /**
+     * 验证签名
+     */
+    private boolean verifySign(Map<String, String> params, String key) throws Exception {
+        String sign = params.get("sign");
+        if (StringUtils.isEmpty(sign)) {
+            return false;
+        }
+
+        // 移除sign字段
+        Map<String, String> newParams = new HashMap<>(params);
+        newParams.remove("sign");
+
+        // 生成新签名
+        String newSign = generateSign(newParams, key);
+
+        return sign.equals(newSign);
+    }
+
+    /**
+     * 关闭订单
+     */
+    public Map<String, String> closeOrder(String orderId){
+        // 构建请求参数
+        Map<String, String> params = new HashMap<>();
+        params.put("appid", wechatPayConfig.getAppId());
+        params.put("mch_id", wechatPayConfig.getMchId());
+        params.put("nonce_str", generateNonceStr());
+        params.put("out_trade_no", orderId);
+
+        // 生成签名
+        String sign = weixinSignature(params);
+        params.put("sign", sign);
+
+        // 将参数转换为XML
+        String xmlParams = XMLUtil.mapToXml(params);
+
+        // 发送请求到微信支付关闭订单接口
+        String url = "https://api.mch.weixin.qq.com/pay/closeorder";
+        String result = null;
+        try {
+            result = HttpUtil.post(url, xmlParams);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+
+        // 解析返回结果
+        try {
+            return XMLUtil.xmlToMap(result);
+        } catch (DocumentException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 查询订单
+     */
+    public Map<String, String> queryOrder(String orderId) throws Exception {
+        // 构建请求参数
+        Map<String, String> params = new HashMap<>();
+        params.put("appid", wechatPayConfig.getAppId());
+        params.put("mch_id", wechatPayConfig.getMchId());
+        params.put("nonce_str", generateNonceStr());
+        params.put("out_trade_no", orderId);
+
+        // 生成签名
+        String sign = generateSign(params, wechatPayConfig.getKey());
+        params.put("sign", sign);
+
+        // 将参数转换为XML
+        String xmlParams = XMLUtil.mapToXml(params);
+
+        // 发送请求到微信支付查询订单接口
+        String url = "https://api.mch.weixin.qq.com/pay/orderquery";
+        String result = HttpUtil.post(url, xmlParams);
+
+        // 解析返回结果
+        return XMLUtil.xmlToMap(result);
+    }
+
+
+    /**
+     * 申请退款 - 使用证书
+     */
+    public Map<String, String>  refund(String orderNo, String refundNo, String totalFee, String refundFee, String refundDesc,String callbackPath) {
+        int i = new BigDecimal(totalFee).multiply(new BigDecimal("100")).intValue();
+        int j = new BigDecimal(refundFee).multiply(new BigDecimal("100")).intValue();
+        try {
+            // 构建请求参数
+            Map<String, String> params = new HashMap<>();
+            params.put("appid", wechatPayConfig.getAppId());
+            params.put("mch_id", wechatPayConfig.getMchId());
+            params.put("nonce_str", UUID.randomUUID().toString().replaceAll("-", ""));
+            params.put("out_trade_no", orderNo);
+            params.put("out_refund_no", refundNo);
+            params.put("total_fee", String.valueOf(i));
+            params.put("refund_fee", String.valueOf(j));
+            params.put("refund_desc", refundDesc);
+            params.put("notify_url", wechatPayConfig.getCallbackPath() + callbackPath); // 退款结果
+
+            // 生成签名
+            String sign = weixinSignature(params);
+            params.put("sign", sign);
+
+            // 转换为XML
+            String xmlParams = XMLUtil.mapToXml(params);
+
+            // 使用证书发送请求
+            String result = postWithCert("https://api.mch.weixin.qq.com/secapi/pay/refund", xmlParams);
+
+            // 解析结果
+            Map<String, String> resultMap = XMLUtil.xmlToMap(result);
+            System.out.println("申请退款结果"+resultMap);
+
+            // 验证签名
+            if (!verifySign(resultMap, wechatPayConfig.getKey())) {
+                resultMap.put("return_code","FAILED");
+                resultMap.put("return_msg","申请退款结果签名验证失败");
+                return resultMap;
+            }
+
+            return resultMap;
+        } catch (Exception e) {
+            Map<String, String> resultMap=new HashMap<>();
+            resultMap.put("return_code","FAILED");
+            resultMap.put("return_msg","申请退款失败");
+            return resultMap;
+        }
+    }
+
+    /**
+     * 使用证书发送请求
+     */
+    private String postWithCert(String url, String xmlData) throws Exception {
+        // 证书类型为PKCS12
+        KeyStore keyStore = KeyStore.getInstance("PKCS12");
+        // 获取证书路径
+        String certPath = wechatPayConfig.getCertPath();
+
+        // 如果是classpath路径,使用ClassLoader加载
+        if (certPath.startsWith("classpath:")) {
+            String path = certPath.substring("classpath:".length());
+            try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream(path)) {
+                if (inputStream == null) {
+                    throw new FileNotFoundException("证书文件不存在: " + path);
+                }
+                keyStore.load(inputStream, wechatPayConfig.getMchId().toCharArray());
+            }
+        } else {
+            // 传统文件路径
+            try (FileInputStream inputStream = new FileInputStream(new File(certPath))) {
+                keyStore.load(inputStream, wechatPayConfig.getMchId().toCharArray());
+            }
+        }
+
+        // 实例化密钥库 & 初始化密钥工厂
+        SSLContext sslContext = SSLContext.getInstance("TLS");
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+        kmf.init(keyStore, wechatPayConfig.getMchId().toCharArray());
+        sslContext.init(kmf.getKeyManagers(), null, new SecureRandom());
+
+        // 创建HttpsURLConnection对象
+        URL httpsUrl = new URL(url);
+        HttpsURLConnection conn = (HttpsURLConnection) httpsUrl.openConnection();
+        conn.setSSLSocketFactory(sslContext.getSocketFactory());
+        conn.setDoOutput(true);
+        conn.setDoInput(true);
+        conn.setUseCaches(false);
+        conn.setRequestMethod("POST");
+        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
+
+        // 发送请求
+        OutputStream outputStream = conn.getOutputStream();
+        outputStream.write(xmlData.getBytes("UTF-8"));
+        outputStream.flush();
+        outputStream.close();
+
+        // 获取响应
+        InputStream inputStream = conn.getInputStream();
+        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
+        StringBuilder result = new StringBuilder();
+        String line;
+        while ((line = bufferedReader.readLine()) != null) {
+            result.append(line);
+        }
+        bufferedReader.close();
+        inputStream.close();
+        conn.disconnect();
+
+        return result.toString();
+    }
+
+    /**
+     * 处理退款回调
+     */
+    public RefundCallbackResult processRefundCallback(String xmlData) {
+        try {
+            // 1. 解析回调XML数据
+            if (StringUtils.isEmpty(xmlData)) {
+                return RefundCallbackResult.fail("回调数据为空");
+            }
+
+            //2.解析参数
+            System.out.println(xmlData);
+            System.out.println("----------------------------------------");
+            Map<String, String> resultMap = XMLUtil.xmlToMap(xmlData);
+            System.out.println(resultMap.get("req_info"));
+            // 3. 检查返回状态
+            String returnCode = resultMap.get("return_code");
+
+            if (!"SUCCESS".equals(returnCode)) {
+                String errMsg = resultMap.get("return_msg");
+                return RefundCallbackResult.fail("通信失败:" + errMsg);
+            }
+
+            //4 使用商户API密钥解密req_info(AES-256-CBC算法)
+            String decryptData = decrypt(resultMap.get("req_info"), wechatPayConfig.getKey());
+            Map<String, String> refundDetail = XMLUtil.xmlToMap(decryptData);
+
+
+            // 4. 提取退款信息
+            String orderNo = refundDetail.get("out_trade_no");        // 原订单号
+            String refundNo = refundDetail.get("out_refund_no");      // 退款订单号
+            String refundId = refundDetail.get("refund_id");          // 微信退款ID
+            System.err.println("退款回调成功,订单号:"+orderNo+",退款号:"+refundNo+",状态:{}"+refundId);
+            RefundCallbackResult refundCallbackResult = RefundCallbackResult.success();
+            refundCallbackResult.setOrderNo(orderNo);
+            refundCallbackResult.setRefundNo(refundId);
+
+            return refundCallbackResult;
+
+        } catch (Exception e) {
+            return RefundCallbackResult.fail("系统异常:" + e.getMessage());
+        }
+    }
+
+    private static String wxDecrypt(String req_info, String key)  throws NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException,
+            InvalidKeyException, BadPaddingException, IllegalBlockSizeException{
+        byte[] decode = Base64.getDecoder().decode(req_info);
+        System.out.println(Arrays.toString(decode));
+        String sign = MD5AndKL.MD5Encode(key, "UTF-8").toLowerCase();
+        System.out.println(sign);
+        if (Security.getProvider("BC") == null){
+            Security.addProvider(new BouncyCastleProvider());
+        }
+        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
+        SecretKeySpec secretKeySpec = new SecretKeySpec(sign.getBytes(), "AES");
+        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
+        return new String(cipher.doFinal(decode));
+    }
+
+    /**
+     * 获取RSA加密公钥
+     */
+    public String getRsaPublicKey() {
+        int maxRetries = 3;
+        for (int retryCount = 0; retryCount < maxRetries; retryCount++) {
+            try {
+                System.out.println("尝试获取RSA公钥,第" + (retryCount + 1) + "次");
+
+                // 构建请求参数
+                Map<String, String> params = new HashMap<>();
+                params.put("mch_id", wechatPayConfig.getMchId());
+                params.put("sign_type", "MD5");
+                params.put("nonce_str", generateNonceStr());
+
+                // 生成签名
+                String sign = weixinSignature(params);
+                params.put("sign", sign);
+
+                // 转换为XML
+                String xmlParams = XMLUtil.mapToXml(params);
+
+                // 打印请求参数
+                System.out.println("请求参数: " + xmlParams);
+
+                // 使用证书发送请求(关键修改:使用postWithCert而非普通HTTP请求)
+                String result = postWithCert("https://fraud.mch.weixin.qq.com/risk/getpublickey", xmlParams);
+
+                // 打印响应结果
+                System.out.println("响应结果: " + result);
+
+                // 解析结果
+                Map<String, String> resultMap = XMLUtil.xmlToMap(result);
+                System.out.println("获取RSA公钥结果: " + resultMap);
+
+                // 检查返回状态
+                if (!"SUCCESS".equals(resultMap.get("return_code"))) {
+                    throw new Exception("RSA公钥获取失败: " + resultMap.get("return_msg"));
+                }
+
+                // 保存公钥到本地文件
+                savePublicKeyToClasspath(resultMap.get("pub_key"));
+
+                return resultMap.get("pub_key");
+            } catch (Exception e) {
+                System.err.println("获取RSA公钥异常: " + e.getMessage() + ", 重试次数: " + (retryCount + 1));
+                e.printStackTrace();
+
+                // 如果是最后一次重试,抛出异常
+                if (retryCount == maxRetries - 1) {
+                    return null;
+                }
+
+                // 重试前等待一段时间
+                try {
+                    Thread.sleep(1000 * (retryCount + 1)); // 指数退避
+                } catch (InterruptedException ie) {
+                    Thread.currentThread().interrupt();
+                    return null;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * 保存RSA公钥到文件夹
+     * @param publicKey RSA公钥内容
+     */
+    private static void savePublicKeyToClasspath(String publicKey) throws IOException {
+        // 创建 cert 目录(如果不存在)
+        Path certDir = Paths.get(CERT_FOLDER);
+        if (!Files.exists(certDir)) {
+            Files.createDirectories(certDir); // 自动创建目录
+        }
+
+        // 写入公钥文件(UTF-8 编码)
+        Path keyFile = certDir.resolve(RSA_PUBLIC_KEY_FILENAME);
+        Files.write(keyFile, publicKey.getBytes(StandardCharsets.UTF_8));
+    }
+    /**
+     * 从文件夹加载RSA公钥
+     * @return RSA公钥内容
+     */
+    private static String loadPublicKeyFromClasspath() throws IOException {
+        Path keyFile = Paths.get(CERT_FOLDER + RSA_PUBLIC_KEY_FILENAME);
+        byte[] bytes = Files.readAllBytes(keyFile); // 读取所有字节
+        return new String(bytes, StandardCharsets.UTF_8); // 转为UTF-8字符串
+    }
+
+    /**
+     * 加载公钥 返回PublicKey对象
+     */
+    public static PublicKey loadPublicKey(String pemContent) throws Exception {
+        // 读取PEM文件内容
+//        String pemContent = new String(Files.readAllBytes(Paths.get(CERT_FOLDER + RSA_PUBLIC_KEY_FILENAME)), StandardCharsets.UTF_8);
+
+        // 移除PEM头尾标记
+        String publicKeyPEM = pemContent
+                .replace("-----BEGIN RSA PUBLIC KEY-----", "")
+                .replace("-----END RSA PUBLIC KEY-----", "")
+                .replaceAll("\\s", ""); // 去除换行/空格
+
+        // 解码Base64
+        byte[] encoded = Base64.getDecoder().decode(publicKeyPEM);
+
+        // 手动解析PKCS#1格式
+        DerInputStream derReader = new DerInputStream(encoded);
+        DerValue[] seq = derReader.getSequence(0);
+        BigInteger modulus = seq[0].getBigInteger();
+        BigInteger exponent = seq[1].getBigInteger();
+
+        RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, exponent);
+        return KeyFactory.getInstance("RSA").generatePublic(keySpec);
+    }
+
+    /**
+     * 使用RSA-OAEP加密数据
+     * @param plaintext 待加密的明文
+     * @return Base64编码的密文
+     */
+    public static String encrypt(String plaintext, PublicKey publicKey) throws Exception {
+        Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING");
+        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
+
+        byte[] encryptedBytes = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
+        return Base64.getEncoder().encodeToString(encryptedBytes);
+    }
+
+
+
+    /**
+     * 商户付款到银行卡(优先使用本地保存的公钥)
+     * @param partnerTradeNo 商户订单号
+     * @param bankNo 银行卡号
+     * @param trueName 银行卡真实姓名
+     * @param bankCode 银行编码
+     * @param amount 金额(分)
+     * @param desc 付款说明
+     * @return 付款结果
+     */
+    public Map<String, String> payToBankCard(String partnerTradeNo, String bankNo, String trueName,
+                                             String bankCode, BigDecimal amount, String desc) throws Exception {
+        int i = amount.multiply(new BigDecimal("100")).intValue();
+        // 1. 尝试从本地加载RSA公钥
+        String pubKey = loadPublicKeyFromClasspath();
+
+        // 2. 如果本地没有公钥或公钥无效,则从微信获取新公钥
+        if (pubKey == null || pubKey.isEmpty()) {
+            pubKey = getRsaPublicKey();
+
+        }
+        //公钥对象
+        PublicKey publicKey = loadPublicKey(pubKey);
+
+        // 3. 使用RSA公钥加密银行卡号和真实姓名
+        String encryptedBankNo = encrypt(bankNo, publicKey);
+        String encryptedTrueName = encrypt(trueName, publicKey);
+
+        // 4. 构建请求参数
+        Map<String, String> params = new HashMap<>();
+        params.put("mch_id", wechatPayConfig.getMchId());
+        params.put("partner_trade_no", partnerTradeNo);
+        params.put("enc_bank_no", encryptedBankNo);
+        params.put("enc_true_name", encryptedTrueName);
+        params.put("bank_code", bankCode);
+        params.put("amount", String.valueOf(i));
+        params.put("desc", desc);
+        params.put("nonce_str", generateNonceStr());
+
+        // 生成签名
+        String sign = weixinSignature(params);
+        params.put("sign", sign);
+
+        // 将参数转换为XML
+        String xmlParams = XMLUtil.mapToXml(params);
+
+        // 5. 发送请求到微信支付付款到银行卡接口
+        String url = "https://api.mch.weixin.qq.com/mmpaysptrans/pay_bank";
+        String result = postWithCert(url, xmlParams);
+
+        // 解析返回结果
+        Map<String, String> resultMap = XMLUtil.xmlToMap(result);
+
+        // 验证签名
+        if (!verifySign(resultMap, wechatPayConfig.getKey())) {
+            throw new Exception("付款到银行卡签名验证失败");
+        }
+
+        return resultMap;
+    }
+
+    public static void main(String[] args) throws IOException {
+
+        String info="CjlaS7RVnPn7zzP5ByZDxUN7OrXGp1/DEdO0qahpIqDH/gTNHb/U7VmrVV0S4lXrIa0N8FEREC3CdIeT4XB5P4D0E8TSURu6J/cD01hFu28f0JDRfeips3vSpTgznRGyCfnUBDPYwyrVeP29Wac7WAb3CCcJf7OZWaweOUkaKjaBRa1GzMZcguSZnQJz0cD5Jb4HbTMvM0VAebfCY9aXdfFBIbm+cPYESo3awqwkNTQeT4V+FViw8f8sjkH0TScMgWBiSKmQC837BLD27yIGklqlYkDP2IMeiNw+b12qCAGszfp2vYd3X+HpViXkQQet3PJWYlAm55R+IgvschP7Ub65XzLINfQrJKrQUXiKKO2LwoSRSwZvfDkR8G8E8X59CnU2XvWKeos5Y0q8ckbJb97yI+09nNgMjYyJoVCVjTFgFMDEQ4+e3CpYRhD6V/3RBp+TvBwszldbRav2XEuCXL2kCJyJEAqLPMNyfYBSNF8z1btjyz0+y/xQQcySKlQInZ710FxSE7KwRSBQ92j9nDdlR7UxCrPVCkEd+GrVNSqqnyjNh1J/rPJPHvvGwkPPq72TKiw6ZgaIgIDhy0/lWHTclo4sjYAWuUVfg3CJ8dqkuQwVZ7i0+NiahIl78RtcUph8NR48yUgBkN7WhCcu5wLbg2tu8Qe0SIwHF+RW1x9Yc8akEkNbMd4xzs8lY5MYEU9V16U8RyWJuwPDph3RnmV8HQ+2hfzmjCvPkBwtfR8P5VdK86OIsHfnfQxAcPM2a86tOBBzFXPrLHgd2CRcDKH+MXTw7RSH/bk1PiMUAWF8TQsNDzgUlznJnkjiQxoym/4ZUf4C6072KKQHbp6bgBYkBhJLT2lmjVMNSX5b1SXM9eTQixRfq6MKGw3P8XJnKdofktVv+KtSzWQlW0C8p504NWACiExupF5EII7FG+xCWt7urWUbc4NRI36UFrKToQCLVv6UBCXt/t9iWlvs6SfuZhpCexeMmZWeiIldzRu87U9rXR46Hu7DAL8dZ+0ItsIZYThSIABzZgaLKggXlkjyAcbcPYKO7egrCmDtFhzHuh4uA3VeBylL3/ZLZ4FUedn/8L4e2iAu22Qj46ORlu17W5R8Ez9kubydeAgC9PkWnjptaubPxE0bjPN69tec";
+
+        String key="fD0JzscfMf295SYtRK3MnPRjSCA4Gahr";
+        try {
+            String decrypted = decrypt(info, key);
+            System.out.println("解密结果: " + decrypted);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+
+    public static String decrypt(String encryptedStringA, String merchantKey) throws Exception {
+        // 1. 对加密串A做base64解码,得到加密串B
+        byte[] decode = Base64.getDecoder().decode(encryptedStringA);
+
+        // 2. 对商户key做md5,得到32位小写key*
+        String sign = MD5AndKL.MD5Encode(merchantKey, "UTF-8").toLowerCase();
+
+        // 3. 确保BouncyCastle提供者已添加
+        if (Security.getProvider("BC") == null) {
+            Security.addProvider(new BouncyCastleProvider());
+        }
+
+        // 4. 使用AES-256-ECB解密(PKCS7Padding)
+        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
+
+        // 注意:微信要求使用AES-256,所以密钥应为32字节(256位)
+        // 如果MD5结果是32字节(256位),直接使用
+        byte[] aesKey = sign.getBytes(StandardCharsets.UTF_8);
+
+        SecretKeySpec secretKeySpec = new SecretKeySpec(aesKey, "AES");
+        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
+
+        // 执行解密并指定UTF-8编码
+        byte[] decryptedBytes = cipher.doFinal(decode);
+        return new String(decryptedBytes, StandardCharsets.UTF_8);
+    }
+
+
+}
diff --git a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/wx/XMLUtil.java b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/wx/XMLUtil.java
new file mode 100644
index 0000000..68e6585
--- /dev/null
+++ b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/wx/XMLUtil.java
@@ -0,0 +1,52 @@
+package com.ruoyi.order.util.payment.wx;
+
+import org.dom4j.Document;
+import org.dom4j.DocumentException;
+import org.dom4j.DocumentHelper;
+import org.dom4j.Element;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * XML工具类
+ */
+public class XMLUtil {
+
+    /**
+     * 将Map转换为XML字符串
+     */
+    public static String mapToXml(Map<String, String> params) {
+        Document document = DocumentHelper.createDocument();
+        // 禁用XML声明
+        document.setXMLEncoding(null);  // 关键设置
+
+        Element root = document.addElement("xml");
+        for (Map.Entry<String, String> entry : params.entrySet()) {
+            String key = entry.getKey();
+            String value = entry.getValue() != null ? entry.getValue() : "";
+            root.addElement(key).setText(value);
+        }
+        
+        return document.asXML();
+    }
+    
+    /**
+     * 将XML字符串转换为Map
+     */
+    public static Map<String, String> xmlToMap(String xmlStr) throws DocumentException {
+        Map<String, String> map = new HashMap<>();
+        Document document = DocumentHelper.parseText(xmlStr);
+        Element root = document.getRootElement();
+
+        for (Iterator<?> iterator = root.elementIterator(); iterator.hasNext();) {
+            Element element = (Element) iterator.next();
+            // 关键修改:获取元素内所有内容(包括CDATA)
+            String value = element.getStringValue(); // 自动处理CDATA
+            map.put(element.getName(), value);
+        }
+
+        return map;
+    }
+}
diff --git a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/wx/vo/PayResult.java b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/wx/vo/PayResult.java
new file mode 100644
index 0000000..5d0b826
--- /dev/null
+++ b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/wx/vo/PayResult.java
@@ -0,0 +1,16 @@
+package com.ruoyi.order.util.payment.wx.vo;
+
+import lombok.Data;
+
+/**
+ * 支付结果VO
+ */
+@Data
+public class PayResult {
+    // 订单ID
+    private String orderNumber;
+    // 微信交易ID
+    private String transactionId;
+    // 支付金额
+    private String totalFee;
+}
diff --git a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/wx/vo/RefundCallbackResult.java b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/wx/vo/RefundCallbackResult.java
new file mode 100644
index 0000000..4e8df35
--- /dev/null
+++ b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/wx/vo/RefundCallbackResult.java
@@ -0,0 +1,38 @@
+package com.ruoyi.order.util.payment.wx.vo;
+
+import lombok.Data;
+
+/**
+ * 退款回调结果实体
+ */
+@Data
+public class RefundCallbackResult {
+    private boolean success;        // 处理是否成功
+    private String msg;             // 结果描述
+    private String orderNo;         // 原订单号
+    private String refundNo;        // 退款订单号
+    private String refundId;        // 微信退款ID
+    private String totalFee;        // 原订单金额(分)
+    private String refundFee;       // 退款金额(分)
+    private String refundStatus;    // 退款状态
+
+    // 成功响应
+    public static RefundCallbackResult success() {
+        return success("处理成功");
+    }
+
+    public static RefundCallbackResult success(String msg) {
+        RefundCallbackResult result = new RefundCallbackResult();
+        result.setSuccess(true);
+        result.setMsg(msg);
+        return result;
+    }
+
+    // 失败响应
+    public static RefundCallbackResult fail(String msg) {
+        RefundCallbackResult result = new RefundCallbackResult();
+        result.setSuccess(false);
+        result.setMsg(msg);
+        return result;
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/wx/vo/UnifiedOrderResult.java b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/wx/vo/UnifiedOrderResult.java
new file mode 100644
index 0000000..85785c3
--- /dev/null
+++ b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/util/payment/wx/vo/UnifiedOrderResult.java
@@ -0,0 +1,38 @@
+package com.ruoyi.order.util.payment.wx.vo;
+
+import lombok.Data;
+
+/**
+ * 统一下单结果VO
+ */
+@Data
+public class UnifiedOrderResult {
+    // 返回状态码
+    private String returnCode;
+    // 返回信息
+    private String returnMsg;
+    // 业务结果
+    private String resultCode;
+    // 错误代码
+    private String errCode;
+    // 错误代码描述
+    private String errCodeDes;
+    // 公众账号ID
+    private String appid;
+    // 商户号
+    private String mchId;
+    // 设备号
+    private String deviceInfo;
+    // 随机字符串
+    private String nonceStr;
+    // 签名
+    private String sign;
+    // 签名类型
+    private String signType;
+    // 交易类型
+    private String tradeType;
+    // 预支付交易会话标识
+    private String prepayId;
+    // 二维码链接
+    private String codeUrl;
+}
diff --git a/ruoyi-service/ruoyi-other/pom.xml b/ruoyi-service/ruoyi-other/pom.xml
index e51a5ae..18947f6 100644
--- a/ruoyi-service/ruoyi-other/pom.xml
+++ b/ruoyi-service/ruoyi-other/pom.xml
@@ -142,6 +142,23 @@
             <artifactId>geodesy</artifactId>
             <version>1.1.3</version>
         </dependency>
+
+        <!--微信支付-->
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-http</artifactId>
+            <version>5.8.25</version>
+        </dependency>
+        <dependency>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcprov-jdk15on</artifactId>
+            <version>1.70</version>
+        </dependency>
+        <dependency>
+            <groupId>dom4j</groupId>
+            <artifactId>dom4j</artifactId>
+            <version>1.6.1</version>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/ShopWithdrawController.java b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/ShopWithdrawController.java
index b5f7d13..e98cf90 100644
--- a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/ShopWithdrawController.java
+++ b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/ShopWithdrawController.java
@@ -26,6 +26,7 @@
 import com.ruoyi.other.util.payment.model.SinglePay;
 import com.ruoyi.other.util.payment.model.SinglePayCallbackResult;
 import com.ruoyi.other.util.payment.model.SinglePayResult;
+import com.ruoyi.other.util.payment.wx.WechatPayService;
 import com.ruoyi.system.api.domain.SysUser;
 import com.ruoyi.system.api.feignClient.SysUserClient;
 import com.ruoyi.system.api.model.LoginUser;
@@ -37,11 +38,13 @@
 import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
+import java.io.IOException;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 import java.util.Optional;
 import java.util.stream.Collectors;
 
@@ -75,6 +78,9 @@
     private SysUserClient sysUserClient;
     @Autowired
     private ShopWithdrawMapper shopWithdrawMapper;
+
+    @Autowired
+    private WechatPayService wechatPayService;
 
 
     @GetMapping("/getShopById")
@@ -269,33 +275,30 @@
         Shop shop = shopService.getById(shopWithdraw1.getShopId());
         BigDecimal money = shopWithdraw1.getMoney();
         if(1 == shopWithdraw.getAuditStatus()){
-            //通过
-            // 先检查账户余额是否充足  todo 商户编号
-            AccountBalanceQueryResult accountBalanceQueryResult = TransferUtil.accountBalanceQuery();
-            if(null == accountBalanceQueryResult){
-                return R.fail("查询账户余额出错");
-            }
-            Double useAbleSettAmount = accountBalanceQueryResult.getUseAbleSettAmount();
-            if(useAbleSettAmount < (shopWithdraw1.getMoney().doubleValue() + 1)){
-                return R.fail("账户可用余额不足,请先补充账户余额");
-            }
-            //银行卡转账
-            SinglePay singlePay = new SinglePay();
-            singlePay.setTradeMerchantNo(TransferUtil.sysTradeMerchantNo);
-            singlePay.setMerchantOrderNo(shopWithdraw1.getId().toString());
-            singlePay.setReceiverAccountNoEnc(shop.getReceiverAccountNoEnc());
-            singlePay.setReceiverNameEnc(shop.getReceiverNameEnc());
-            singlePay.setReceiverAccountType(shop.getReceiverAccountType());
-            singlePay.setReceiverBankChannelNo(shop.getReceiverBankChannelNo());
-            singlePay.setPaidAmount(shopWithdraw1.getMoney().doubleValue());
-            singlePay.setPaidDesc("账户余额提现");
-            singlePay.setPaidUse("208");
-            singlePay.setCallbackUrl("/other/shop-withdraw/withdrawalCallback");
-            SinglePayResult singlePayResult = TransferUtil.singlePay(singlePay);
-            if(null == singlePayResult){
-                return R.fail("转账失败");
-            }
-            shopWithdraw1.setStatus(1);
+            //取消商户转账,线下转账
+           /*
+           try {
+                Map<String, String> map = wechatPayService.payToBankCard(shopWithdraw1.getId().toString(),
+                        shopWithdraw1.getReceiverAccountNoEnc(),shopWithdraw1.getReceiverNameEnc(),shopWithdraw1.getReceiverBankChannelNo(),shopWithdraw1.getMoney(),shopWithdraw.getRemark());
+                if (map.get("return_code").equals("SUCCESS")) {
+                    System.out.println("转账申请成功");
+                    shopWithdraw1.setStatus(1);
+                }else {
+                    return R.fail("转账申请失败");
+                }
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }*/
+            //到账
+
+            shopWithdraw1.setStatus(2);
+            shopWithdraw1.setArrivalTime(LocalDateTime.now());
+            shopWithdrawService.updateById(shopWithdraw);
+            //更新店铺审核中的金额,和提现金额
+            shop.setWithdrawAuditMoney(shop.getWithdrawAuditMoney().subtract(shopWithdraw1.getMoney()));//审核中金额
+            shop.setWithdrawMoney(shop.getWithdrawMoney().add(shopWithdraw1.getMoney()));//提现金额
+            shopService.updateById(shop);
+
         }
         if(2 == shopWithdraw.getAuditStatus()){
             //审核不通过
@@ -330,8 +333,7 @@
         return R.ok();
     }
 
-    
-    
+
     /**
      * 提现审核通过后转账回调通知
      * @param singlePayCallbackResult
diff --git a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/service/impl/ShopServiceImpl.java b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/service/impl/ShopServiceImpl.java
index cf664fb..968a5ea 100644
--- a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/service/impl/ShopServiceImpl.java
+++ b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/service/impl/ShopServiceImpl.java
@@ -338,10 +338,12 @@
 
         //商品评价
         GoodsEvaluate goodsEvaluateOne = goodsEvaluateMapper.getGoodsEvaluateOne(goods.getId());
-        AppUser appUserById = appUserClient.getAppUserById(goodsEvaluateOne.getAppUserId());
-        goodsEvaluateOne.setUserName(appUserById.getName());
-        goodsEvaluateOne.setAvatar(appUserById.getAvatar());
-        goodsVO.setGoodsEvaluate(goodsEvaluateOne);
+        if(goodsEvaluateOne != null){
+            AppUser appUserById = appUserClient.getAppUserById(goodsEvaluateOne.getAppUserId());
+            goodsEvaluateOne.setUserName(appUserById.getName());
+            goodsEvaluateOne.setAvatar(appUserById.getAvatar());
+            goodsVO.setGoodsEvaluate(goodsEvaluateOne);
+        }
         return goodsVO;
 
     }
diff --git a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/util/payment/wx/HttpUtil.java b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/util/payment/wx/HttpUtil.java
new file mode 100644
index 0000000..4c2310b
--- /dev/null
+++ b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/util/payment/wx/HttpUtil.java
@@ -0,0 +1,99 @@
+package com.ruoyi.other.util.payment.wx;
+
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
+
+import javax.net.ssl.*;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.URL;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+/**
+ * HTTP工具类
+ */
+public class HttpUtil {
+
+    /**
+     * 发送POST请求
+     */
+    public static String post(String urlStr, String data) throws Exception {
+        // 设置超时时间(单位:毫秒)
+        int timeout = 5000; // 5秒
+
+        // 发送 POST 请求
+        try (HttpResponse response = HttpRequest.post(urlStr)
+                .body(data, "application/xml") // 设置 XML 请求体
+                .timeout(timeout)
+                .execute()) {
+
+            // 检查 HTTP 状态码
+            if (!response.isOk()) {
+                throw new RuntimeException("HTTP请求失败,状态码: " + response.getStatus()
+                        + ", 响应: " + response.body());
+            }
+            return response.body();
+        }
+    }
+    
+    /**
+     * 发送HTTPS请求
+     */
+    public static String postHttps(String urlStr, String data, String certPath, String certPassword) throws Exception {
+        // 创建SSL上下文
+        SSLContext sslContext = SSLContext.getInstance("SSL");
+        TrustManager[] trustManagers = {new X509TrustManager() {
+            @Override
+            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+            }
+            
+            @Override
+            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+            }
+            
+            @Override
+            public X509Certificate[] getAcceptedIssuers() {
+                return null;
+            }
+        }};
+        sslContext.init(null, trustManagers, new java.security.SecureRandom());
+        
+        // 创建HTTPS连接
+        URL url = new URL(urlStr);
+        HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
+        conn.setSSLSocketFactory(sslContext.getSocketFactory());
+        conn.setHostnameVerifier(new HostnameVerifier() {
+            @Override
+            public boolean verify(String hostname, SSLSession session) {
+                return true;
+            }
+        });
+        
+        conn.setRequestMethod("POST");
+        conn.setDoOutput(true);
+        conn.setDoInput(true);
+        conn.setUseCaches(false);
+        conn.setRequestProperty("Content-Type", "application/xml");
+        conn.setRequestProperty("Connection", "Keep-Alive");
+        conn.setRequestProperty("Charset", "UTF-8");
+        
+        // 发送请求
+        OutputStream os = conn.getOutputStream();
+        os.write(data.getBytes("UTF-8"));
+        os.flush();
+        os.close();
+        
+        // 获取响应
+        StringBuilder result = new StringBuilder();
+        BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
+        String line;
+        while ((line = br.readLine()) != null) {
+            result.append(line);
+        }
+        br.close();
+        
+        return result.toString();
+    }
+}
diff --git a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/util/payment/wx/PayResult.java b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/util/payment/wx/PayResult.java
new file mode 100644
index 0000000..244626c
--- /dev/null
+++ b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/util/payment/wx/PayResult.java
@@ -0,0 +1,16 @@
+package com.ruoyi.other.util.payment.wx;
+
+import lombok.Data;
+
+/**
+ * 支付结果VO
+ */
+@Data
+public class PayResult {
+    // 订单ID
+    private String orderNumber;
+    // 微信交易ID
+    private String transactionId;
+    // 支付金额
+    private String totalFee;
+}
diff --git a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/util/payment/wx/RefundCallbackResult.java b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/util/payment/wx/RefundCallbackResult.java
new file mode 100644
index 0000000..6c5eb20
--- /dev/null
+++ b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/util/payment/wx/RefundCallbackResult.java
@@ -0,0 +1,38 @@
+package com.ruoyi.other.util.payment.wx;
+
+import lombok.Data;
+
+/**
+ * 退款回调结果实体
+ */
+@Data
+public class RefundCallbackResult {
+    private boolean success;        // 处理是否成功
+    private String msg;             // 结果描述
+    private String orderNo;         // 原订单号
+    private String refundNo;        // 退款订单号
+    private String refundId;        // 微信退款ID
+    private String totalFee;        // 原订单金额(分)
+    private String refundFee;       // 退款金额(分)
+    private String refundStatus;    // 退款状态
+
+    // 成功响应
+    public static RefundCallbackResult success() {
+        return success("处理成功");
+    }
+
+    public static RefundCallbackResult success(String msg) {
+        RefundCallbackResult result = new RefundCallbackResult();
+        result.setSuccess(true);
+        result.setMsg(msg);
+        return result;
+    }
+
+    // 失败响应
+    public static RefundCallbackResult fail(String msg) {
+        RefundCallbackResult result = new RefundCallbackResult();
+        result.setSuccess(false);
+        result.setMsg(msg);
+        return result;
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/util/payment/wx/WechatPayConfig.java b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/util/payment/wx/WechatPayConfig.java
new file mode 100644
index 0000000..3fbd68c
--- /dev/null
+++ b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/util/payment/wx/WechatPayConfig.java
@@ -0,0 +1,26 @@
+package com.ruoyi.other.util.payment.wx;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * 微信支付配置类
+ */
+@Data
+@Component
+@ConfigurationProperties(prefix = "wx")
+public class WechatPayConfig {
+    // 小程序APPID
+    private String appId;
+    // 商户号
+    private String mchId;
+    // 商户API密钥
+    private String key;
+    // 支付结果通知地址
+    private String callbackPath;
+    // 证书路径
+    private String certPath;
+    // 商户RAS加密公钥路径
+    private String RASPath;
+}
diff --git a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/util/payment/wx/WechatPayService.java b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/util/payment/wx/WechatPayService.java
new file mode 100644
index 0000000..dbf26be
--- /dev/null
+++ b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/util/payment/wx/WechatPayService.java
@@ -0,0 +1,734 @@
+package com.ruoyi.other.util.payment.wx;
+
+
+import com.alibaba.fastjson2.JSON;
+import com.ruoyi.common.core.domain.R;
+import com.ruoyi.other.util.payment.MD5AndKL;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.openssl.PEMParser;
+import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
+import org.dom4j.DocumentException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+import sun.security.util.DerInputStream;
+import sun.security.util.DerValue;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.SecretKeySpec;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.servlet.http.HttpServletRequest;
+import java.io.*;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.URL;
+import java.net.UnknownHostException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.*;
+import java.security.spec.RSAPublicKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.*;
+
+/**
+ * 微信支付服务类
+ */
+@Service
+public class WechatPayService {
+
+    @Autowired
+    private WechatPayConfig wechatPayConfig;
+    private static final String RSA_PUBLIC_KEY_FILENAME = "wechat_rsa_public_key.pem";
+    private static final String CERT_FOLDER = "C:\\cert\\";
+    /**
+     * 统一下单
+     * @param orderNumber 订单号
+     * @param totalFee 总金额(分)
+     * @param body 商品描述
+     * @param openid 用户openid
+     * @return 预支付订单信息
+     */
+    public R unifiedOrder(String orderNumber, String totalFee, String body, String openid, String callbackPath) throws Exception {
+        int i = new BigDecimal(totalFee).multiply(new BigDecimal("100")).intValue();
+        String hostAddress = null;
+        try {
+            hostAddress = InetAddress.getLocalHost().getHostAddress();
+        } catch (UnknownHostException e) {
+            e.printStackTrace();
+        }
+        // 构建请求参数
+        Map<String, String> params = new HashMap<>();
+        params.put("appid", wechatPayConfig.getAppId());
+        params.put("mch_id", wechatPayConfig.getMchId());
+        params.put("nonce_str", generateNonceStr());
+        params.put("body", body);
+        params.put("out_trade_no", orderNumber);
+        params.put("total_fee", String.valueOf(i) );
+        params.put("spbill_create_ip", "221.182.45.100"); // 实际应用中应获取客户端IP
+        params.put("notify_url", wechatPayConfig.getCallbackPath()+callbackPath);
+        params.put("trade_type", "JSAPI");
+        params.put("openid", openid);
+
+        // 生成签名
+        String sign = weixinSignature(params);
+        params.put("sign", sign);
+
+        // 将参数转换为XML
+        String xmlParams = XMLUtil.mapToXml(params).replaceFirst("^<\\?xml.+?\\?>\\s*", "");
+
+        // 发送请求到微信支付统一下单接口
+        String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
+        String result = HttpUtil.post(url, xmlParams);
+
+        // 解析返回结果
+        Map<String, String> resultMap = XMLUtil.xmlToMap(result);
+
+        // 验证签名
+        if (!verifySign(resultMap, wechatPayConfig.getKey())) {
+            return R.fail("微信支付签名验证失败");
+//            throw new Exception("微信支付签名验证失败");
+        }
+
+        // 构建小程序支付所需参数
+        Map<String, String> payParams = new HashMap<>();
+        payParams.put("appId", wechatPayConfig.getAppId());
+        payParams.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
+        payParams.put("nonceStr", generateNonceStr());
+        payParams.put("package", "prepay_id=" + resultMap.get("prepay_id"));
+        payParams.put("signType", "MD5");
+
+        // 生成支付签名
+        String paySign = weixinSignature(payParams);
+        payParams.put("paySign", paySign);
+
+        //给前端标识
+        payParams.put("payMethod","1");
+        return R.ok(JSON.toJSONString(payParams));
+    }
+    /**
+     * 微信下单的签名算法
+     * @param map
+     * @return
+     */
+    private String weixinSignature(Map<String, String> map){
+        try {
+            Set<Map.Entry<String, String>> entries = map.entrySet();
+            List<Map.Entry<String, String>> infoIds = new ArrayList<Map.Entry<String, String>>(entries);
+            // 对所有传入参数按照字段名的 ASCII 码从小到大排序(字典序)
+            Collections.sort(infoIds, new Comparator<Map.Entry<String, String>>() {
+                public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2) {
+                    return (o1.getKey()).toString().compareTo(o2.getKey());
+                }
+            });
+            // 构造签名键值对的格式
+            StringBuilder sb = new StringBuilder();
+            for (Map.Entry<String, String> item : infoIds) {
+                if (item.getKey() != null || item.getKey() != "") {
+                    String key = item.getKey();
+                    Object val = item.getValue();
+                    if (!(val == "" || val == null)) {
+                        sb.append(key + "=" + val + "&");
+                    }
+                }
+            }
+            sb.append("key=" + wechatPayConfig.getKey());
+            String sign = MD5AndKL.MD5Encode(sb.toString(), "UTF-8").toUpperCase(); //注:MD5签名方式
+            return sign;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 处理支付结果通知
+     * @param request HTTP请求
+     * @return 处理结果
+     */
+    public PayResult processNotify(HttpServletRequest request) throws Exception {
+        // 读取请求内容
+        BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream(), StandardCharsets.UTF_8));
+        String line;
+        StringBuilder xml = new StringBuilder();
+        while ((line = br.readLine()) != null) {
+            xml.append(line);
+        }
+        br.close();
+
+        // 解析XML
+        Map<String, String> resultMap = XMLUtil.xmlToMap(xml.toString());
+
+        // 验证签名
+        if (!verifySign(resultMap, wechatPayConfig.getKey())) {
+            throw new Exception("微信支付签名验证失败");
+        }
+
+        // 验证支付结果
+        if (!"SUCCESS".equals(resultMap.get("return_code")) || !"SUCCESS".equals(resultMap.get("result_code"))) {
+            throw new Exception("微信支付结果异常");
+        }
+
+        // 处理业务逻辑
+        PayResult payResult = new PayResult();
+        payResult.setOrderNumber(resultMap.get("out_trade_no"));
+        payResult.setTransactionId(resultMap.get("transaction_id"));
+        payResult.setTotalFee(resultMap.get("total_fee"));
+
+        return payResult;
+    }
+
+    /**
+     * 生成随机字符串
+     */
+    private String generateNonceStr() {
+        return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
+    }
+
+    /**
+     * 微信支付API V2签名算法
+     * @param params 请求参数
+     * @param apiKey 商户API密钥
+     * @return 签名结果
+     */
+    public static String generateSign(Map<String, String> params, String apiKey) throws Exception {
+        // 1. 过滤空值参数
+        Map<String, String> filteredParams = new HashMap<>();
+        for (Map.Entry<String, String> entry : params.entrySet()) {
+            String key = entry.getKey();
+            String value = entry.getValue();
+            // 排除sign字段和空值字段
+            if (!"sign".equals(key) && value != null && !value.isEmpty()) {
+                filteredParams.put(key, value);
+            }
+        }
+
+        // 2. 按照ASCII码排序参数名
+        List<String> keys = new ArrayList<>(filteredParams.keySet());
+        Collections.sort(keys);
+
+        // 3. 构建签名原始字符串
+        StringBuilder sb = new StringBuilder();
+        for (String key : keys) {
+            String value = filteredParams.get(key);
+            sb.append(key).append("=").append(value).append("&");
+        }
+
+        // 4. 添加API密钥
+        sb.append("key=").append(apiKey);
+
+        // 5. MD5加密并转为大写
+        MessageDigest md = MessageDigest.getInstance("MD5");
+        byte[] digest = md.digest(sb.toString().getBytes("UTF-8"));
+
+        // 6. 转换为十六进制字符串
+        StringBuilder sign = new StringBuilder();
+        for (byte b : digest) {
+            sign.append(String.format("%02x", b & 0xff));
+        }
+
+        return sign.toString().toUpperCase();
+    }
+    /**
+     * 验证签名
+     */
+    private boolean verifySign(Map<String, String> params, String key) throws Exception {
+        String sign = params.get("sign");
+        if (StringUtils.isEmpty(sign)) {
+            return false;
+        }
+
+        // 移除sign字段
+        Map<String, String> newParams = new HashMap<>(params);
+        newParams.remove("sign");
+
+        // 生成新签名
+        String newSign = generateSign(newParams, key);
+
+        return sign.equals(newSign);
+    }
+
+    /**
+     * 关闭订单
+     */
+    public Map<String, String> closeOrder(String orderId){
+        // 构建请求参数
+        Map<String, String> params = new HashMap<>();
+        params.put("appid", wechatPayConfig.getAppId());
+        params.put("mch_id", wechatPayConfig.getMchId());
+        params.put("nonce_str", generateNonceStr());
+        params.put("out_trade_no", orderId);
+
+        // 生成签名
+        String sign = weixinSignature(params);
+        params.put("sign", sign);
+
+        // 将参数转换为XML
+        String xmlParams = XMLUtil.mapToXml(params);
+
+        // 发送请求到微信支付关闭订单接口
+        String url = "https://api.mch.weixin.qq.com/pay/closeorder";
+        String result = null;
+        try {
+            result = HttpUtil.post(url, xmlParams);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+
+        // 解析返回结果
+        try {
+            return XMLUtil.xmlToMap(result);
+        } catch (DocumentException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 查询订单
+     */
+    public Map<String, String> queryOrder(String orderId) throws Exception {
+        // 构建请求参数
+        Map<String, String> params = new HashMap<>();
+        params.put("appid", wechatPayConfig.getAppId());
+        params.put("mch_id", wechatPayConfig.getMchId());
+        params.put("nonce_str", generateNonceStr());
+        params.put("out_trade_no", orderId);
+
+        // 生成签名
+        String sign = generateSign(params, wechatPayConfig.getKey());
+        params.put("sign", sign);
+
+        // 将参数转换为XML
+        String xmlParams = XMLUtil.mapToXml(params);
+
+        // 发送请求到微信支付查询订单接口
+        String url = "https://api.mch.weixin.qq.com/pay/orderquery";
+        String result = HttpUtil.post(url, xmlParams);
+
+        // 解析返回结果
+        return XMLUtil.xmlToMap(result);
+    }
+
+
+    /**
+     * 申请退款 - 使用证书
+     */
+    public Map<String, String>  refund(String orderNo, String refundNo, String totalFee, String refundFee, String refundDesc,String callbackPath) {
+        int i = new BigDecimal(totalFee).multiply(new BigDecimal("100")).intValue();
+        int j = new BigDecimal(refundFee).multiply(new BigDecimal("100")).intValue();
+        try {
+            // 构建请求参数
+            Map<String, String> params = new HashMap<>();
+            params.put("appid", wechatPayConfig.getAppId());
+            params.put("mch_id", wechatPayConfig.getMchId());
+            params.put("nonce_str", UUID.randomUUID().toString().replaceAll("-", ""));
+            params.put("out_trade_no", orderNo);
+            params.put("out_refund_no", refundNo);
+            params.put("total_fee", String.valueOf(i));
+            params.put("refund_fee", String.valueOf(j));
+            params.put("refund_desc", refundDesc);
+            params.put("notify_url", wechatPayConfig.getCallbackPath() + callbackPath); // 退款结果
+
+            // 生成签名
+            String sign = weixinSignature(params);
+            params.put("sign", sign);
+
+            // 转换为XML
+            String xmlParams = XMLUtil.mapToXml(params);
+
+            // 使用证书发送请求
+            String result = postWithCert("https://api.mch.weixin.qq.com/secapi/pay/refund", xmlParams);
+
+            // 解析结果
+            Map<String, String> resultMap = XMLUtil.xmlToMap(result);
+            System.out.println("申请退款结果"+resultMap);
+
+            // 验证签名
+            if (!verifySign(resultMap, wechatPayConfig.getKey())) {
+                resultMap.put("return_code","FAILED");
+                resultMap.put("return_msg","申请退款结果签名验证失败");
+                return resultMap;
+            }
+
+            return resultMap;
+        } catch (Exception e) {
+            Map<String, String> resultMap=new HashMap<>();
+            resultMap.put("return_code","FAILED");
+            resultMap.put("return_msg","申请退款失败");
+            return resultMap;
+        }
+    }
+
+    /**
+     * 使用证书发送请求
+     */
+    private String postWithCert(String url, String xmlData) throws Exception {
+        // 证书类型为PKCS12
+        KeyStore keyStore = KeyStore.getInstance("PKCS12");
+        // 获取证书路径
+        String certPath = wechatPayConfig.getCertPath();
+
+        // 如果是classpath路径,使用ClassLoader加载
+        if (certPath.startsWith("classpath:")) {
+            String path = certPath.substring("classpath:".length());
+            try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream(path)) {
+                if (inputStream == null) {
+                    throw new FileNotFoundException("证书文件不存在: " + path);
+                }
+                keyStore.load(inputStream, wechatPayConfig.getMchId().toCharArray());
+            }
+        } else {
+            // 传统文件路径
+            try (FileInputStream inputStream = new FileInputStream(new File(certPath))) {
+                keyStore.load(inputStream, wechatPayConfig.getMchId().toCharArray());
+            }
+        }
+
+        // 实例化密钥库 & 初始化密钥工厂
+        SSLContext sslContext = SSLContext.getInstance("TLS");
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+        kmf.init(keyStore, wechatPayConfig.getMchId().toCharArray());
+        sslContext.init(kmf.getKeyManagers(), null, new SecureRandom());
+
+        // 创建HttpsURLConnection对象
+        URL httpsUrl = new URL(url);
+        HttpsURLConnection conn = (HttpsURLConnection) httpsUrl.openConnection();
+        conn.setSSLSocketFactory(sslContext.getSocketFactory());
+        conn.setDoOutput(true);
+        conn.setDoInput(true);
+        conn.setUseCaches(false);
+        conn.setRequestMethod("POST");
+        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
+
+        // 发送请求
+        OutputStream outputStream = conn.getOutputStream();
+        outputStream.write(xmlData.getBytes("UTF-8"));
+        outputStream.flush();
+        outputStream.close();
+
+        // 获取响应
+        InputStream inputStream = conn.getInputStream();
+        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
+        StringBuilder result = new StringBuilder();
+        String line;
+        while ((line = bufferedReader.readLine()) != null) {
+            result.append(line);
+        }
+        bufferedReader.close();
+        inputStream.close();
+        conn.disconnect();
+
+        return result.toString();
+    }
+
+    /**
+     * 处理退款回调
+     */
+    public RefundCallbackResult processRefundCallback(String xmlData) {
+        try {
+            // 1. 解析回调XML数据
+            if (StringUtils.isEmpty(xmlData)) {
+//                logger.error("退款回调数据为空");
+                return RefundCallbackResult.fail("回调数据为空");
+            }
+
+            //2.解析参数
+            System.err.println(xmlData);
+            System.out.println("----------------------------------------");
+            Map<String, String> resultMap = XMLUtil.xmlToMap(xmlData);
+            System.out.println(resultMap.get("req_info"));
+            // 3. 检查返回状态
+            String returnCode = resultMap.get("return_code");
+
+            if (!"SUCCESS".equals(returnCode)) {
+                String errMsg = resultMap.get("return_msg");
+                return RefundCallbackResult.fail("通信失败:" + errMsg);
+            }
+
+            //4 使用商户API密钥解密req_info(AES-256-CBC算法)
+            String decryptData = wxDecrypt(resultMap.get("req_info"), wechatPayConfig.getKey());
+            Map<String, String> refundDetail = XMLUtil.xmlToMap(decryptData);
+
+
+            // 4. 提取退款信息
+            String orderNo = refundDetail.get("out_trade_no");        // 原订单号
+            String refundNo = refundDetail.get("out_refund_no");      // 退款订单号
+            String refundId = refundDetail.get("refund_id");          // 微信退款ID
+            System.err.println("退款回调成功,订单号:"+orderNo+",退款号:"+refundNo+",状态:{}"+refundId);
+            RefundCallbackResult refundCallbackResult = RefundCallbackResult.success();
+            refundCallbackResult.setOrderNo(orderNo);
+            refundCallbackResult.setRefundNo(refundId);
+
+            return refundCallbackResult;
+
+        } catch (Exception e) {
+            return RefundCallbackResult.fail("系统异常:" + e.getMessage());
+        }
+    }
+
+    private static String wxDecrypt(String req_info, String key)  throws NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException,
+            InvalidKeyException, BadPaddingException, IllegalBlockSizeException{
+        byte[] decode = Base64.getDecoder().decode(req_info);
+        System.out.println(Arrays.toString(decode));
+        String sign = MD5AndKL.MD5Encode(key, "UTF-8").toLowerCase();
+        System.out.println(sign);
+        if (Security.getProvider("BC") == null){
+            Security.addProvider(new BouncyCastleProvider());
+        }
+        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
+        SecretKeySpec secretKeySpec = new SecretKeySpec(sign.getBytes(), "AES");
+        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
+        return new String(cipher.doFinal(decode));
+    }
+
+    /**
+     * 获取RSA加密公钥
+     */
+    public String getRsaPublicKey() {
+        int maxRetries = 3;
+        for (int retryCount = 0; retryCount < maxRetries; retryCount++) {
+            try {
+                System.out.println("尝试获取RSA公钥,第" + (retryCount + 1) + "次");
+
+                // 构建请求参数
+                Map<String, String> params = new HashMap<>();
+                params.put("mch_id", wechatPayConfig.getMchId());
+                params.put("sign_type", "MD5");
+                params.put("nonce_str", generateNonceStr());
+
+                // 生成签名
+                String sign = weixinSignature(params);
+                params.put("sign", sign);
+
+                // 转换为XML
+                String xmlParams = XMLUtil.mapToXml(params);
+
+                // 打印请求参数
+                System.out.println("请求参数: " + xmlParams);
+
+                // 使用证书发送请求(关键修改:使用postWithCert而非普通HTTP请求)
+                String result = postWithCert("https://fraud.mch.weixin.qq.com/risk/getpublickey", xmlParams);
+
+                // 打印响应结果
+                System.out.println("响应结果: " + result);
+
+                // 解析结果
+                Map<String, String> resultMap = XMLUtil.xmlToMap(result);
+                System.out.println("获取RSA公钥结果: " + resultMap);
+
+                // 检查返回状态
+                if (!"SUCCESS".equals(resultMap.get("return_code"))) {
+                    throw new Exception("RSA公钥获取失败: " + resultMap.get("return_msg"));
+                }
+
+                // 保存公钥到本地文件
+                savePublicKeyToClasspath(resultMap.get("pub_key"));
+
+                return resultMap.get("pub_key");
+            } catch (Exception e) {
+                System.err.println("获取RSA公钥异常: " + e.getMessage() + ", 重试次数: " + (retryCount + 1));
+                e.printStackTrace();
+
+                // 如果是最后一次重试,抛出异常
+                if (retryCount == maxRetries - 1) {
+                    return null;
+                }
+
+                // 重试前等待一段时间
+                try {
+                    Thread.sleep(1000 * (retryCount + 1)); // 指数退避
+                } catch (InterruptedException ie) {
+                    Thread.currentThread().interrupt();
+                    return null;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * 保存RSA公钥到文件夹
+     * @param publicKey RSA公钥内容
+     */
+    private static void savePublicKeyToClasspath(String publicKey) throws IOException {
+        // 创建 cert 目录(如果不存在)
+        Path certDir = Paths.get(CERT_FOLDER);
+        if (!Files.exists(certDir)) {
+            Files.createDirectories(certDir); // 自动创建目录
+        }
+
+        // 写入公钥文件(UTF-8 编码)
+        Path keyFile = certDir.resolve(RSA_PUBLIC_KEY_FILENAME);
+        Files.write(keyFile, publicKey.getBytes(StandardCharsets.UTF_8));
+    }
+    /**
+     * 从文件夹加载RSA公钥
+     * @return RSA公钥内容
+     */
+    private static String loadPublicKeyFromClasspath() throws IOException {
+        Path keyFile = Paths.get(CERT_FOLDER + RSA_PUBLIC_KEY_FILENAME);
+        byte[] bytes = Files.readAllBytes(keyFile); // 读取所有字节
+        return new String(bytes, StandardCharsets.UTF_8); // 转为UTF-8字符串
+    }
+
+    /**
+     * 加载公钥 返回PublicKey
+     */
+    public static PublicKey loadPublicKey(String pemContent) throws Exception {
+        // 读取PEM文件内容
+//        String pemContent = new String(Files.readAllBytes(Paths.get(CERT_FOLDER + RSA_PUBLIC_KEY_FILENAME)), StandardCharsets.UTF_8);
+
+        // 移除PEM头尾标记
+        String publicKeyPEM = pemContent
+                .replace("-----BEGIN RSA PUBLIC KEY-----", "")
+                .replace("-----END RSA PUBLIC KEY-----", "")
+                .replaceAll("\\s", ""); // 去除换行/空格
+
+        // 解码Base64
+        byte[] encoded = Base64.getDecoder().decode(publicKeyPEM);
+
+        // 手动解析PKCS#1格式
+        DerInputStream derReader = new DerInputStream(encoded);
+        DerValue[] seq = derReader.getSequence(0);
+        BigInteger modulus = seq[0].getBigInteger();
+        BigInteger exponent = seq[1].getBigInteger();
+
+        RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, exponent);
+        return KeyFactory.getInstance("RSA").generatePublic(keySpec);
+    }
+
+    /**
+     * 使用RSA-OAEP加密数据
+     * @param plaintext 待加密的明文
+     * @return Base64编码的密文
+     */
+    public static String encrypt(String plaintext, PublicKey publicKey) throws Exception {
+        Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING");
+        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
+
+        byte[] encryptedBytes = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
+        return Base64.getEncoder().encodeToString(encryptedBytes);
+    }
+
+
+
+    /**
+     * 商户付款到银行卡(优先使用本地保存的公钥)
+     * @param partnerTradeNo 商户订单号
+     * @param bankNo 银行卡号
+     * @param trueName 银行卡真实姓名
+     * @param bankCode 银行编码
+     * @param amount 金额(分)
+     * @param desc 付款说明
+     * @return 付款结果
+     */
+    public Map<String, String> payToBankCard(String partnerTradeNo, String bankNo, String trueName,
+                                             String bankCode, BigDecimal amount, String desc) throws Exception {
+        int i = amount.multiply(new BigDecimal("100")).intValue();
+        // 1. 尝试从本地加载RSA公钥
+        String pubKey = loadPublicKeyFromClasspath();
+
+        // 2. 如果本地没有公钥或公钥无效,则从微信获取新公钥
+        if (pubKey == null || pubKey.isEmpty()) {
+            pubKey = getRsaPublicKey();
+
+        }
+        //公钥对象
+        PublicKey publicKey = loadPublicKey(pubKey);
+
+        // 3. 使用RSA公钥加密银行卡号和真实姓名
+        String encryptedBankNo = encrypt(bankNo, publicKey);
+        String encryptedTrueName = encrypt(trueName, publicKey);
+
+        // 4. 构建请求参数
+        Map<String, String> params = new HashMap<>();
+        params.put("mch_id", wechatPayConfig.getMchId());
+        params.put("partner_trade_no", partnerTradeNo);
+        params.put("enc_bank_no", encryptedBankNo);
+        params.put("enc_true_name", encryptedTrueName);
+        params.put("bank_code", bankCode);
+        params.put("amount", String.valueOf(i));
+        params.put("desc", desc);
+        params.put("nonce_str", generateNonceStr());
+
+        // 生成签名
+        String sign = weixinSignature(params);
+        params.put("sign", sign);
+
+        // 将参数转换为XML
+        String xmlParams = XMLUtil.mapToXml(params);
+
+        // 5. 发送请求到微信支付付款到银行卡接口
+        String url = "https://api.mch.weixin.qq.com/mmpaysptrans/pay_bank";
+        String result = postWithCert(url, xmlParams);
+
+        // 解析返回结果
+        Map<String, String> resultMap = XMLUtil.xmlToMap(result);
+
+        // 验证签名
+        if (!verifySign(resultMap, wechatPayConfig.getKey())) {
+            throw new Exception("付款到银行卡签名验证失败");
+        }
+
+        return resultMap;
+    }
+
+    public static void main(String[] args) throws IOException {
+/*
+        try {
+            // 1. 加载公钥
+            PublicKey publicKey = loadPublicKey();
+
+            // 2. 加密数据
+            String sensitiveData = "用户名";
+            String encryptedData = encrypt(sensitiveData, publicKey);
+
+            System.out.println("加密结果(Base64):\n" + encryptedData);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }*/
+
+        String info="CjlaS7RVnPn7zzP5ByZDxUN7OrXGp1/DEdO0qahpIqDH/gTNHb/U7VmrVV0S4lXrIa0N8FEREC3CdIeT4XB5P4D0E8TSURu6J/cD01hFu2/uJOvcE6EeQH2xiRg/Wir4qcW7c6uTiLoqyirCQXcGzQb3CCcJf7OZWaweOUkaKjaBRa1GzMZcguSZnQJz0cD5jTMx+Tch5+b7jBq5PrTFxtMSH/DAG+kgkRazDFnEzkMeT4V+FViw8f8sjkH0TScMgWBiSKmQC837BLD27yIGklqlYkDP2IMeiNw+b12qCAGszfp2vYd3X+HpViXkQQet3PJWYlAm55R+IgvschP7Ub65XzLINfQrJKrQUXiKKO2LwoSRSwZvfDkR8G8E8X59CnU2XvWKeos5Y0q8ckbJb97yI+09nNgMjYyJoVCVjTGc7ghcYvWKbqanJ8bSFqiBCIqLSXsRR2DmJIxHq9fGE72kCJyJEAqLPMNyfYBSNF8z1btjyz0+y/xQQcySKlQInZ710FxSE7KwRSBQ92j9nDdlR7UxCrPVCkEd+GrVNSqqnyjNh1J/rPJPHvvGwkPPq72TKiw6ZgaIgIDhy0/lWHTclo4sjYAWuUVfg3CJ8dqkuQwVZ7i0+NiahIl78RtcUph8NR48yUgBkN7WhCcu5wLbg2tu8Qe0SIwHF+RW1x9Yc8akEkNbMd4xzs8lY5MYEU9V16U8RyWJuwPDph3RnmV8HQ+2hfzmjCvPkBwtfR8P5VdK86OIsHfnfQxAcPM2a86tOBBzFXPrLHgd2CRcDKH+MXTw7RSH/bk1PiMUAWF8TQsNDzgUlznJnkjiQxoym/4ZUf4C6072KKQHbp6bgBYkBhJLT2lmjVMNSX5b1SXM9eTQixRfq6MKGw3P8XJnKdofktVv+KtSzWQlW0C8p504NWACiExupF5EII7FG+xbTa/s7vxXCP7R98tpcQTGoQCLVv6UBCXt/t9iWlvs6SfuZhpCexeMmZWeiIldzRu87U9rXR46Hu7DAL8dZ+0ItsIZYThSIABzZgaLKggXlkjyAcbcPYKO7egrCmDtFhwN50V7hoXEQB8G5kf/lMuT5+xNE2FRmv7H2a0ttZiv4u17W5R8Ez9kubydeAgC9PkWnjptaubPxE0bjPN69tec";
+        String key="fD0JzscfMf295SYtRK3MnPRjSCA4Gahr";
+        try {
+            String decrypted = decrypt(info, key);
+            System.out.println("解密结果: " + decrypted);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+
+    public static String decrypt(String encryptedStringA, String merchantKey) throws Exception {
+        try {
+            byte[] decode = Base64.getDecoder().decode(encryptedStringA);
+            String sign = MD5AndKL.MD5Encode(merchantKey, "UTF-8").toLowerCase();
+            System.out.println("MD5 Key: " + sign); // 调试输出
+
+            if (Security.getProvider("BC") == null) {
+                Security.addProvider(new BouncyCastleProvider());
+            }
+
+            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
+            byte[] aesKey = Arrays.copyOf(sign.getBytes("UTF-8"), 16); // 明确指定 UTF-8
+            SecretKeySpec secretKeySpec = new SecretKeySpec(aesKey, "AES");
+            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
+
+            byte[] decryptedBytes = cipher.doFinal(decode);
+            return new String(decryptedBytes, "UTF-8"); // 明确指定 UTF-8
+        } catch (Exception e) {
+            System.err.println("解密失败: " + e.getMessage());
+            throw e;
+        }
+    }
+
+}
diff --git a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/util/payment/wx/XMLUtil.java b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/util/payment/wx/XMLUtil.java
new file mode 100644
index 0000000..1ea6998
--- /dev/null
+++ b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/util/payment/wx/XMLUtil.java
@@ -0,0 +1,52 @@
+package com.ruoyi.other.util.payment.wx;
+
+import org.dom4j.Document;
+import org.dom4j.DocumentException;
+import org.dom4j.DocumentHelper;
+import org.dom4j.Element;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * XML工具类
+ */
+public class XMLUtil {
+
+    /**
+     * 将Map转换为XML字符串
+     */
+    public static String mapToXml(Map<String, String> params) {
+        Document document = DocumentHelper.createDocument();
+        // 禁用XML声明
+        document.setXMLEncoding(null);  // 关键设置
+
+        Element root = document.addElement("xml");
+        for (Map.Entry<String, String> entry : params.entrySet()) {
+            String key = entry.getKey();
+            String value = entry.getValue() != null ? entry.getValue() : "";
+            root.addElement(key).setText(value);
+        }
+        
+        return document.asXML();
+    }
+    
+    /**
+     * 将XML字符串转换为Map
+     */
+    public static Map<String, String> xmlToMap(String xmlStr) throws DocumentException {
+        Map<String, String> map = new HashMap<>();
+        Document document = DocumentHelper.parseText(xmlStr);
+        Element root = document.getRootElement();
+
+        for (Iterator<?> iterator = root.elementIterator(); iterator.hasNext();) {
+            Element element = (Element) iterator.next();
+            // 关键修改:获取元素内所有内容(包括CDATA)
+            String value = element.getStringValue(); // 自动处理CDATA
+            map.put(element.getName(), value);
+        }
+
+        return map;
+    }
+}

--
Gitblit v1.7.1