前期硬性门槛:账号与资质准备

在动手写代码之前,必须先搞定“入场券”。微信小程序支付并非个人开发者可以随意触碰的功能,这是很多初学者容易踩的第一个坑。个人主体的小程序无法申请微信支付,你必须拥有经过微信认证的企业、政府、媒体或其他组织类型的小程序账号。

整个准备流程分为三步走:

  1. 小程序认证:登录微信公众平台,完成主体信息填写并缴纳 300 元认证费,获取唯一的 AppIDAppSecret
  2. 商户号申请:访问微信支付商户平台(pay.weixin.qq.com),提交营业执照等资料申请商户号,审核通过后获得 MchID(商户号)。
  3. 关联绑定:这是最关键的一步。登录小程序后台,在“微信支付”模块中将刚才申请的商户号进行绑定;同时登录商户平台,在“产品中心”->"AppID 账号管理”中关联你的小程序 AppID。只有双向绑定成功,支付接口才能正常调用。

此外,技术环境上必须准备一个已备案且配置了 HTTPS 的域名。微信强制要求所有交互接口(特别是支付回调通知)必须通过 HTTPS 传输,本地 localhost 或未备案的 IP 地址在生产环境中是行不通的。

核心交互流程梳理

理清业务时序是编码的前提。小程序支付的标准流程是一个典型的“前端触发 - 后端中转 - 微信处理 - 异步回调”闭环:

  • 第一步:获取用户标识。小程序端调用 wx.login 获取临时 code,后端拿着 code 调用微信接口换取用户的 OpenID。这是后续下单的必备参数。
  • 第二步:统一下单。用户在小程序点击支付后,后端服务器携带订单金额、商品描述、OpenID 等信息,调用微信【JSAPI 下单】接口。
  • 第三步:前端调起支付。微信返回预支付交易会话标识(prepay_id)及相关签名参数给后端,后端将这些参数透传给小程序前端。前端调用 wx.requestPayment 唤起收银台。
  • 第四步:异步通知处理。用户支付成功后,微信服务器会主动向后端配置的 notify_url 发送支付结果通知。切记:订单状态的最终确认必须以这个异步通知为准,而不是依赖前端的同步返回。

Java SDK 集成与依赖配置

虽然可以直接通过 HTTP 请求对接微信 API,但处理复杂的签名算法(RSA2)和证书加解密极易出错。强烈建议使用官方或社区成熟的 Java SDK。目前主流方案是使用 wechatpay-java 系列依赖。

在项目的 pom.xml 中添加以下核心依赖:

<dependency>
    <groupId>com.github.wechatpay-apiv3</groupId>
    <artifactId>wechatpay-java</artifactId>
    <version>0.2.15</version>
</dependency>

引入 SDK 后,你需要在资源目录(resources)下放置从商户平台下载的证书文件:apiclient_cert.pem(商户公钥证书)、apiclient_key.pem(商户私钥),并确保记录了APIv3 密钥(需在商户平台单独设置)和商户号序列号

接下来是配置类的封装,这是初始化的关键:

private Config createConfig() {
    return new RSAPublicKeyConfig.Builder()
            .merchantId("你的商户号")
            .privateKeyFromPath("classpath:cert/apiclient_key.pem")
            .merchantSerialNumber("你的证书序列号")
            .apiV3Key("你的 APIv3 密钥")
            .build();
}

下单接口实现与参数封装

有了配置,就可以编写下单逻辑了。我们需要构建 JsapiServiceExtension 服务实例,并组装请求参数。注意金额单位是,而非元。

public PrepayWithRequestPaymentResponse createOrder(String openId, String outTradeNo, int totalAmount) {
    JsapiServiceExtension service = new JsapiServiceExtension.Builder()
            .config(createConfig())
            .build();

    PrepayRequest request = new PrepayRequest();
    request.setAppid("你的小程序 AppID");
    request.setMchid("你的商户号");
    request.setDescription("测试商品名称");
    request.setOutTradeNo(outTradeNo);
    
    // 金额设置,单位为分
    Amount amount = new Amount();
    amount.setTotal(totalAmount); 
    request.setAmount(amount);

    Payer payer = new Payer();
    payer.setOpenid(openId);
    request.setPayer(payer);
    
    // 设置回调地址,必须是 https 且公网可达
    request.setNotifyUrl("https://your-domain.com/api/pay/notify");

    return service.prepayWithRequestPayment(request);
}

调用成功后,SDK 会返回包含 timeStampnonceStrpackagepaySign 等字段的对象。后端需将这些参数原样返回给小程序前端,由前端执行 wx.requestPayment

回调通知与验签逻辑

支付回调是资金安全最后一道防线。微信发送的通知体是经过加密的 JSON 数据,不能直接使用。必须利用 SDK 提供的工具进行解密和验签,防止伪造请求。

定义一个 Controller 接收 POST 请求:

@PostMapping("/notify")
public String handleNotify(HttpServletRequest request) throws Exception {
    String body = HttpUtils.readData(request);
    // 使用 SDK 解析并验签,若失败会抛出异常
    NotificationParser parser = new NotificationParser(createConfig());
    Transaction result = parser.parse(body, request.getHeader("Wechatpay-Signature"), 
                                      request.getHeader("Wechatpay-Nonce"), 
                                      request.getHeader("Wechatpay-Timestamp"), 
                                      Transaction.class);

    if ("SUCCESS".equals(result.getTradeState())) {
        // 验签通过且支付成功,更新本地订单状态
        // 务必判断订单是否已处理过,避免重复入账
        orderService.updateStatus(result.getOutTradeNo(), OrderStatus.PAID);
    }
    
    // 必须返回标准响应,否则微信会重试通知
    return "{\"code\":\"SUCCESS\",\"message\":\"OK\"}";
}

避坑指南与注意事项

在实际落地过程中,几个细节往往决定成败:

首先是证书路径问题。在 Jar 包部署环境下,使用 File 类读取 classpath 下的证书往往会报错找不到文件。建议改用 InputStream 流式读取,或者将证书放置在服务器固定的绝对路径下。

其次是回调地址的公网可达性。开发阶段如果没有公网域名,可以使用内网穿透工具(如 frp)将本地端口映射到外网,但生产环境务必使用正式备案域名,且确保防火墙未拦截微信服务器的 IP 段。

最后是幂等性处理。微信在网络波动时会多次发送相同的回调通知。你的业务逻辑中必须检查订单当前状态,如果已经是“已支付”,则直接返回成功,严禁重复执行发货或充值操作。

打通支付全流程虽然步骤繁琐,但只要严格按照官方规范配置证书、处理好签名验签逻辑,就能稳稳地接住每一笔交易。

在这里插入图片描述

更多推荐