From 03dd384bb8b78f04eadcf619849b3687fa98c6c1 Mon Sep 17 00:00:00 2001 From: zhanglin <852614290@qq.com> Date: 星期六, 22 七月 2023 18:19:47 +0800 Subject: [PATCH] 微信支付,支付与结果通知 --- ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/controller/miniapp/NotifyController.java | 132 ++++++++++++++++++++++ ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/domain/dto/WXPayNotifyDto.java | 19 +++ ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/order/OrderServiceImpl.java | 133 ++++++++++++++++++++++ ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/domain/dto/WXPayNotifyResourceDto.java | 14 ++ ruoyi-modules/ruoyi-order/pom.xml | 6 + 5 files changed, 304 insertions(+), 0 deletions(-) diff --git a/ruoyi-modules/ruoyi-order/pom.xml b/ruoyi-modules/ruoyi-order/pom.xml index de0540b..09bad0d 100644 --- a/ruoyi-modules/ruoyi-order/pom.xml +++ b/ruoyi-modules/ruoyi-order/pom.xml @@ -114,6 +114,12 @@ <version>0.4.9</version> </dependency> + <dependency> + <groupId>com.github.wechatpay-apiv3</groupId> + <artifactId>wechatpay-java</artifactId> + <version>0.2.10</version> + </dependency> + <!-- 爬虫工具,抓取和解析html https://mvnrepository.com/artifact/org.jsoup/jsoup --> <dependency> <groupId>org.jsoup</groupId> diff --git a/ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/controller/miniapp/NotifyController.java b/ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/controller/miniapp/NotifyController.java new file mode 100644 index 0000000..f885ddf --- /dev/null +++ b/ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/controller/miniapp/NotifyController.java @@ -0,0 +1,132 @@ +package com.ruoyi.order.controller.miniapp; + +import com.ruoyi.common.core.domain.R; +import com.ruoyi.common.core.web.controller.BaseController; +import com.ruoyi.order.domain.dto.AppSureOrderDto; +import com.ruoyi.order.domain.dto.WXPayNotifyDto; +import com.ruoyi.order.domain.vo.AppSureOrderVo; +import com.ruoyi.order.service.order.OrderService; +import com.wechat.pay.contrib.apache.httpclient.notification.Notification; +import com.wechat.pay.contrib.apache.httpclient.notification.NotificationHandler; +import com.wechat.pay.contrib.apache.httpclient.notification.NotificationRequest; +import com.wechat.pay.java.core.Config; +import com.wechat.pay.java.core.RSAAutoCertificateConfig; +import com.wechat.pay.java.core.RSAConfig; +import com.wechat.pay.java.core.cipher.PrivacyEncryptor; +import com.wechat.pay.java.core.notification.NotificationConfig; +import com.wechat.pay.java.core.notification.NotificationParser; +import com.wechat.pay.java.core.notification.RequestParam; +import com.wechat.pay.java.service.partnerpayments.jsapi.model.Transaction; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import net.bytebuddy.asm.Advice; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.BufferedReader; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +/** + * @program: ruoyi + * @author: linqingsong + * @create: 2023-07-22 17:20 + * @description: 成都软思同创科技有限公司 + **/ +@Api(value = "微信通知控制", tags = "微信通知控制", description = "微信通知控制") +@RestController +@RequestMapping("/app/notify") +public class NotifyController extends BaseController { + /** 商户号 */ + public static String merchantId = ""; + /** 商户API私钥路径 */ + public static String privateKeyPath = ""; + /** 商户证书序列号 */ + public static String merchantSerialNumber = ""; + /** 微信支付平台证书路径 */ + public static String wechatPayCertificatePath = ""; + /** 商户APIV3密钥 */ + public static String apiV3key = "..."; + + @Resource + private OrderService orderService; + + @RequestMapping(value = "/payNotify", method = RequestMethod.POST) + @ApiOperation(value = "微信支付通知") + public Map payNotify(HttpServletRequest request, HttpServletResponse response) { + Config config = + new RSAConfig.Builder() + .merchantId(merchantId) + .privateKeyFromPath(privateKeyPath) + .merchantSerialNumber(merchantSerialNumber) + .wechatPayCertificatesFromPath(wechatPayCertificatePath) + .build(); + + PrivacyEncryptor encryptor = config.createEncryptor(); + String wechatPayCertificateSerialNumber = encryptor.getWechatpaySerial(); + + + String nonoc=request.getHeader("Wechatpay-Nonce"); + String signature=request.getHeader("Wechatpay-Signature"); + String timestamp=request.getHeader("Wechatpay-Timestamp"); + String serial=request.getHeader("Wechatpay-Serial"); + String signatureType=request.getHeader("Wechatpay-Signature-Type"); + + String requestBody=""; + + try { + BufferedReader reader = request.getReader(); + String line = ""; + StringBuffer inputString = new StringBuffer(); + while ( (line = reader.readLine()) != null ) { + inputString.append(line); + } + if(inputString!=null && !"".equals(inputString)) { + requestBody = inputString.toString(); + } + reader.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + RequestParam requestParam = new RequestParam.Builder() + .serialNumber(wechatPayCertificateSerialNumber) + .nonce(nonoc) + .signature(signature) + .timestamp(timestamp) + .body(requestBody) + .build(); + + NotificationConfig notifiConfig = new RSAAutoCertificateConfig.Builder() + .merchantId(merchantId) + .privateKeyFromPath(privateKeyPath) + .merchantSerialNumber(merchantSerialNumber) + .apiV3Key(apiV3key) + .build(); + + NotificationParser parser = new NotificationParser(notifiConfig); + + Transaction transaction = parser.parse(requestParam, Transaction.class); + + + String tradeStateEnum=transaction.getTradeState().toString(); + if(tradeStateEnum.equals("success")){ + String outTradeNo=transaction.getOutTradeNo(); + orderService.payBack(outTradeNo); + } + + Map map=new HashMap(); + map.put("code","SUCCESS"); + map.put("message","成功"); + + return map; + } + +} diff --git a/ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/domain/dto/WXPayNotifyDto.java b/ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/domain/dto/WXPayNotifyDto.java new file mode 100644 index 0000000..698fceb --- /dev/null +++ b/ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/domain/dto/WXPayNotifyDto.java @@ -0,0 +1,19 @@ +package com.ruoyi.order.domain.dto; + +import lombok.Data; + +/** + * @program: ruoyi + * @author: linqingsong + * @create: 2023-07-22 17:23 + * @description: 成都软思同创科技有限公司 + **/ +@Data +public class WXPayNotifyDto { + private String id; + private String create_time; + private String event_type; + private String resource_type; + private WXPayNotifyResourceDto resource; + private String summary; +} diff --git a/ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/domain/dto/WXPayNotifyResourceDto.java b/ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/domain/dto/WXPayNotifyResourceDto.java new file mode 100644 index 0000000..cebb086 --- /dev/null +++ b/ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/domain/dto/WXPayNotifyResourceDto.java @@ -0,0 +1,14 @@ +package com.ruoyi.order.domain.dto; + +/** + * @program: ruoyi + * @author: linqingsong + * @create: 2023-07-22 17:25 + * @description: 成都软思同创科技有限公司 + **/ +public class WXPayNotifyResourceDto { + private String algorithm; + private String ciphertext; + private String associated_datal; + private String nonce; +} diff --git a/ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/order/OrderServiceImpl.java b/ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/order/OrderServiceImpl.java index d610779..a3440b9 100644 --- a/ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/order/OrderServiceImpl.java +++ b/ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/order/OrderServiceImpl.java @@ -14,6 +14,7 @@ import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.order.domain.dto.*; import com.ruoyi.order.domain.pojo.account.OrderRefund; +import com.ruoyi.order.domain.pojo.account.PaymentMessage; import com.ruoyi.order.domain.pojo.order.ConsumerGoods; import com.ruoyi.order.domain.pojo.order.Order; import com.ruoyi.order.domain.pojo.order.OrderGoods; @@ -24,6 +25,8 @@ import com.ruoyi.order.service.order.OrderGoodsService; import com.ruoyi.order.service.order.OrderService; import com.ruoyi.order.service.order.UserServiceRecordService; +import com.ruoyi.order.tools.request.pay.combine.CombineTransactionsJsRequest; +import com.ruoyi.order.tools.service.ProfitsSharingService; import com.ruoyi.system.api.constant.AppErrorConstant; import com.ruoyi.system.api.constant.DelayTaskEnum; import com.ruoyi.system.api.constant.SecurityConstant; @@ -39,6 +42,8 @@ import com.ruoyi.system.api.domain.poji.sys.SysUser; import com.ruoyi.system.api.domain.vo.*; import com.ruoyi.system.api.service.*; +import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension; +import com.wechat.pay.java.service.payments.jsapi.model.*; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; @@ -52,6 +57,10 @@ import java.util.concurrent.TimeUnit; import java.util.function.Function; import java.util.stream.Collectors; + +import com.wechat.pay.java.core.Config; +import com.wechat.pay.java.core.RSAConfig; +import com.wechat.pay.java.service.payments.jsapi.JsapiService; /** * <p> @@ -106,8 +115,28 @@ @Resource private RedisService redisService; + @Resource + private ProfitsSharingService profitsSharingService; + @Autowired private RedissonClient redissonClient; + + /** 商户号 */ + public static String merchantId = ""; + /** 商户API私钥路径 */ + public static String privateKeyPath = ""; + /** 商户证书序列号 */ + public static String merchantSerialNumber = ""; + /** 微信支付平台证书路径 */ + public static String wechatPayCertificatePath = ""; + /** 微信支付 APIv3 密钥 */ + public static String apiV3Key = ""; + /** 微信支付APPID */ + public static String appId=""; + /** 微信支付商户ID */ + public static String mchId=""; + /** 通知地址 */ + public static String notifyUrl=""; /** * @description: buyGoods @@ -664,6 +693,37 @@ appPlaceOrderVo.setOrderId(orderId); appPlaceOrderVo.setOrderNo(orderNo); // 调用支付 + /* CombineTransactionsJsRequest request=new CombineTransactionsJsRequest(); + request.setCombineAppid(); + request.setCombineMchid(); + profitsSharingService.combineTransactions(request);*/ + + //构建预下单支付对象 + PrepayRequest request = new PrepayRequest(); + Amount amount = new Amount(); + amount.setTotal(Integer.parseInt(order.getPayMoney().multiply(new BigDecimal(100)).toString())); + request.setAmount(amount); + request.setAppid(this.appId); + request.setMchid(this.mchId); + request.setDescription(order.getGoodsInfo()); + request.setNotifyUrl(this.notifyUrl); + request.setOutTradeNo(order.getOrderId()); + Payer payer = new Payer(); payer.setOpenid("oLTPCuN5a-nBD4rAL_fa********"); + + request.setPayer(payer); + + + //返回前端唤醒支付结果信息 + PrepayWithRequestPaymentResponse res = this.getJsApIResponse(request); + + appPlaceOrderVo.setAppId(this.appId); + appPlaceOrderVo.setTimeStamp(res.getTimeStamp()); + appPlaceOrderVo.setNonceStr(res.getNonceStr()); + appPlaceOrderVo.setPackageStr(res.getPackageVal()); + appPlaceOrderVo.setTradeType(res.getSignType()); + appPlaceOrderVo.setPaySign(res.getPaySign()); + + //减去优惠券 if(memberCouponSJ!=null){ remoteCouponService.useMemberCoupon(memberCouponSJ.toString()); @@ -684,6 +744,79 @@ } /** + * + * 功能描述: 预下单,返回支付数据prePayId + * + * 构建对象参考 + * PrepayRequest request = new PrepayRequest(); + * Amount amount = new Amount(); + * amount.setTotal(100); + * request.setAmount(amount); + * request.setAppid("wxa9d9651ae******"); + * request.setMchid("190000****"); + * request.setDescription("测试商品标题"); + * request.setNotifyUrl("https://notify_url"); + * request.setOutTradeNo("out_trade_no_001"); + * Payer payer = new Payer(); + * payer.setOpenid("oLTPCuN5a-nBD4rAL_fa********"); + * request.setPayer(payer); + * + * @auther: linqingsong + * @date: 2023/7/22 16:13 + */ + /*public String getPrePayId(PrepayRequest request) { + Config config = + new RSAConfig.Builder() + .merchantId(merchantId) + .privateKeyFromPath(privateKeyPath) + .merchantSerialNumber(merchantSerialNumber) + .wechatPayCertificatesFromPath(wechatPayCertificatePath) + .build(); + JsapiService service = new JsapiService.Builder().config(config).build(); + PrepayResponse response = service.prepay(request); + return response.getPrepayId(); + }*/ + + + /** + * + * 功能描述: 预下单,并返回前端需要换起支付的字符串 + * + * 构建对象参考 + * * PrepayRequest request = new PrepayRequest(); + * * Amount amount = new Amount(); + * * amount.setTotal(100); + * * request.setAmount(amount); + * * request.setAppid("wxa9d9651ae******"); + * * request.setMchid("190000****"); + * * request.setDescription("测试商品标题"); + * * request.setNotifyUrl("https://notify_url"); + * * request.setOutTradeNo("out_trade_no_001"); + * * Payer payer = new Payer(); + * * payer.setOpenid("oLTPCuN5a-nBD4rAL_fa********"); + * * request.setPayer(payer); + * + * + * @auther: linqingsong + * @date: 2023/7/22 16:53 + */ + public PrepayWithRequestPaymentResponse getJsApIResponse(PrepayRequest request){ + Config config = + new RSAConfig.Builder() + .merchantId(merchantId) + .privateKeyFromPath(privateKeyPath) + .merchantSerialNumber(merchantSerialNumber) + .wechatPayCertificatesFromPath(wechatPayCertificatePath) + .build(); + JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build(); + + PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request); + + return response; + } + + + /** * @param appPlaceActivityDto * @return AppPlaceOrderVo * @description 创建活动订单 -- Gitblit v1.7.1