功能实战指南)
WxJava 微信支付预约扣费连续包月功能实战指南【免费下载链接】WxJava微信开发 Java SDK 支持包括微信支付开放平台小程序企业微信视频号公众号等的后端开发项目地址: https://gitcode.com/gh_mirrors/wx/WxJava导读本文基于 WxJava 微信支付 SDK 的subscriptionbilling模块完整讲解预约扣费连续包月能力的接入与使用。该功能允许商户在用户签约授权后按约定时间与金额自动从用户支付账户扣费是视频会员、云服务、知识付费等订阅制业务的标准支付方案。读完本文你将掌握从服务实例获取、预约创建、查询、取消、立即扣费到扣费记录查询的完整调用链并了解各请求参数在源码中的字段映射与底层实现。功能特性微信支付预约扣费连续包月功能在 WxJava 中由SubscriptionBillingService统一封装通过 SubscriptionBillingService.java 对外暴露以下五个能力能力接口方法说明预约扣费scheduleSubscription创建未来某个时间点的扣费计划可附带周期计划实现连续包月查询预约querySubscription按subscription_id查询已创建的扣费计划状态取消预约cancelSubscription取消尚未执行的扣费计划立即扣费instantBilling立即执行扣费常用于补扣失败费用或特殊情况即时扣费扣费记录查询queryTransactions按时间窗口分页查询历史扣费记录快速开始1. 获取服务实例预约扣费服务无需单独构建直接通过WxPayService获取SubscriptionBillingService subscriptionService wxPayService.getSubscriptionBillingService();从源码看该服务由BaseWxPayServiceImpl在内部以new SubscriptionBillingServiceImpl(this)的方式持有见 BaseWxPayServiceImpl.java并通过 WxPayService.java 的getSubscriptionBillingService()方法暴露。因此你只需保证wxPayService已正确配置含商户号、APIv3 密钥、商户证书序列号与私钥即可直接使用。2. 创建预约扣费// 创建预约扣费请求 SubscriptionScheduleRequest request new SubscriptionScheduleRequest(); request.setOutTradeNo(subscription_ System.currentTimeMillis()); request.setOpenid(用户的openid); request.setDescription(腾讯视频VIP会员); request.setScheduleTime(2024-09-01T10:00:0008:00); // 设置扣费金额 SubscriptionAmount amount new SubscriptionAmount(); amount.setTotal(3000); // 30元单位为分 amount.setCurrency(CNY); request.setAmount(amount); // 设置扣费计划可选 BillingPlan billingPlan new BillingPlan(); billingPlan.setPlanType(MONTHLY); // 按月扣费 billingPlan.setPeriod(1); // 每1个月 billingPlan.setTotalCount(12); // 总共12次 request.setBillingPlan(billingPlan); // 发起预约扣费 SubscriptionScheduleResult result subscriptionService.scheduleSubscription(request); System.out.println(预约扣费ID: result.getSubscriptionId());预约扣费请求参数详解SubscriptionScheduleRequest源码见 SubscriptionScheduleRequest.java通过SerializedName注解完成 Java 字段与微信 API JSON 字段的映射各参数说明如下参数对应JSON字段必填类型说明outTradeNoout_trade_no是string(32)商户系统内部订单号只能是数字、大小写字母、_、-、*同一商户号下唯一openidopenid是string(128)用户在直连商户 appid 下的唯一标识descriptiondescription是string(127)订单描述如腾讯充值中心-QQ会员充值amountamount是object预约扣费金额信息见下节scheduleTimeschedule_time是string(32)预约扣费时间遵循 RFC3339格式YYYY-MM-DDTHH:mm:ssTIMEZONE如2018-06-08T10:34:5608:00billingPlanbilling_plan否object扣费计划信息用于连续包月等场景notifyUrlnotify_url否string(256)异步接收微信支付结果通知的回调地址必须为外网可访问的 URL 且不能携带参数attachattach否string(128)附加数据在查询 API 和支付通知中原样返回可作为自定义参数使用金额与扣费计划对象SubscriptionAmountSubscriptionAmount.javatotal订单总金额单位为分int 类型currency货币类型CNY表示人民币境内商户号仅支持人民币。BillingPlanBillingPlan.javaplanTypeplan_type必填计划类型取值MONTHLY/WEEKLY/DAILY/YEARLYperiod必填扣费周期配合planType使用例如planTypeMONTHLY, period1表示每 1 个月扣费一次totalCounttotal_count选填总扣费次数不填表示无限次扣费executedCountexecuted_count选填已扣费次数查询时由微信返回startTimestart_time选填与endTimeend_time选填计划开始/结束时间同样遵循 RFC3339 格式。3. 查询预约扣费// 通过预约扣费ID查询 String subscriptionId 从预约扣费结果中获取的ID; SubscriptionQueryResult queryResult subscriptionService.querySubscription(subscriptionId); System.out.println(预约状态: queryResult.getStatus());subscription_id即创建预约时返回的SubscriptionScheduleResult.getSubscriptionId()。查询返回结果包含预约状态status、预约时间schedule_time、创建时间create_time、金额amount以及扣费计划billing_plan等字段见 SubscriptionScheduleResult.java。4. 取消预约扣费// 创建取消请求 SubscriptionCancelRequest cancelRequest new SubscriptionCancelRequest(); cancelRequest.setSubscriptionId(subscriptionId); cancelRequest.setCancelReason(用户主动取消); // 取消预约扣费 SubscriptionCancelResult cancelResult subscriptionService.cancelSubscription(cancelRequest); System.out.println(取消结果: cancelResult.getStatus());SubscriptionCancelRequestSubscriptionCancelRequest.java仅有两个字段必填的subscriptionIdsubscription_id微信支付预约扣费 ID和选填的cancelReasoncancel_reason取消原因描述string(256)。5. 立即扣费立即扣费用于在预约计划之外临时发起扣费例如补扣上月会员费、处理失败重试等// 创建立即扣费请求 SubscriptionInstantBillingRequest instantRequest new SubscriptionInstantBillingRequest(); instantRequest.setOutTradeNo(instant_ System.currentTimeMillis()); instantRequest.setOpenid(用户的openid); instantRequest.setDescription(补扣上月会员费); // 设置扣费金额 SubscriptionAmount instantAmount new SubscriptionAmount(); instantAmount.setTotal(3000); // 30元 instantAmount.setCurrency(CNY); instantRequest.setAmount(instantAmount); // 执行立即扣费 SubscriptionInstantBillingResult instantResult subscriptionService.instantBilling(instantRequest); System.out.println(扣费结果: instantResult.getTradeState());SubscriptionInstantBillingRequestSubscriptionInstantBillingRequest.java字段与预约扣费请求大体一致包括必填的outTradeNo、openid、description、amount以及选填的notifyUrl、attach注意立即扣费请求不包含billing_plan与schedule_time。6. 查询扣费记录// 创建查询请求 SubscriptionTransactionQueryRequest queryRequest new SubscriptionTransactionQueryRequest(); queryRequest.setOpenid(用户的openid); queryRequest.setBeginTime(2024-08-01T00:00:0008:00); queryRequest.setEndTime(2024-08-31T23:59:5908:00); queryRequest.setLimit(20); queryRequest.setOffset(0); // 查询扣费记录 SubscriptionTransactionQueryResult transactionResult subscriptionService.queryTransactions(queryRequest); System.out.println(总记录数: transactionResult.getTotalCount()); for (SubscriptionTransactionQueryResult.SubscriptionTransaction transaction : transactionResult.getData()) { System.out.println(订单号: transaction.getOutTradeNo() , 状态: transaction.getTradeState()); }查询结果SubscriptionTransactionQueryResultSubscriptionTransactionQueryResult.java包含总数量totalCount与扣费记录列表data。每条记录SubscriptionTransaction字段包括微信支付订单号transactionId、商户订单号outTradeNo、预约扣费 IDsubscriptionId仅预约扣费产生的交易有此字段、交易状态tradeState、支付完成时间successTime、扣费金额amount、用户标识openid、订单描述description及附加数据attach。扣费计划类型BillingPlan.planType支持的取值MONTHLY按月扣费WEEKLY按周扣费DAILY按日扣费YEARLY按年扣费配合period使用例如MONTHLY period2表示每 2 个月扣费一次totalCount不填则代表无限期扣费直到用户主动解约。预约状态说明预约扣费计划SubscriptionScheduleResult.status可能处于以下状态SCHEDULED已预约待执行CANCELLED已取消EXECUTED已执行FAILED执行失败交易状态说明扣费记录SubscriptionTransaction.tradeState的取值与微信支付通用交易状态一致SUCCESS支付成功REFUND转入退款NOTPAY未支付CLOSED已关闭REVOKED已撤销刷卡支付USERPAYING用户支付中PAYERROR支付失败源码级实现原理从 SubscriptionBillingServiceImpl.java 可以看到五个接口方法均复用WxPayService的统一 APIv3 请求通道postV3/getV3并通过 Gson 完成请求序列化与响应反序列化对应端点如下方法HTTP请求URL前缀 路径是否需要证书scheduleSubscriptionPOST/v3/subscription-billing/schedule是querySubscriptionGET/v3/subscription-billing/schedule/{subscription_id}否cancelSubscriptionPOST/v3/subscription-billing/schedule/{subscription_id}/cancel是instantBillingPOST/v3/subscription-billing/instant-billing是queryTransactionsGET/v3/subscription-billing/transactions?openidbegin_timeend_timelimitoffset否URL 前缀来自payService.getPayBaseUrl()默认https://api.mch.weixin.qq.com服务内所有 APIv3 请求统一走该基础地址。几个值得注意的实现细节取消预约cancelSubscription将subscription_id拼接进 URL 路径请求体仍整体序列化发送其中subscription_id字段同时存在于 URL 与 body记录查询的分页与过滤queryTransactions内部按openid、begin_time、end_time、limit、offset顺序拼接查询串limit与offset用于分页时间字段均采用 RFC3339 格式查询走 GET 请求不需要商户证书异常处理所有方法统一抛出WxPayException由底层 APIv3 通道在请求失败时封装错误码与错误信息。注意事项用户授权使用预约扣费功能前需要用户在微信内完成签约授权未签约用户无法发起预约扣费商户资质需要具备相应的业务资质才能开通此功能且 APIv3 密钥、商户证书序列号与私钥必须正确配置金额限制扣费金额需要在签约模板规定的范围内total单位为分频率限制API 调用有频率限制请注意控制调用频次避免触发限流异常处理建议对所有 API 调用进行异常处理捕获WxPayException并对支付结果通知做签名验签与幂等处理时间格式所有时间字段必须遵循 RFC3339 标准格式如2024-09-01T10:00:0008:00否则微信侧会校验失败取消时机取消操作通常只对SCHEDULED已预约未执行状态的计划生效取消后状态变为CANCELLED。示例完整代码将上述步骤串联起来即得到完整的可运行示例类路径对应源码包com.github.binarywang.wxpay.bean.subscriptionbillingimport com.github.binarywang.wxpay.service.SubscriptionBillingService; import com.github.binarywang.wxpay.bean.subscriptionbilling.*; public class SubscriptionBillingExample { private SubscriptionBillingService subscriptionService; public void example() throws Exception { // 1. 创建预约扣费 SubscriptionScheduleRequest request new SubscriptionScheduleRequest(); request.setOutTradeNo(subscription_ System.currentTimeMillis()); request.setOpenid(用户openid); request.setDescription(VIP会员续费); request.setScheduleTime(2024-09-01T10:00:0008:00); SubscriptionAmount amount new SubscriptionAmount(); amount.setTotal(3000); amount.setCurrency(CNY); request.setAmount(amount); BillingPlan plan new BillingPlan(); plan.setPlanType(MONTHLY); plan.setPeriod(1); plan.setTotalCount(12); request.setBillingPlan(plan); SubscriptionScheduleResult result subscriptionService.scheduleSubscription(request); // 2. 查询预约状态 SubscriptionQueryResult query subscriptionService.querySubscription(result.getSubscriptionId()); // 3. 如需取消 if (SCHEDULED.equals(query.getStatus())) { SubscriptionCancelRequest cancelReq new SubscriptionCancelRequest(); cancelReq.setSubscriptionId(result.getSubscriptionId()); cancelReq.setCancelReason(用户取消); SubscriptionCancelResult cancelResult subscriptionService.cancelSubscription(cancelReq); } } }相关代码与文档索引服务接口SubscriptionBillingService.java服务实现SubscriptionBillingServiceImpl.java服务获取入口WxPayService.java、BaseWxPayServiceImpl.java请求/响应模型weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/subscriptionbilling/ 目录下的 11 个 Bean 类使用文档本指南的原始出处 SUBSCRIPTION_BILLING_USAGE.md更多用法微信支付模块的 MULTI_APPID_USAGE.md多商户号场景与 CONNECTION_POOL.md连接池调优可帮助你完善生产环境部署【免费下载链接】WxJava微信开发 Java SDK 支持包括微信支付开放平台小程序企业微信视频号公众号等的后端开发项目地址: https://gitcode.com/gh_mirrors/wx/WxJava创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考