当前位置:   article > 正文

Springboot对接微信支付SDK,超简单版:wechatpay-apiv3_billdownloadserviceextension

billdownloadserviceextension

官网:https://github.com/wechatpay-apiv3/wechatpay-java

一:引入依赖

我用的是微信官方推荐的java版本的SDK,maven坐标如下

  1. <dependency>
  2. <groupId>com.github.wechatpay-apiv3</groupId>
  3. <artifactId>wechatpay-java</artifactId>
  4. <version>0.2.12</version>
  5. </dependency>

二:准备微信支付所必要的商户参数,具体如下:

  1. xxx:
  2. pay:
  3. wechat-pay:
  4. #商户号
  5. merchantId: xxxxxxx
  6. #商户API私钥(很长)
  7. privateKey: xxxxxxx...
  8. #商户API公钥 (也很长)
  9. publicKey: xxxxxx....
  10. #微信支付的商户平台证书序列号
  11. merchantSerialNo: xxxxxxxxxxx
  12. #微信公众号ID
  13. appid: xxxxxxxxx
  14. #支付回调地址,必须是外网可访问的,文中会提供对应工具
  15. notify_url: https://xxxxx
  16. #支付回调地址,同上,我写成了两个接口分开处理业务
  17. refunds_notify_url: https://xxxxxxx
  18. #秘钥, 申请微信支付商户平台证书的时候能看见
  19. apiV3Key: xxxxxxx
  20. #域名
  21. domain: https://api.mch.weixin.qq.com

商户api证书:

申请完成之后商户api证书会下载成压缩包,解压之后就是上图的文件了,其中apiclient_key.pem就是商户私钥, 另外一个就是公钥了,具体都是做什么的可以去看官网或者其他文章

        私钥的加载方式有两种

               1.一种是将私钥中的字符串直接复制到代码中(或者.yaml配置文件中),切记:不能有换行.

               2.第二种是用加载文件的方式, 将api证书文件存到你的电脑或者服务器上,在配置文件中分别记录对应的位置即可,这种方式的具体加载方式看官网即可.

