From d1c4d003f62a7bd4bc762f2fc62b97726e247e0c Mon Sep 17 00:00:00 2001
From: xuhy <3313886187@qq.com>
Date: 星期五, 19 九月 2025 18:20:54 +0800
Subject: [PATCH] AI对接,微信小程序支付

---
 /dev/null                                                                    |   57 ---
 ruoyi-system/src/main/java/com/ruoyi/system/wxPay/utils/JsapiPrepay.java     |  118 +++++++
 ruoyi-admin/src/main/resources/application-test.yml                          |   25 +
 ruoyi-system/pom.xml                                                         |    8 
 ruoyi-system/src/main/java/com/ruoyi/system/wxPay/model/V3.java              |   31 +
 ruoyi-system/src/main/java/com/ruoyi/system/wxPay/utils/WXPayUtility.java    |  441 +++++++++++++++++++++++++++
 ruoyi-system/src/main/java/com/ruoyi/system/wxPay/utils/WxV3Pay.java         |  108 ++++--
 ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/WxPayController.java |  134 ++------
 8 files changed, 721 insertions(+), 201 deletions(-)

diff --git a/ruoyi-admin/src/main/resources/application-test.yml b/ruoyi-admin/src/main/resources/application-test.yml
index e94910b..ad0964c 100644
--- a/ruoyi-admin/src/main/resources/application-test.yml
+++ b/ruoyi-admin/src/main/resources/application-test.yml
@@ -214,4 +214,27 @@
   priKeyStr: C:\Users\Admin\Desktop\test\OP00000003_private_key.pem
   lklNotifyCerStr: C:\Users\Admin\Desktop\test\lkl-apigw-v2.cer
   sm4Key: LHo55AjrT4aDhAIBZhb5KQ==
-  serverUrl: https://test.wsmsd.cn/
\ No newline at end of file
+  serverUrl: https://test.wsmsd.cn/
+payment:
+  wx:
+    # 微信appid
+    appId: wxa17e8d1331e50934
+    # 微信商户号
+    mchId: 1721757915
+    # 秘钥
+    secretId: 79c234527fd3b6553679d52be5e29b19
+    v3:
+      # 加签串
+      apiKey: V7mKp9qL2Rs4jU6tX8wZ0bC3eF5hN1yD4gA
+      # 加签证书地址
+      privateKeyPath: D:/app/cert/weixin/apiclient_key.pem
+      # 微信支付公钥id
+      publicKeyId: PUB_KEY_ID_0117217579152025091800181718000000
+      # 微信支付公钥证书
+      publicKeyPath: D:/app/cert/weixin/apiclient_cert.pem
+      # 证书序列号
+      mchSerialNo: 39C7F6152E38A62B5786634D5C1F984FB5A38AD5
+      # 支付成功回调地址
+      notifyPayUrl: http://221.182.45.100/wx/pay/notify
+      # 支付退款回调地址
+      notifyRefundUrl: http://221.182.45.100/wx/refund/notify
\ No newline at end of file
diff --git a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/WxPayController.java b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/WxPayController.java
index d3c5629..8e049c0 100644
--- a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/WxPayController.java
+++ b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/WxPayController.java
@@ -1,8 +1,7 @@
 package com.ruoyi.web.controller.api;
 
+import com.alibaba.fastjson2.JSONObject;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.core.domain.R;
 import com.ruoyi.common.utils.CodeGenerateUtils;
 import com.ruoyi.framework.web.service.TokenService;
@@ -14,12 +13,11 @@
 import com.ruoyi.system.service.TSysInspectionService;
 import com.ruoyi.system.service.TSysOtherConfigService;
 import com.ruoyi.system.service.TSysPayRecordService;
-import com.ruoyi.system.wxPay.enums.RefundEnum;
 import com.ruoyi.system.wxPay.enums.TradeStateEnum;
 import com.ruoyi.system.wxPay.model.WeixinPayProperties;
-import com.ruoyi.system.wxPay.model.WxPaymentRefundModel;
 import com.ruoyi.system.wxPay.utils.WxTimeUtils;
 import com.ruoyi.system.wxPay.utils.WxV3Pay;
+import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
@@ -27,8 +25,11 @@
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
-import java.io.IOException;
+import javax.servlet.http.HttpServletResponse;
+import java.io.BufferedReader;
+import java.io.PrintWriter;
 import java.math.BigDecimal;
+import java.nio.charset.StandardCharsets;
 import java.util.Map;
 import java.util.Objects;
 
@@ -73,7 +74,7 @@
         String userId = tokenService.getLoginUserApplet().getUserId();
         TSysAppUser sysAppUser = sysAppUserService.getById(userId);
         // 价格
-        Integer totalPrice = sysOtherConfig.getAiPrice().multiply(new BigDecimal(100)).intValue();
+        Long totalPrice = sysOtherConfig.getAiPrice().multiply(new BigDecimal(100)).longValue();
         // 生成订单号
         String orderNo = CodeGenerateUtils.generateOrderSn();
         // 查询用户信息 用户openid
@@ -81,62 +82,41 @@
         // 存储支付记录
         sysPayRecordService.saveData(orderNo, userId, sysOtherConfig.getAiPrice(), 1);
         // 调用支付方法
