Browse Source

微信移动端支付

guomengjiao 5 months ago
parent
commit
a20a2883f7

+ 13 - 10
.idea/workspace.xml

@@ -30,6 +30,8 @@
   <component name="ChangeListManager">
     <list default="true" id="fc9366aa-6566-4981-8149-d75e02f8e884" name="默认的" comment="微信移动端支付">
       <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/modules/bjflapi/src/main/java/com/jeesite/modules/bjflapi/report/WebsiteUserOrderControllerApi.java" beforeDir="false" afterPath="$PROJECT_DIR$/modules/bjflapi/src/main/java/com/jeesite/modules/bjflapi/report/WebsiteUserOrderControllerApi.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/modules/report/src/main/java/com/jeesite/modules/report/service/WebsiteUserOrderService.java" beforeDir="false" afterPath="$PROJECT_DIR$/modules/report/src/main/java/com/jeesite/modules/report/service/WebsiteUserOrderService.java" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/modules/report/src/main/java/com/jeesite/modules/report/util/WxPayUtil.java" beforeDir="false" afterPath="$PROJECT_DIR$/modules/report/src/main/java/com/jeesite/modules/report/util/WxPayUtil.java" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/web/src/main/resources/config/application.yml" beforeDir="false" afterPath="$PROJECT_DIR$/web/src/main/resources/config/application.yml" afterDir="false" />
     </list>
@@ -108,6 +110,7 @@
       <recent name="D:\work\bjfl\admin_api\modules\report\src\main\java\com\jeesite\modules\report\web" />
     </key>
     <key name="MoveFile.RECENT_KEYS">
+      <recent name="D:\work\bjfl\admin_api\web\src\main\resources\cert" />
       <recent name="D:\Git\xiangxi\bjfl_web\modules\basedata\src\main\resources\mappings\modules\basedata" />
     </key>
     <key name="CopyClassDialog.RECENTS_KEY">
@@ -456,14 +459,7 @@
       <workItem from="1734579234738" duration="258000" />
       <workItem from="1734579502121" duration="1272000" />
       <workItem from="1734658594781" duration="126472000" />
-      <workItem from="1735184825354" duration="43102000" />
-    </task>
-    <task id="LOCAL-00007" summary="报告">
-      <created>1681204786000</created>
-      <option name="number" value="00007" />
-      <option name="presentableId" value="LOCAL-00007" />
-      <option name="project" value="LOCAL" />
-      <updated>1681204786000</updated>
+      <workItem from="1735184825354" duration="47732000" />
     </task>
     <task id="LOCAL-00008" summary="修复图片丢失">
       <created>1681366727600</created>
@@ -801,7 +797,14 @@
       <option name="project" value="LOCAL" />
       <updated>1735294213225</updated>
     </task>
-    <option name="localTasksCounter" value="56" />
+    <task id="LOCAL-00056" summary="微信移动端支付">
+      <created>1735525419724</created>
+      <option name="number" value="00056" />
+      <option name="presentableId" value="LOCAL-00056" />
+      <option name="project" value="LOCAL" />
+      <updated>1735525419724</updated>
+    </task>
+    <option name="localTasksCounter" value="57" />
     <servers />
   </component>
   <component name="TypeScriptGeneratedFilesManager">
@@ -893,7 +896,7 @@
         </line-breakpoint>
         <line-breakpoint enabled="true" type="java-line">
           <url>file://$PROJECT_DIR$/modules/report/src/main/java/com/jeesite/modules/report/service/WebsiteUserOrderService.java</url>
-          <line>71</line>
+          <line>76</line>
           <option name="timeStamp" value="50" />
         </line-breakpoint>
       </breakpoints>

+ 12 - 0
modules/bjflapi/src/main/java/com/jeesite/modules/bjflapi/report/WebsiteUserOrderControllerApi.java

@@ -169,4 +169,16 @@ public class WebsiteUserOrderControllerApi extends AbstractController {
         return websiteUserOrderService.payAsyncNotify(paramMap);
     }
 