三:编写配置类WechatPayConfig.java

  1. import com.wechat.pay.java.core.Config;
  2. import com.wechat.pay.java.core.RSAAutoCertificateConfig;
  3. import com.wechat.pay.java.service.billdownload.BillDownloadServiceExtension;
  4. import com.wechat.pay.java.service.payments.app.AppServiceExtension;
  5. import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
  6. import com.wechat.pay.java.service.refund.RefundService;
  7. import lombok.Data;
  8. import lombok.NoArgsConstructor;
  9. import org.springframework.beans.factory.annotation.Value;
  10. import org.springframework.context.annotation.Bean;
  11. import org.springframework.context.annotation.Configuration;
  12. import org.springframework.core.annotation.Order;
  13. import java.security.KeyFactory;
  14. import java.security.NoSuchAlgorithmException;
  15. import java.security.PrivateKey;
  16. import java.security.spec.InvalidKeySpecException;
  17. import java.security.spec.PKCS8EncodedKeySpec;
  18. import java.util.Base64;
  19. import java.util.List;
  20. /**
  21. * @author: wxj
  22. * @Desc:
  23. * @create: 2023-11-06 13:15:34
  24. **/
  25. @Data
  26. @Configuration
  27. @NoArgsConstructor
  28. public class WechatPayConfig {
  29. @Value("${}")
  30. private String merchantId;
  31. @Value("${}")
  32. private String privateKey;
  33. @Value("${}")
  34. private String publicKey;
  35. @Value("${}")
  36. private String serialNo;
  37. @Value("${}")
  38. private String appid;
  39. @Value("${}")
  40. private String notifyUrl;
  41. @Value("${}")
  42. private String apiV3Key;
  43. @Value("${}")
  44. private String domain;
  45. @Value("${}")
  46. private String refundNotifyUrl;
  47. /**
  48. * 初始化最基础的商户配置
  49. *
  50. * @return Config
  51. */
  52. @Bean
  53. @Order(0)
  54. public Config initConfig() {
  55. return new RSAAutoCertificateConfig.Builder()
  56. .merchantId(merchantId)
  57. .privateKey(privateKey)
  58. .merchantSerialNumber(serialNo)
  59. .apiV3Key(apiV3Key)
  60. .build();
  61. }
  62. /**
  63. * 初始化小程序需要的SDK支持服务
  64. *
  65. * @return JsapiService
  66. */
  67. @Bean
  68. @Order(1)
  69. public JsapiServiceExtension initJsapiService() {
  70. Config config = SpringUtils.getBean(Config.class);
  71. return new JsapiServiceExtension.Builder().config(config).build();
  72. }
  73. /**
  74. * 初始化安卓app需要的SDK支持服务
  75. *
  76. * @return AppService
  77. */
  78. @Bean
  79. @Order(2)
  80. public AppServiceExtension initAppService() {
  81. Config config = SpringUtils.getBean(Config.class);
  82. return new AppServiceExtension.Builder().config(config).build();
  83. }
  84. /**
  85. * 初始化退款服务需要的SDK支持服务
  86. *
  87. * @return RefundService
  88. */
  89. @Bean
  90. @Order(3)
  91. public RefundService initRefundService() {
  92. Config config = SpringUtils.getBean(Config.class);
  93. return new RefundService.Builder().config(config).build();
  94. }
  95. @Bean
  96. @Order(4)
  97. public BillDownloadServiceExtension initBillDownloadServiceExtension() {
  98. Config config = SpringUtils.getBean(Config.class);
  99. return new BillDownloadServiceExtension.Builder().config(config).build();
  100. }
  101. /**
  102. * 加载私钥
  103. */
  104. public PrivateKey getPrivateKey() {
  105. try {
  106. KeyFactory kf = KeyFactory.getInstance("RSA");
  107. return kf.generatePrivate(
  108. new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
  109. } catch (NoSuchAlgorithmException e) {
  110. throw new RuntimeException("当前Java环境不支持RSA", e);
  111. } catch (InvalidKeySpecException e) {
  112. throw new RuntimeException("无效的密钥格式");
  113. } catch (Exception e) {
  114. throw new RuntimeException("加载私钥异常,请检查私钥文件", e);
  115. }
  116. }
  117. }

                业务代码就使用小程序支付代码为例

小程序api文档地址

四:下单相关接口(4个)

  1. import cn.hutool.core.date.DateUtil;
  2. import com.alibaba.fastjson2.JSONObject;
  3. import com.wechat.pay.java.core.Config;
  4. import com.wechat.pay.java.core.exception.ValidationException;
  5. import com.wechat.pay.java.core.notification.NotificationConfig;
  6. import com.wechat.pay.java.core.notification.NotificationParser;
  7. import com.wechat.pay.java.core.notification.RequestParam;
  8. import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
  9. import com.wechat.pay.java.service.payments.jsapi.model.*;
  10. import com.wechat.pay.java.service.payments.model.Transaction;
  11. import com.wechat.pay.java.service.refund.RefundService;
  12. import lombok.extern.slf4j.Slf4j;
  13. import org.springframework.stereotype.Component;
  14. import org.springframework.transaction.annotation.Transactional;
  15. import javax.annotation.Resource;
  16. import javax.servlet.http.HttpServletRequest;
  17. import java.util.List;
  18. import java.util.concurrent.locks.ReentrantLock;
  19. import java.util.stream.Collectors;
  20. @Slf4j
  21. @Component
  22. public class WechatAppletPayService {
  23. @Resource
  24. private Config config;
  25. @Resource
  26. private JsapiServiceExtension jsapiService;
  27. @Resource
  28. private RefundService refundService;
  29. @Resource
  30. private WechatPayConfig payConfig;
  31. private final ReentrantLock lock = new ReentrantLock();
  32. /**
  33. * 创建订单
  34. *
  35. * @param orderBo 订单参数对象
  36. * @return
  37. */
  38. public R<PrepayWithRequestPaymentResponse> createOrder(CourseOrderBo orderBo) {
  39. // 创建未支付订单对象并插入数据库, 具体根据需求实现
  40. // Order 创建的订单对象 cusWechat用户在咱们小程序对应的对象, 主要需要用户的openId,openId是某个微信用户在第一次进小程序的时候就分配的唯一ID,不会变,还是不知道openId是啥的去百度搜吧
  41. return this.pushOrder(order, cusWechat);
  42. }
  43. /**
  44. * 拉起支付
  45. *
  46. * @param orderBo
  47. * @param cusWechat
  48. * @return
  49. */
  50. public R<PrepayWithRequestPaymentResponse> pushOrder(CourseOrderBo orderBo, CusWechat cusWechat) {
  51. String appid = cusWechat.getAppid();
  52. String openid = cusWechat.getOpenid();
  53. PrepayRequest request = new PrepayRequest();
  54. request.setMchid(payConfig.getMerchantId());
  55. request.setAppid(appid);
  56. request.setDescription(orderBo.getGoodsName());
  57. request.setOutTradeNo(orderBo.getOrderId());
  58. // 2023-11-30T15:45:48+08:00
  59. String timeExpire = DateUtil.offsetMinute(DateUtil.date(), 10).toString().replace(" ", "T") + "+08:00";
  60. request.setTimeExpire(timeExpire);
  61. JSONObject attach = new JSONObject(1);
  62. attach.put("couponCode", orderBo.getCouponCode());
  63. request.setAttach(attach.toString());
  64. request.setNotifyUrl(String.format(payConfig.getNotifyUrl(), WechatConstants.SourcePathEnum.PAY_FROM_APPLET));
  65. Amount amount = new Amount();
  66. amount.setTotal(orderBo.getTotalAmount().intValue());
  67. amount.setCurrency("CNY");
  68. request.setAmount(amount);
  69. Payer payer = new Payer();
  70. payer.setOpenid(openid);
  71. request.setPayer(payer);
  72. PrepayWithRequestPaymentResponse prepay = jsapiService.prepayWithRequestPayment(request);
  73. return R.ok(prepay);
  74. }
  75. /**
  76. * 通过微信交易ID查询订单
  77. *
  78. * @param id
  79. * @param transactionId
  80. * @return
  81. */
  82. public R getOrderByTransactionId(Long id, String transactionId) {
  83. QueryOrderByIdRequest request = new QueryOrderByIdRequest();
  84. request.setMchid(payConfig.getMerchantId());
  85. request.setTransactionId(transactionId);
  86. Transaction transactionResp = jsapiService.queryOrderById(request);
  87. Transaction.TradeStateEnum tradeState = transactionResp.getTradeState();
  88. CourseTransactionVo transactionVo = transactionService.queryById(id);
  89. }
  90. public R getOrderByOrderId(String orderId) {
  91. QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
  92. request.setMchid(payConfig.getMerchantId());
  93. request.setOutTradeNo(orderId);
  94. Transaction transactionResp = jsapiService.queryOrderByOutTradeNo(request);
  95. String appid = transactionResp.getAppid();
  96. String openId = transactionResp.getPayer().getOpenid();
  97. Long aLong = transactionResp.getAmount().getTotal().longValue();
  98. Long aLong1 = transactionResp.getAmount().getPayerTotal().longValue();
  99. String transactionId = transactionResp.getTransactionId();
  100. Transaction.TradeStateEnum tradeState = transactionResp.getTradeState();
  101. // 具体业务自行处理
  102. return R.ok();
  103. }
  104. @Transactional(rollbackFor = Exception.class)
  105. public R<String> closeOrder(String orderId) {
  106. try {
  107. CloseOrderRequest request = new CloseOrderRequest();
  108. request.setMchid(payConfig.getMerchantId());
  109. request.setOutTradeNo(orderId);
  110. jsapiService.closeOrder(request);
  111. // 具体业务自行处理
  112. return R.ok();
  113. } catch (Exception e) {
  114. throw new RuntimeException(e);
  115. }
  116. }
  117. }

这里包含了下单,根据商户订单号查询微信支付订单,根据微信支付订单号查询微信支付订单以及关闭订单四个接口,具体业务代码需要兄弟你自己根据你们项目需求写.

五:退款相关接口(2个)

  1. import cn.hutool.core.util.EnumUtil;
  2. import com.wechat.pay.java.service.refund.RefundService;
  3. import com.wechat.pay.java.service.refund.model.*;
  4. import org.springframework.stereotype.Service;
  5. import javax.annotation.Resource;
  6. /**
  7. * @author: wxj
  8. * @Desc: 微信支付退款服务类
  9. * @create: 2023-12-06 17:17:33
  10. **/
  11. @Service
  12. public class WechatRefundService {
  13. @Resource
  14. private WechatPayConfig payConfig;
  15. @Resource
  16. private RefundService refundService;
  17. /**
  18. * 后台向微信支付申请退款
  19. *
  20. * @param bo 参数对象
  21. * orderId 退款的订单ID
  22. * refundAmount 实际退款金额(由相关人员与客户商谈)
  23. * refundReason 退款理由
  24. * @return 处理结果
  25. */
  26. public R<String> refundsOrder(CourseOrderBo bo) {
  27. try {
  28. // 具体业务自行实现
  29. CreateRequest request = new CreateRequest();
  30. request.setReason(reasonEnum.getReason());
  31. Integer platform = order.getPlatform();
  32. WechatConstants.PlatformEnum platformEnum = EnumUtil.likeValueOf(WechatConstants.PlatformEnum.class, platform);
  33. AmountReq amount = new AmountReq();
  34. amount.setRefund(refundAmount);
  35. amount.setTotal(order.getTotalAmount());
  36. amount.setCurrency("CNY");
  37. request.setAmount(amount);
  38. request.setOutRefundNo(refundTransaction.getId().toString());
  39. request.setOutTradeNo(orderId);
  40. Refund refund = refundService.create(request);
  41. Status status_wx = refund.getStatus();
  42. String refundId_wx = refund.getRefundId();
  43. String transactionId_wx = refund.getTransactionId();
  44. String orderId_wx = refund.getOutTradeNo();
  45. com.wechat.pay.java.service.refund.model.Amount amount_wx = refund.getAmount();
  46. long total_wx = amount_wx.getTotal();
  47. long refundAmount_wx = amount_wx.getRefund();
  48. Long playTotal_wx = amount_wx.getPayerTotal();
  49. refundTransaction.setTransactionId(transactionId_wx);
  50. refundTransaction.setPayAmount(playTotal_wx);
  51. refundTransaction.setTotalAmount(total_wx);
  52. refundTransaction.setOrderId(orderId_wx);
  53. refundTransaction.setRefundId(refundId_wx);
  54. transactionService.updateByBo(BeanCopyUtils.copy(refundTransaction, CourseTransactionBo.class));
  55. return R.ok("申请成功, 请注意查收退款记录");
  56. } catch (Exception e) {
  57. e.printStackTrace();
  58. throw e;
  59. }
  60. }
  61. public R getRefundsOrder(Long id) {
  62. try {
  63. // 具体业务自行处理 此处ID为商户系统流水ID
  64. QueryByOutRefundNoRequest request = new QueryByOutRefundNoRequest();
  65. request.setSubMchid(payConfig.getMerchantId());
  66. request.setOutRefundNo(transaction.getId().toString());
  67. Refund refundResp = refundService.queryByOutRefundNo(request);
  68. return R.fail();
  69. } catch (Exception e) {
  70. throw new RuntimeException(e);
  71. }
  72. }
  73. }

六:下载账单类接口(2个)

  1. import cn.hutool.core.date.DateUtil;
  2. import com.wechat.pay.java.service.billdownload.BillDownloadServiceExtension;
  3. import com.wechat.pay.java.service.billdownload.DigestBillEntity;
  4. import com.wechat.pay.java.service.billdownload.model.AccountType;
  5. import com.wechat.pay.java.service.billdownload.model.BillType;
  6. import com.wechat.pay.java.service.billdownload.model.GetFundFlowBillRequest;
  7. import com.wechat.pay.java.service.billdownload.model.GetTradeBillRequest;
  8. import lombok.extern.slf4j.Slf4j;
  9. import org.springframework.stereotype.Service;
  10. import javax.annotation.Resource;
  11. import javax.servlet.http.HttpServletResponse;
  12. import java.io.InputStream;
  13. /**
  14. * @author: wxj
  15. * @Desc: 微信支付下载服务类
  16. * @create: 2023-12-06 17:37:49
  17. **/
  18. @Slf4j
  19. @Service
  20. public class WechatBillDownloadService {
  21. @Resource
  22. private BillDownloadServiceExtension downloadService;
  23. /**
  24. * @param billDate 日期 不填默认昨天
  25. * @param billTypeStr 导出内容类型
  26. * ALL: 返回当日所有订单信息(不含充值退款订单)
  27. * SUCCESS: 返回当日成功支付的订单(不含充值退款订单)
  28. * REFUND: 返回当日退款订单(不含充值退款订单)
  29. * RECHARGE_REFUND: 返回当日充值退款订单
  30. * ALL_SPECIAL: 返回个性化账单当日所有订单信息
  31. * SUC_SPECIAL: 返回个性化账单当日成功支付的订单
  32. * REF_SPECIAL: 返回个性化账单当日退款订单
  33. * @param tarType 压缩类型 不填默认ZGIP
  34. * @return
  35. */
  36. public R<InputStream> exportTransactions(String billDate, String tarType, String billTypeStr, HttpServletResponse resp) {
  37. if (StringUtils.isEmpty(billDate)) {
  38. billDate = DateUtil.format(DateUtil.yesterday(), "yyyy-MM-DD");
  39. }
  40. BillType billType = BillType.ALL;
  41. try {
  42. billType = BillType.valueOf(billTypeStr);
  43. } catch (IllegalArgumentException e) {
  44. e.printStackTrace();
  45. }
  46. GetTradeBillRequest request = new GetTradeBillRequest();
  47. request.setBillDate(billDate);
  48. request.setBillType(billType);
  49. request.setTarType(null);
  50. DigestBillEntity tradeBill = downloadService.getTradeBill(request);
  51. return R.ok(tradeBill.getInputStream());
  52. }
  53. public R<InputStream> exportFundflow(String billDate, String accountTypeStr, HttpServletResponse resp) {
  54. if (StringUtils.isEmpty(billDate)) {
  55. billDate = DateUtil.format(DateUtil.yesterday(), "yyyy-MM-DD");
  56. }
  57. AccountType accountType = AccountType.ALL;
  58. try {
  59. accountType = AccountType.valueOf(accountTypeStr);
  60. } catch (IllegalArgumentException e) {
  61. e.printStackTrace();
  62. }
  63. GetFundFlowBillRequest request = new GetFundFlowBillRequest();
  64. request.setBillDate(billDate);
  65. request.setTarType(null);
  66. request.setAccountType(accountType);
  67. DigestBillEntity fundFlowBill = downloadService.getFundFlowBill(request);
  68. return R.ok(fundFlowBill.getInputStream());
  69. }
  70. }

       

 安卓app的接口大差不差也都这样,不知道方法或者参数接收的兄弟可以看SDK源码,实在找不到idea不能搜索jar中的代码,建议反编译之后再用idea打开搜索,毕竟我就是这么做的...

这些接口暂时还没完整测试, 过段时间测通过上线了再把支付宝的也分享出来...

                         ~~写完了,溜溜球~~~

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/467374
推荐阅读
相关标签
  

闽ICP备14008679号