-        Map<String, Object> result = wxV3Pay.jsApi(orderNo, totalPrice, openId,"AI检测报告支付");
+        Map<String, Object> result = wxV3Pay.jsApi(orderNo, totalPrice, openId,"AI检测报告支付","");
         log.info("支付参数:{}", result);
         return R.ok(result);
     }
 
     /**
-     * 微信v3支付-订单退款
-     *
-     * @return
-     */
-    @ApiOperation("订单退款")
-    @PostMapping(value = "refund-order")
-    public AjaxResult<String> refundOrder() {
-         Map<String, Object> result = wxV3Pay.refund(new WxPaymentRefundModel());
-         log.info("退款结果:{}", result);
-        // 微信支付退款单号
-        String refund_id = result.get("refund_id").toString();
-        // 商户退款单号
-        String out_refund_no = result.get("out_refund_no").toString();
-        // 微信支付订单号
-        String transaction_id = result.get("transaction_id").toString();
-        // 商户订单号 tradeNo
-        String out_trade_no = result.get("out_trade_no").toString();
-        // 退款成功时间
-        String success_time = Objects.nonNull(result.get("success_time")) ? result.get("success_time").toString() : null;
-        // 退款状态 RefundEnum
-        String status = result.get("status").toString();
-        // TODO 退款业务处理
-        return AjaxResult.success();
-    }
-    /**
      * 支付回调
      */
     @PostMapping("pay/notify")
     @ApiOperation("订单回调")
-    public void payNotify(HttpServletRequest request) throws Exception {
+    public void payNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
         try {
-            Map<String, Object> params = wxV3Pay.verifyNotify(request, new TypeReference<Map<String, Object>>() {});
-            log.info("支付回调:{}", params);
-            // 商户订单号
-            String tradeNo = params.get("out_trade_no").toString();
-            // 交易状态
-            String trade_state = params.get("trade_state").toString();
-            // 交易状态描述
-            String trade_state_desc = params.get("trade_state_desc").toString();
-            // 微信支付订单号
-            String transaction_id = params.get("transaction_id").toString();
-            // 支付完成时间
-            // 时间不对的话,可以调用  WxTimeUtils.toRfc3339Date(success_time)转换一下
-            String success_time = params.get("success_time").toString();
-            // 附加数据
-            Integer attach = Integer.parseInt(params.get("attach").toString());
+            System.err.println("微信回调");
+            BufferedReader reader = request.getReader();
+            StringBuilder requestBody = new StringBuilder();
+            String line;
+            while ((line = reader.readLine()) != null) {
+                requestBody.append(line);
+            }
+            System.err.println("全部请求体" + requestBody);
+            JSONObject jsonObject = JSONObject.parseObject(requestBody.toString());
+            JSONObject resource = jsonObject.getJSONObject("resource");
+
+            AesUtil aesUtil = new AesUtil(weixinPayProperties.getV3().getApiKey().getBytes(StandardCharsets.UTF_8));
+            String decryptedData = aesUtil.decryptToString(resource.getString("associated_data").getBytes(StandardCharsets.UTF_8), resource.getString("nonce").getBytes(StandardCharsets.UTF_8),
+                    resource.getString("ciphertext"));
+            System.err.println("微信解密的字符串信息" + decryptedData);
+            JSONObject jsonInfo = JSONObject.parse(decryptedData);
+            String out_trade_no = jsonInfo.getString("out_trade_no");
+            String transaction_id = jsonInfo.getString("transaction_id");
+            String trade_state = jsonInfo.getString("trade_state");
+            String success_time = jsonInfo.getString("success_time");
             // 查询订单
             TSysPayRecord sysPayRecord = sysPayRecordService.getOne(Wrappers.lambdaQuery(TSysPayRecord.class)
-                    .eq(TSysPayRecord::getOrderNo, tradeNo).last("LIMIT 1"));
-            // 处理订单
+                    .eq(TSysPayRecord::getOrderNo, out_trade_no).last("LIMIT 1"));
             if (trade_state.equals(TradeStateEnum.SUCCESS.name())) {
                 log.info("回调成功");
                 // 订单号查询订单
@@ -150,60 +130,14 @@
                 sysInspection.setIsPay(1);
                 sysInspectionService.updateById(sysInspection);
 
-                wxV3Pay.ack();
+                PrintWriter out = response.getWriter();
+                out.print("SUCCESS");
+                out.flush();
+                out.close();
             }
-            wxV3Pay.ack();
         } catch (Exception e) {
             log.error("支付回调异常:{}", e, e);
             wxV3Pay.ack(false, e.getMessage());
         }
     }