+    /**
+     * 微信的异步通知
+     */
+    @PostMapping(value = "/wxpay/asyncNotify")
+    public String wxpayAsyncNotify(@RequestBody String requestBody, HttpServletRequest request) {
+        String result = websiteUserOrderService.wxpayAsyncNotify(requestBody, request);
+        if ("success".equals(result)) {
+            return null;
+        } else {
+            return "{\"code\":\"FAIL\",\"message\":\"失败\"}";
+        }
+    }
 }

+ 58 - 16
modules/report/src/main/java/com/jeesite/modules/report/service/WebsiteUserOrderService.java

@@ -1,5 +1,6 @@
 package com.jeesite.modules.report.service;
 
+import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.alipay.api.AlipayApiException;
 import com.alipay.api.internal.util.AlipaySignature;
@@ -16,6 +17,8 @@ import com.jeesite.modules.report.entity.WebsiteUserOrder;
 import com.jeesite.modules.report.entity.WebsiteUserOrderDown;
 import com.jeesite.modules.report.util.AlipayUtil;
 import com.jeesite.modules.sys.utils.R;
+import com.wechat.pay.java.core.notification.NotificationParser;
+import com.wechat.pay.java.core.notification.RequestParam;
 import com.wechat.pay.java.service.payments.model.Transaction;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -44,6 +47,8 @@ public class WebsiteUserOrderService extends CrudService<WebsiteUserOrderDao, We
 	private WxPayService wxPayService;
 	@Resource
 	private WxPayH5Service wxPayH5Service;