-    
-    /**
-     * 支付回调成功后
-     */
-    @PostMapping("pay/ack")
-    public void ack(){
-        try {
-            wxV3Pay.ack();
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-    }
-    
-    
-    
-
-    /**
-     * 退款回调
-     */
-    @PostMapping("refund/notify")
-    public void refundNotify(HttpServletRequest request) throws IOException {
-        try {
-            Map<String, Object> params = wxV3Pay.verifyNotify(request, new TypeReference<Map<String, Object>>() {
-            });
-            // 商户订单号
-            String out_trade_no = params.get("out_trade_no").toString();
-            // 商户退款单号
-            String out_refund_no = params.get("out_refund_no").toString();
-            // 微信支付订单号
-            String transaction_id = params.get("transaction_id").toString();
-            // 微信支付退款单号
-            String refund_id = params.get("refund_id").toString();
-            // 退款状态
-            String tradeState = params.get("refund_status").toString();
-            // 退款成功时间
-            // 时间不对的话,可以调用  WxTimeUtils.toRfc3339Date(success_time)转换一下
-            String success_time = params.get("success_time").toString();
-            if (tradeState.equals(RefundEnum.SUCCESS.name())) {
-                wxV3Pay.ack();
-            } else {
-                wxV3Pay.ack(false, "不是成功的退款状态");
-            }
-        } catch (Exception e) {
-            e.printStackTrace();
-            wxV3Pay.ack(false, e.getMessage());
-        }
-    }
-    
 }
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/config/WxConfig.java b/ruoyi-common/src/main/java/com/ruoyi/common/config/WxConfig.java
deleted file mode 100644
index 770412a..0000000
--- a/ruoyi-common/src/main/java/com/ruoyi/common/config/WxConfig.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.ruoyi.common.config;
-
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.stereotype.Component;
-
-
-/**
- * 项目中需继承此类
- *
- * @author lihen
- */
-@Data
-@Component
-@ConfigurationProperties(prefix = "wx.config")
-public class WxConfig {
-
-    /**
-     * 获取 App ID
-     *
-     * @return App ID
-     */
-    @JsonProperty("appId")
-    private String appId;
-
-    /**
-     * 获取 Secret
-     *
-     * @return Secret
-     */
-    @JsonProperty("secret")
-    private String secret;
-
-
-}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/WxAppletTools.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/WxAppletTools.java
deleted file mode 100644
index 7c6ee85..0000000
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/WxAppletTools.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package com.ruoyi.common.utils;
-
-import com.alibaba.fastjson2.JSONObject;
-import com.ruoyi.common.config.WxConfig;
-import com.ruoyi.common.core.redis.RedisCache;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-import org.springframework.util.StringUtils;
-import org.springframework.web.client.RestTemplate;
-
-import java.text.MessageFormat;
-
-/**
- * @author liheng
- * @ClassName WxAppletTools
- * @Description
- * @date 2020-12-04 13:55
- */
-@Slf4j
-@Component
-public class WxAppletTools {
-    @Autowired
-    private RedisCache redisCache;
-    @Autowired
-    private RestTemplate restTemplate;
-    @Autowired
-    private WxConfig wxConfig;
-    private final static String ACCESSTOKEN_CACHE_KEY = "accessToken";
-    /**
-     * 请求参数
-     * 属性	类型	默认值	必填	说明
-     * appid	string		是	小程序 appId
-     * secret	string		是	小程序 appSecret
-     * js_code	string		是	登录时获取的 code
-     * grant_type	string		是	授权类型,此处只需填写 authorization_cod
-     * <p>
-     * 返回值:
-     * <p>
-     * 属性	类型	说明
-     * openid	string	用户唯一标识
-     * session_key	string	会话密钥
-     * unionid	string	用户在开放平台的唯一标识符,若当前小程序已绑定到微信开放平台帐号下会返回,详见 UnionID 机制说明。
-     * errcode	number	错误码
-     * errmsg	string	错误信息
-     */
-    private static final String JSCODE_2_SESSION_URL = "https://api.weixin.qq.com/sns/jscode2session?appid={0}&secret={1}&js_code={2}&grant_type=authorization_code";
-
-
-    /**
-     * 请求参数
-     * 属性	类型	默认值	必填	说明
-     * grant_type	string		是	填写 client_credential
-     * appid	string		是	小程序唯一凭证,即 AppID,可在「微信公众平台 - 设置 - 开发设置」页中获得。(需要已经成为开发者,且帐号没有异常状态)
-     * secret	string		是	小程序唯一凭证密钥,即 AppSecret,获取方式同 appid
-     * 返回值
-     * Object
-     * 返回的 JSON 数据包
-     * <p>
-     * 属性	类型	说明
-     * access_token	string	获取到的凭证
-     * expires_in	number	凭证有效时间,单位:秒。目前是7200秒之内的值。
-     * errcode	number	错误码
-     * errmsg	string	错误信息
-     */
-    private static String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}";
-
-    /**
-     * @return
-     */
-    public String getAccessToken() {
-        String requestUrl = MessageFormat.format(ACCESS_TOKEN_URL, wxConfig.getAppId(), wxConfig.getSecret());
-        String respBody = restTemplate.getForEntity(requestUrl, String.class).getBody();
-        JSONObject jsonObject = JSONObject.parseObject(respBody);
-        return jsonObject.getString("access_token");
-    }
-}
diff --git a/ruoyi-system/pom.xml b/ruoyi-system/pom.xml
index cca3bb2..5c28a56 100644
--- a/ruoyi-system/pom.xml
+++ b/ruoyi-system/pom.xml
@@ -96,8 +96,14 @@
         </dependency>
         <dependency>
             <groupId>com.github.wechatpay-apiv3</groupId>
+            <artifactId>wechatpay-java-core</artifactId>
+            <version>0.2.12</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.github.wechatpay-apiv3</groupId>
             <artifactId>wechatpay-apache-httpclient</artifactId>
-            <version>0.4.3</version>
+            <version>0.4.9</version>
         </dependency>
     </dependencies>
 
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/task/utils/TaskUtil.java b/ruoyi-system/src/main/java/com/ruoyi/system/task/utils/TaskUtil.java
deleted file mode 100644
index a0cec7c..0000000
--- a/ruoyi-system/src/main/java/com/ruoyi/system/task/utils/TaskUtil.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package com.ruoyi.system.task.utils;
-
-
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.ruoyi.common.constant.CacheConstants;
-import com.ruoyi.common.core.redis.RedisCache;
-import com.ruoyi.common.utils.uuid.UUID;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Component;
-
-import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.time.temporal.ChronoUnit;
-import java.util.List;
-
-/**
- * @author zhibing.pu
- * @date 2023/7/11 8:39
- */
-@Component
-public class TaskUtil {
-    @Autowired
-    RedisCache redisCache;
-    // 用于更新违约金账单
-    // 每分钟执行一次的定时任务
-
-    @Scheduled(cron = "0 0 0 * * ?")
-    public void dayOfProportionBill() {
-        try {
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-    }
-
-    public static void main(String[] args) {
-
-//        LocalDateTime now = LocalDateTime.now().minusMonths(1).withDayOfMonth(31);
-//        System.err.println(now);
-//        LocalDateTime now2 = now.plusMonths(1);
-//        System.err.println(now2);
-//
-//        LocalDateTime now1 = LocalDateTime.now();
-//        long days = ChronoUnit.DAYS.between(now, now1);
-//        long days2 = ChronoUnit.DAYS.between(now.plusDays(1), now1);
-//
-//        System.err.println(days);
-//        System.err.println(days2);
-//        LocalDateTime endTime = now.with(TemporalAdjusters.lastDayOfMonth()).withSecond(59).withHour(23).withMinute(59);
-//
-//        System.err.println(endTime);
-
-    }
-
-}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/wxPay/model/V3.java b/ruoyi-system/src/main/java/com/ruoyi/system/wxPay/model/V3.java
index cdcbfc9..18062cb 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/wxPay/model/V3.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/wxPay/model/V3.java
@@ -28,6 +28,14 @@
      */
     private String privateKeyPath;
     /**
+     * 微信支付公钥id
+     */
+    private String publicKeyId;
+    /**
+     * 微信支付公钥证书 apiclient_cert.pem
+     */
+    private String publicKeyPath;
+    /**
      * 商户证书序列号
      */
     private String  mchSerialNo;
@@ -74,4 +82,27 @@
         }
         return new ByteArrayInputStream(certData);
     }
+
+    public InputStream getPublicKeyStream() {
+        // 需要证书释放
+        byte[] certData;
+//        InputStream certStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(this.privateKeyPath);
+        InputStream certStream = null;
+        try {
+            certStream = new FileInputStream(this.publicKeyPath);
+            certData = IOUtils.toByteArray(certStream);
+        } catch (IOException e) {
+            e.printStackTrace();
+            throw new RuntimeException("公钥文件未找到");
+        }finally {
+            if(null != certStream){
+                try {
+                    certStream.close();
+                } catch (IOException e) {
+                    log.error("公钥流关闭异常");
+                }
+            }
+        }
+        return new ByteArrayInputStream(certData);
+    }
 }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/wxPay/utils/JsapiPrepay.java b/ruoyi-system/src/main/java/com/ruoyi/system/wxPay/utils/JsapiPrepay.java
new file mode 100644
index 0000000..ded7b52
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/wxPay/utils/JsapiPrepay.java
@@ -0,0 +1,118 @@
+package com.ruoyi.system.wxPay.utils;
+
+
+import com.google.gson.annotations.SerializedName;
+import okhttp3.*;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+/**
+ * JSAPI下单
+ */
+public class JsapiPrepay {
+  private static String HOST = "https://api.mch.weixin.qq.com";
+  private static String METHOD = "POST";
+  private static String PATH = "/v3/pay/transactions/jsapi";
+  private final String mchId;
+  private final String certificateSerialNo;
+  private final PrivateKey privateKey;
+  private final String wechatPayPublicKeyId;
+  private final PublicKey wechatPayPublicKey;
+
+  public JsapiPrepay(String mchId, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
+    this.mchId = mchId;
+    this.certificateSerialNo = certificateSerialNo;
+    this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
+    this.wechatPayPublicKeyId = wechatPayPublicKeyId;
+    this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
+  }
+
+  public DirectAPIv3JsapiPrepayResponse run(DirectAPIv3JsapiPrepayRequest request) {
+    String uri = PATH;
+    String reqBody = WXPayUtility.toJson(request);
+
+    Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
+    reqBuilder.addHeader("Accept", "application/json");
+    reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
+    reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchId, certificateSerialNo,privateKey, METHOD, uri, reqBody));
+    reqBuilder.addHeader("Content-Type", "application/json");
+    RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody);
+    reqBuilder.method(METHOD, requestBody);
+    Request httpRequest = reqBuilder.build();
+
+    // 发送HTTP请求
+    OkHttpClient client = new OkHttpClient.Builder().build();
+    try (Response httpResponse = client.newCall(httpRequest).execute()) {
+      String respBody = WXPayUtility.extractBody(httpResponse);
+      if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
+        // 2XX 成功,验证应答签名
+        WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
+            httpResponse.headers(), respBody);
+
+        // 从HTTP应答报文构建返回数据
+        return WXPayUtility.fromJson(respBody, DirectAPIv3JsapiPrepayResponse.class);
+      } else {
+        throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
+      }
+    } catch (IOException e) {
+      throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
+    }
+  }
+  public static class DirectAPIv3JsapiPrepayRequest {
+    @SerializedName("appid")
+    public String appid;
+  
+    @SerializedName("mchid")
+    public String mchid;
+  
+    @SerializedName("description")
+    public String description;
+  
+    @SerializedName("out_trade_no")
+    public String outTradeNo;
+  
+    @SerializedName("time_expire")
+    public String timeExpire;
+  
+    @SerializedName("attach")
+    public String attach;
+  
+    @SerializedName("notify_url")
+    public String notifyUrl;
+  
+    @SerializedName("goods_tag")
+    public String goodsTag;
+  
+    @SerializedName("support_fapiao")
+    public Boolean supportFapiao;
+  
+    @SerializedName("amount")
+    public CommonAmountInfo amount;
+
+    @SerializedName("payer")
+    public JsapiReqPayerInfo payer;
+
+  }
+  
+  public static class DirectAPIv3JsapiPrepayResponse {
+    @SerializedName("prepay_id")
+    public String prepayId;
+  }
+  
+  public static class CommonAmountInfo {
+    @SerializedName("total")
+    public Long total;
+
+    @SerializedName("currency")
+    public String currency;
+  }
+
+  public static class JsapiReqPayerInfo {
+    @SerializedName("openid")
+    public String openid;
+  }
+
+}
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/wxPay/utils/WXPayUtility.java b/ruoyi-system/src/main/java/com/ruoyi/system/wxPay/utils/WXPayUtility.java
new file mode 100644
index 0000000..834edae
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/wxPay/utils/WXPayUtility.java
@@ -0,0 +1,441 @@
+package com.ruoyi.system.wxPay.utils;
+
+import com.google.gson.*;
+import com.google.gson.annotations.Expose;
+import com.wechat.pay.java.core.util.GsonUtil;
+import okhttp3.Headers;
+import okhttp3.Response;
+import okio.BufferedSource;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.security.*;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.time.DateTimeException;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Base64;
+import java.util.Map;
+import java.util.Objects;
+
+public class WXPayUtility {
+  private static final Gson gson = new GsonBuilder()
+      .disableHtmlEscaping()
+      .addSerializationExclusionStrategy(new ExclusionStrategy() {
+        @Override
+        public boolean shouldSkipField(FieldAttributes fieldAttributes) {
+          final Expose expose = fieldAttributes.getAnnotation(Expose.class);
+          return expose != null && !expose.serialize();
+        }
+
+        @Override
+        public boolean shouldSkipClass(Class<?> aClass) {
+          return false;
+        }
+      })
+      .addDeserializationExclusionStrategy(new ExclusionStrategy() {
+        @Override
+        public boolean shouldSkipField(FieldAttributes fieldAttributes) {
+          final Expose expose = fieldAttributes.getAnnotation(Expose.class);
+          return expose != null && !expose.deserialize();
+        }
+
+        @Override
+        public boolean shouldSkipClass(Class<?> aClass) {
+          return false;
+        }
+      })
+      .create();
+  private static final char[] SYMBOLS =
+      "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
+  private static final SecureRandom random = new SecureRandom();
+
+  /**
+   * 将 Object 转换为 JSON 字符串
+   */
+  public static String toJson(Object object) {
+    return gson.toJson(object);
+  }
+
+  /**
+   * 将 JSON 字符串解析为特定类型的实例
+   */
+  public static <T> T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException {
+    return gson.fromJson(json, classOfT);
+  }
+
+  /**
+   * 从公私钥文件路径中读取文件内容
+   *
+   * @param keyPath 文件路径
+   * @return 文件内容
+   */
+  private static String readKeyStringFromPath(String keyPath) {
+    try {
+      return new String(Files.readAllBytes(Paths.get(keyPath)), StandardCharsets.UTF_8);
+    } catch (IOException e) {
+      throw new UncheckedIOException(e);
+    }
+  }
+
+  /**
+   * 读取 PKCS#8 格式的私钥字符串并加载为私钥对象
+   *
+   * @param keyString 私钥文件内容,以 -----BEGIN PRIVATE KEY----- 开头
+   * @return PrivateKey 对象
+   */
+  public static PrivateKey loadPrivateKeyFromString(String keyString) {
+    try {
+      keyString = keyString.replace("-----BEGIN PRIVATE KEY-----", "")
+          .replace("-----END PRIVATE KEY-----", "")
+          .replaceAll("\\s+", "");
+      return KeyFactory.getInstance("RSA").generatePrivate(
+          new PKCS8EncodedKeySpec(Base64.getDecoder().decode(keyString)));
+    } catch (NoSuchAlgorithmException e) {
+      throw new UnsupportedOperationException(e);
+    } catch (InvalidKeySpecException e) {
+      throw new IllegalArgumentException(e);
+    }
+  }
+
+  /**
+   * 从 PKCS#8 格式的私钥文件中加载私钥
+   *
+   * @param keyPath 私钥文件路径
+   * @return PrivateKey 对象
+   */
+  public static PrivateKey loadPrivateKeyFromPath(String keyPath) {
+    return loadPrivateKeyFromString(readKeyStringFromPath(keyPath));
+  }
+
+  /**
+   * 读取 PKCS#8 格式的公钥字符串并加载为公钥对象
+   *
+   * @param keyString 公钥文件内容,以 -----BEGIN PUBLIC KEY----- 开头
+   * @return PublicKey 对象
+   */
+  public static PublicKey loadPublicKeyFromString(String keyString) {
+    try {
+      keyString = keyString.replace("-----BEGIN PUBLIC KEY-----", "")
+          .replace("-----END PUBLIC KEY-----", "")
+          .replaceAll("\\s+", "");
+      return KeyFactory.getInstance("RSA").generatePublic(
+          new X509EncodedKeySpec(Base64.getDecoder().decode(keyString)));
+    } catch (NoSuchAlgorithmException e) {
+      throw new UnsupportedOperationException(e);
+    } catch (InvalidKeySpecException e) {
+      throw new IllegalArgumentException(e);
+    }
+  }
+
+  /**
+   * 从 PKCS#8 格式的公钥文件中加载公钥
+   *
+   * @param keyPath 公钥文件路径
+   * @return PublicKey 对象
+   */
+  public static PublicKey loadPublicKeyFromPath(String keyPath) {
+    return loadPublicKeyFromString(readKeyStringFromPath(keyPath));
+  }
+
+  /**
+   * 创建指定长度的随机字符串,字符集为[0-9a-zA-Z],可用于安全相关用途
+   */
+  public static String createNonce(int length) {
+    char[] buf = new char[length];
+    for (int i = 0; i < length; ++i) {
+      buf[i] = SYMBOLS[random.nextInt(SYMBOLS.length)];
+    }
+    return new String(buf);
+  }
+
+  /**
+   * 使用公钥按照 RSA_PKCS1_OAEP_PADDING 算法进行加密
+   *
+   * @param publicKey 加密用公钥对象
+   * @param plaintext 待加密明文
+   * @return 加密后密文
+   */
+  public static String encrypt(PublicKey publicKey, String plaintext) {
+    final String transformation = "RSA/ECB/OAEPWithSHA-1AndMGF1Padding";
+
+    try {
+      Cipher cipher = Cipher.getInstance(transformation);
+      cipher.init(Cipher.ENCRYPT_MODE, publicKey);
+      return Base64.getEncoder().encodeToString(cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8)));
+    } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
+      throw new IllegalArgumentException("The current Java environment does not support " + transformation, e);
+    } catch (InvalidKeyException e) {
+      throw new IllegalArgumentException("RSA encryption using an illegal publicKey", e);
+    } catch (BadPaddingException | IllegalBlockSizeException e) {
+      throw new IllegalArgumentException("Plaintext is too long", e);
+    }
+  }
+
+  /**
+   * 使用私钥按照指定算法进行签名
+   *
+   * @param message 待签名串
+   * @param algorithm 签名算法,如 SHA256withRSA
+   * @param privateKey 签名用私钥对象
+   * @return 签名结果
+   */
+  public static String sign(String message, String algorithm, PrivateKey privateKey) {
+    byte[] sign;
+    try {
+      Signature signature = Signature.getInstance(algorithm);
+      signature.initSign(privateKey);
+      signature.update(message.getBytes(StandardCharsets.UTF_8));
+      sign = signature.sign();
+    } catch (NoSuchAlgorithmException e) {
+      throw new UnsupportedOperationException("The current Java environment does not support " + algorithm, e);
+    } catch (InvalidKeyException e) {
+      throw new IllegalArgumentException(algorithm + " signature uses an illegal privateKey.", e);
+    } catch (SignatureException e) {
+      throw new RuntimeException("An error occurred during the sign process.", e);
+    }
+    return Base64.getEncoder().encodeToString(sign);
+  }
+
+  /**
+   * 使用公钥按照特定算法验证签名
+   *
+   * @param message 待签名串
+   * @param signature 待验证的签名内容
+   * @param algorithm 签名算法,如:SHA256withRSA
+   * @param publicKey 验签用公钥对象
+   * @return 签名验证是否通过
+   */
+  public static boolean verify(String message, String signature, String algorithm,
+                               PublicKey publicKey) {
+    try {
+      Signature sign = Signature.getInstance(algorithm);
+      sign.initVerify(publicKey);
+      sign.update(message.getBytes(StandardCharsets.UTF_8));
+      return sign.verify(Base64.getDecoder().decode(signature));
+    } catch (SignatureException e) {
+      return false;
+    } catch (InvalidKeyException e) {
+      throw new IllegalArgumentException("verify uses an illegal publickey.", e);
+    } catch (NoSuchAlgorithmException e) {
+      throw new UnsupportedOperationException("The current Java environment does not support" + algorithm, e);
+    }
+  }
+
+  /**
+   * 根据微信支付APIv3请求签名规则构造 Authorization 签名
+   *
+   * @param mchid 商户号
+   * @param certificateSerialNo 商户API证书序列号
+   * @param privateKey 商户API证书私钥
+   * @param method 请求接口的HTTP方法,请使用全大写表述,如 GET、POST、PUT、DELETE
+   * @param uri 请求接口的URL
+   * @param body 请求接口的Body
+   * @return 构造好的微信支付APIv3 Authorization 头
+   */
+  public static String buildAuthorization(String mchid, String certificateSerialNo,
+                                          PrivateKey privateKey,
+                                          String method, String uri, String body) {
+    String nonce = createNonce(32);
+    long timestamp = Instant.now().getEpochSecond();
+
+    String message = String.format("%s\n%s\n%d\n%s\n%s\n", method, uri, timestamp, nonce,
+        body == null ? "" : body);
+
+    String signature = sign(message, "SHA256withRSA", privateKey);
+
+    return String.format(
+        "WECHATPAY2-SHA256-RSA2048 mchid=\"%s\",nonce_str=\"%s\",signature=\"%s\"," +
+            "timestamp=\"%d\",serial_no=\"%s\"",
+        mchid, nonce, signature, timestamp, certificateSerialNo);
+  }
+
+  /**
+   * 对参数进行 URL 编码
+   *
+   * @param content 参数内容
+   * @return 编码后的内容
+   */
+  public static String urlEncode(String content) {
+    try {
+      return URLEncoder.encode(content, StandardCharsets.UTF_8.name());
+    } catch (UnsupportedEncodingException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  /**
+   * 对参数Map进行 URL 编码,生成 QueryString
+   *
+   * @param params Query参数Map
+   * @return QueryString
+   */
+  public static String urlEncode(Map<String, Object> params) {
+    if (params == null || params.isEmpty()) {
+      return "";
+    }
+
+    int index = 0;
+    StringBuilder result = new StringBuilder();
+    for (Map.Entry<String, Object> entry : params.entrySet()) {
+      result.append(entry.getKey())
+          .append("=")
+          .append(urlEncode(entry.getValue().toString()));
+      index++;
+      if (index < params.size()) {
+        result.append("&");
+      }
+    }
+    return result.toString();
+  }
+
+  /**
+   * 从应答中提取 Body
+   *
+   * @param response HTTP 请求应答对象
+   * @return 应答中的Body内容,Body为空时返回空字符串
+   */
+  public static String extractBody(Response response) {
+    if (response.body() == null) {
+      return "";
+    }
+
+    try {
+      BufferedSource source = response.body().source();
+      return source.readUtf8();
+    } catch (IOException e) {
+      throw new RuntimeException(String.format("An error occurred during reading response body. Status: %d", response.code()), e);
+    }
+  }
+
+  /**
+   * 根据微信支付APIv3应答验签规则对应答签名进行验证,验证不通过时抛出异常
+   *
+   * @param wechatpayPublicKeyId 微信支付公钥ID
+   * @param wechatpayPublicKey 微信支付公钥对象
+   * @param headers 微信支付应答 Header 列表
+   * @param body 微信支付应答 Body
+   */
+  public static void validateResponse(String wechatpayPublicKeyId, PublicKey wechatpayPublicKey,
+                                      Headers headers,
+                                      String body) {
+    String timestamp = headers.get("Wechatpay-Timestamp");
+    try {
+      Instant responseTime = Instant.ofEpochSecond(Long.parseLong(timestamp));
+      // 拒绝过期请求
+      if (Duration.between(responseTime, Instant.now()).abs().toMinutes() >= 5) {
+        throw new IllegalArgumentException(
+            String.format("Validate http response,timestamp[%s] of httpResponse is expires, "
+                    + "request-id[%s]",
+                timestamp, headers.get("Request-ID")));
+      }
+    } catch (DateTimeException | NumberFormatException e) {
+      throw new IllegalArgumentException(
+          String.format("Validate http response,timestamp[%s] of httpResponse is invalid, " +
+                  "request-id[%s]", timestamp,
+              headers.get("Request-ID")));
+    }
+    String message = String.format("%s\n%s\n%s\n", timestamp, headers.get("Wechatpay-Nonce"),
+        body == null ? "" : body);
+    String serialNumber = headers.get("Wechatpay-Serial");
+    if (!Objects.equals(serialNumber, wechatpayPublicKeyId)) {
+      throw new IllegalArgumentException(
+          String.format("Invalid Wechatpay-Serial, Local: %s, Remote: %s", wechatpayPublicKeyId,
+              serialNumber));
+    }
+    String signature = headers.get("Wechatpay-Signature");
+
+    boolean success = verify(message, signature, "SHA256withRSA", wechatpayPublicKey);
+    if (!success) {
+      throw new IllegalArgumentException(
+          String.format("Validate response failed,the WechatPay signature is incorrect.%n"
+                  + "Request-ID[%s]\tresponseHeader[%s]\tresponseBody[%.1024s]",
+              headers.get("Request-ID"), headers, body));
+    }
+  }
+
+  /**
+   * 微信支付API错误异常,发送HTTP请求成功,但返回状态码不是 2XX 时抛出本异常
+   */
+  public static class ApiException extends RuntimeException {
+    private static final long serialVersionUID = 2261086748874802175L;
+
+    private final int statusCode;
+    private final String body;
+    private final Headers headers;
+    private final String errorCode;
+    private final String errorMessage;
+
+    public ApiException(int statusCode, String body, Headers headers) {
+      super(String.format("微信支付API访问失败,StatusCode: [%s], Body: [%s], Headers: [%s]", statusCode, body, headers));
+      this.statusCode = statusCode;
+      this.body = body;
+      this.headers = headers;
+
+      if (body != null && !body.isEmpty()) {
+        JsonElement code;
+        JsonElement message;
+
+        try {
+          JsonObject jsonObject = GsonUtil.getGson().fromJson(body, JsonObject.class);
+          code = jsonObject.get("code");
+          message = jsonObject.get("message");
+        } catch (JsonSyntaxException ignored) {
+          code = null;
+          message = null;
+        }
+        this.errorCode = code == null ? null : code.getAsString();
+        this.errorMessage = message == null ? null : message.getAsString();
+      } else {
+        this.errorCode = null;
+        this.errorMessage = null;
+      }
+    }
+
+    /**
+     * 获取 HTTP 应答状态码
+     */
+    public int getStatusCode() {
+      return statusCode;
+    }
+
+    /**
+     * 获取 HTTP 应答包体内容
+     */
+    public String getBody() {
+      return body;
+    }
+
+    /**
+     * 获取 HTTP 应答 Header
+     */
+    public Headers getHeaders() {
+      return headers;
+    }
+
+    /**
+     * 获取 错误码 (错误应答中的 code 字段)
+     */
+    public String getErrorCode() {
+      return errorCode;
+    }
+
+    /**
+     * 获取 错误消息 (错误应答中的 message 字段)
+     */
+    public String getErrorMessage() {
+      return errorMessage;
+    }
+  }
+}
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/wxPay/utils/WxV3Pay.java b/ruoyi-system/src/main/java/com/ruoyi/system/wxPay/utils/WxV3Pay.java
index ff256ae..2ba770d 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/wxPay/utils/WxV3Pay.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/wxPay/utils/WxV3Pay.java
@@ -1,29 +1,21 @@
 package com.ruoyi.system.wxPay.utils;
 
-import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import com.ruoyi.system.utils.wx.tools.WxUtils;
 import com.ruoyi.system.wxPay.model.WeixinPayProperties;
 import com.ruoyi.system.wxPay.model.WxCloseOrderModel;
-import com.ruoyi.system.wxPay.model.WxPaymentInfoModel;
 import com.ruoyi.system.wxPay.model.WxPaymentRefundModel;
 import com.ruoyi.system.wxPay.resp.NotifyV3PayDecodeRespBody;
 import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
 import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
 import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
-import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
 import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
-import com.wechat.pay.contrib.apache.httpclient.cert.CertificatesManager;
 import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
 import lombok.Getter;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
 import org.apache.http.impl.client.CloseableHttpClient;
 
 import javax.servlet.http.HttpServletRequest;
-import java.nio.charset.StandardCharsets;
 import java.security.PrivateKey;
 import java.util.Map;
 
@@ -62,13 +54,6 @@
             checkWxConfig();
             this.privateKey = PemUtil.loadPrivateKey(config.getV3().getPrivateKeyStream());
             this.privateKeySigner = new PrivateKeySigner(config.getV3().getMchSerialNo(), privateKey);
-            // 获取证书管理器实例
-            CertificatesManager certificatesManager = CertificatesManager.getInstance();
-            // 向证书管理器增加需要自动更新平台证书的商户信息
-            certificatesManager.putMerchant(config.getMchId(), new WechatPay2Credentials(config.getMchId(),
-                    this.privateKeySigner), config.getV3().getApiKey().getBytes(StandardCharsets.UTF_8));
-            // 从证书管理器中获取verifier
-            this.verifier = certificatesManager.getVerifier(config.getMchId());
             this.validator = new WechatPay2Validator(verifier);
             this.builder = WechatPayHttpClientBuilder.create()
                     .withMerchant(config.getMchId(), config.getV3().getMchSerialNo(), this.privateKey)
@@ -122,37 +107,76 @@
      * @author xiaochen
      * @date 2022-03-22 12:47
      */
-    public Map<String, Object> jsApi(String tradeNo, Integer amount, String openid, String description) {
-        WxPaymentInfoModel requestBody = WxPaymentInfoModel.builder()
-                .mchid(this.config.getMchId())
-                .appid(this.config.getAppId())
-                .description(description)
-                .out_trade_no(tradeNo)
-//                .attach("")
-                .amount(WxPaymentInfoModel.Amount.builder().total(amount).build())
-                .payer(WxPaymentInfoModel.Payer.builder().openid(openid).build())
-                // 分不分账
-//                .settle_info(WxPaymentInfoModel.SettleInfo.builder().profit_sharing(true).build())
-                .build();
-        // 封装基础数据
-        String reqBody = buildBaseParam(requestBody
-                , this.config.getV3().getNotifyPayUrl());
-        //请求URL
-        HttpEntityEnclosingRequestBase httpPost = requestPost(
-                "/v3/pay/transactions/jsapi"
-                , this.config.getHttpReadTimeoutMs()
-                , this.config.getHttpConnectTimeoutMs()
-                , reqBody);
-        String repBody = result(httpClient, httpPost);
-        ObjectMapper om = new ObjectMapper();
+    public Map<String, Object> jsApi(String tradeNo, Long amount, String openid, String description,String attach) {
+        JsapiPrepay client = new JsapiPrepay(
+                this.config.getMchId(),                    // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/merchant/4013070756
+                this.config.getV3().getMchSerialNo(),         // 商户API证书序列号,如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013053053
+                this.config.getV3().getPrivateKeyPath(),     // 商户API证书私钥文件路径,本地文件路径
+                this.config.getV3().getPublicKeyId(),      // 微信支付公钥ID,如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013038816
+                this.config.getV3().getPublicKeyPath()           // 微信支付公钥文件路径,本地文件路径
+        );
+        JsapiPrepay.DirectAPIv3JsapiPrepayRequest request = new JsapiPrepay.DirectAPIv3JsapiPrepayRequest();
+        request.appid = this.config.getAppId();
+        request.mchid = this.config.getMchId();
+        request.description = description;
+        request.outTradeNo = tradeNo;
+//        request.timeExpire = "2018-06-08T10:34:56+08:00";
+        request.attach = attach;
+        request.notifyUrl = this.config.getCallBackUrl();
+        request.goodsTag = "WXG";
+        request.supportFapiao = false;
+        request.amount = new JsapiPrepay.CommonAmountInfo();
+        request.amount.total = amount;
+        request.amount.currency = "CNY";
+        request.payer = new JsapiPrepay.JsapiReqPayerInfo();
+        request.payer.openid = openid;
         try {
-            JsonNode rootNode = om.readTree(repBody);
-            String prepayId = rootNode.path("prepay_id").asText();
-            return wxTuneUp(this.privateKeySigner, requestBody.getAppid(), prepayId);
-        } catch (JsonProcessingException e) {
+            JsapiPrepay.DirectAPIv3JsapiPrepayResponse response = client.run(request);
+            return wxTuneUp(this.privateKeySigner, this.config.getAppId(), response.prepayId);
+        } catch (WXPayUtility.ApiException e) {
             throw new RuntimeException("获取支付数据错误!");
         }
     }
+//    /**
+//     * jsApi下单
+//     *
+//     * @param tradeNo     订单号
+//     * @param amount      金额 分
+//     * @param openid      openid
+//     * @param description 订单描述
+//     * @return java.util.Map<java.lang.String, java.lang.Object>
+//     * @author xiaochen
+//     * @date 2022-03-22 12:47
+//     */
+//    public Map<String, Object> jsApi(String tradeNo, Integer amount, String openid, String description) {
+//        WxPaymentInfoModel requestBody = WxPaymentInfoModel.builder()
+//                .mchid(this.config.getMchId())
+//                .appid(this.config.getAppId())
+//                .description(description)
+//                .out_trade_no(tradeNo)
+////                .attach("")
+//                .amount(WxPaymentInfoModel.Amount.builder().total(amount).build())
+//                .payer(WxPaymentInfoModel.Payer.builder().openid(openid).build())
+//                .build();
+//        // 封装基础数据
+//        String reqBody = buildBaseParam(requestBody
+//                , this.config.getV3().getNotifyPayUrl());
+//        //请求URL
+//        HttpEntityEnclosingRequestBase httpPost = requestPost(
+//                "/v3/pay/transactions/jsapi"
+//                , this.config.getHttpReadTimeoutMs()
+//                , this.config.getHttpConnectTimeoutMs()
+//                , reqBody);
+//        String repBody = result(httpClient, httpPost);
+//        ObjectMapper om = new ObjectMapper();
+//        try {
+//            JsonNode rootNode = om.readTree(repBody);
+//            String prepayId = rootNode.path("prepay_id").asText();
+//            return wxTuneUp(this.privateKeySigner, requestBody.getAppid(), prepayId);
+//        } catch (JsonProcessingException e) {
+//            throw new RuntimeException("获取支付数据错误!");
+//        }
+//    }
 
 
     /**

--
Gitblit v1.7.1