+	@Resource
+	private NotificationParser notificationParser;
 
 	private static Logger logger = LoggerFactory.getLogger(WebsiteUserOrderService.class);
 	/**
@@ -194,22 +199,7 @@ public class WebsiteUserOrderService extends CrudService<WebsiteUserOrderDao, We
 			if (signVerified) {
 				// TODO 验签成功后,按照支付结果异步通知中的描述,对支付结果中的业务内容进行二次校验,校验成功后在response中返回success并继续商户自身业务处理,校验失败返回failure
 				if ("TRADE_SUCCESS".equals(trade_status) || "TRADE_FINISHED".equals(trade_status)) {
-					WebsiteUserOrder where = new WebsiteUserOrder();
-					where.setOrderNumber(out_trade_no);
-					where.setPayStatus(Constants.orderPayStatus.WAIT);
-					WebsiteUserOrder websiteUserOrder = dao.get(where);
-					if (websiteUserOrder == null) {
-						logger.error("zfb payAsyncNotify error {}订单不存在未支付", out_trade_no);
-					} else {
-						if (!total_amount.equals(websiteUserOrder.getPayPrice().toString())) {
-							logger.error("zfb payAsyncNotify amount不相等 {} {}", total_amount, websiteUserOrder.getPayPrice().toString());
-							return "failure";
-						}
-						websiteUserOrder.setPayStatus(Constants.orderPayStatus.PAY_SUCCESS);
-						websiteUserOrder.setPayDate(DateUtils.parseDateByFormat(gmt_payment, "yyyy-MM-dd HH:mm:ss"));
-						super.update(websiteUserOrder);
-					}
-					return "success";
+					return payUpdate(out_trade_no, total_amount, DateUtils.parseDateByFormat(gmt_payment, "yyyy-MM-dd HH:mm:ss"));
 				}
 			}
 		} catch (AlipayApiException e) {
@@ -219,6 +209,25 @@ public class WebsiteUserOrderService extends CrudService<WebsiteUserOrderDao, We
 		return "failure";
 	}
 
+	private String payUpdate(String out_trade_no, String total_amount, Date date) {
+		WebsiteUserOrder where = new WebsiteUserOrder();
+		where.setOrderNumber(out_trade_no);
+		where.setPayStatus(Constants.orderPayStatus.WAIT);
+		WebsiteUserOrder websiteUserOrder = dao.get(where);
+		if (websiteUserOrder == null) {
+			logger.error("payAsyncNotify error {}订单不存在未支付", out_trade_no);
+		} else {
+			if (!total_amount.equals(websiteUserOrder.getPayPrice().toString())) {
+				logger.error("payAsyncNotify amount不相等 {} {}", total_amount, websiteUserOrder.getPayPrice().toString());
+				return "failure";
+			}
+			websiteUserOrder.setPayStatus(Constants.orderPayStatus.PAY_SUCCESS);
+			websiteUserOrder.setPayDate(date);
+			super.update(websiteUserOrder);
+		}
+		return "success";
+	}
+
 	//定时任务会调用此方法
 //	@Scheduled(cron ="0 0/5 * * * ?")
 	public void zfbPayQuery() {
@@ -309,4 +318,37 @@ public class WebsiteUserOrderService extends CrudService<WebsiteUserOrderDao, We
 	public WebsiteUserOrder getOne(WebsiteUserOrder orderWhere) {
 		return super.get(orderWhere);
 	}
+
+
+	public String wxpayAsyncNotify(String requestBody, HttpServletRequest request) {
+		try {
+			logger.info("wx wxpayAsyncNotify 进来了 {}", requestBody);
+			// 随机串
+			String nonceStr = request.getHeader("Wechatpay-Nonce");
+			// 微信传递过来的签名
+			String signature = request.getHeader("Wechatpay-Signature");
+			// 证书序列号(微信平台)
+			String serialNo = request.getHeader("Wechatpay-Serial");
+			// 时间戳
+			String timestamp = request.getHeader("Wechatpay-Timestamp");
+			RequestParam requestParam = new RequestParam.Builder()
+					.serialNumber(serialNo)
+					.nonce(nonceStr)
+					.signature(signature)
+					.timestamp(timestamp)
+					.body(requestBody)
+					.build();
+			// 以支付通知回调为例,验签、解密并转换成 Transaction
+			Transaction transaction = notificationParser.parse(requestParam, Transaction.class);
+			logger.info("wx wxpayAsyncNotify transaction:{}", JSON.toJSONString(transaction));
+			Transaction.TradeStateEnum tradeState = transaction.getTradeState();
+			if (Transaction.TradeStateEnum.SUCCESS.equals(tradeState)){
+				int amount = transaction.getAmount().getPayerTotal() / 100;
+				return payUpdate(transaction.getOutTradeNo(), String.valueOf(amount), DateUtils.parseDateISOByFormat(transaction.getSuccessTime()));
+			}
+		} catch (Exception e) {
+			logger.error("wxpayAsyncNotify error", e);
+		}
+		return "failure";
+	}
 }

+ 17 - 0
modules/report/src/main/java/com/jeesite/modules/report/util/WxPayUtil.java

@@ -2,6 +2,8 @@ package com.jeesite.modules.report.util;
 
 import com.wechat.pay.java.core.Config;
 import com.wechat.pay.java.core.RSAAutoCertificateConfig;
+import com.wechat.pay.java.core.notification.NotificationConfig;
+import com.wechat.pay.java.core.notification.NotificationParser;
 import com.wechat.pay.java.service.payments.h5.H5Service;
 import com.wechat.pay.java.service.payments.nativepay.NativePayService;
 import com.wechat.pay.java.service.refund.RefundService;
@@ -65,4 +67,19 @@ public class WxPayUtil {
     public H5Service h5Service(Config config) {
         return new H5Service.Builder().config(config).build();
     }
+
+    @Bean
+    public NotificationConfig notificationConfig() {
+        return new RSAAutoCertificateConfig.Builder()
+                .merchantId(mchId)
+                .privateKeyFromPath(privateKeyPath)
+                .merchantSerialNumber(merchantSerialNumber)
+                .apiV3Key(apiV3Key)
+                .build();
+    }
+
+    @Bean
+    public NotificationParser notificationParser(NotificationConfig config) {
+        return new NotificationParser(config);
+    }
 }

+ 1 - 1
web/src/main/resources/config/application.yml

@@ -957,6 +957,6 @@ wxpay:
   # 商户API私钥路径
   privateKeyPath: cert/apiclient_key.pem
   # 商户证书序列号
-  merchantSerialNumber:
+  merchantSerialNumber: 1BAA3C96C5BF0E3B57796EEC0DF61E3A346B1C64
   # 商户APIV3密钥
   apiV3Key: gaux2PjT2vwtcRNvvH5EKpuhIUNe1djN