Java 接入微信支付保姆式教程(一):支付流程、商户号与环境准备
前言
微信支付几乎是国内 Java 开发人员绕不开的一项能力。
不管做的是:
text
商城
外卖
预约系统
SaaS
会员系统
医院系统
门店系统
小程序
公众号
只要系统存在在线收款,就很有可能需要接入微信支付。
但是对于第一次接微信支付的开发者来说,真正让人头疼的往往不是 Java 代码。
而是一上来就会看到一大堆名词:
text
AppID
mchid
商户号
微信商户平台
微信公众平台
微信开放平台
APIv3
APIv3 密钥
商户 API 证书
商户私钥
证书序列号
微信支付公钥
微信支付公钥 ID
openid
prepay_id
第一次看到这些东西的时候,很容易产生一个感觉:
我只是想让用户付个钱,为什么要准备这么多东西?
实际上,只要把微信支付整个体系拆开来看,它并没有想象中那么复杂。
整个微信支付接入,本质上可以理解成三件事情:
text
第一步
证明"我是哪个商户"
第二步
证明"用户正在我的哪个微信应用中支付"
第三步
由我的服务器调用微信支付 API 创建支付订单
其中:
text
商户号 mchid
解决的是:
谁在收钱?
而:
text
AppID
解决的是:
用户在哪个微信应用里完成支付?
最后:
text
商户 API 私钥
+
微信支付公钥
+
APIv3 密钥
解决的则是:
微信支付服务器和我们的服务器之间,如何安全地通信?
所以本系列不会一上来就复制一堆微信支付 SDK 代码。
第一篇我们先把整个微信支付体系真正搞清楚。
本文主要依据当前微信支付官方 API v3 商户文档整理,包括:
- 微信支付小程序支付产品文档;
- JSAPI 支付产品文档;
- 微信支付开发接入准备文档;
- API v3 开发必要参数说明;
- 商户号与 AppID 绑定说明;
- APIv3 密钥说明;
- 商户 API 证书说明;
- 微信支付公钥相关说明。
本文以:
text
普通商户
+
微信小程序
+
Spring Boot
+
微信支付 API v3
作为主要教程场景。
服务商模式、特约商户模式暂时不在本系列第一阶段讨论范围内。
一、我们最终到底要实现什么?
在正式了解微信支付之前,先把最终目标搞清楚。
假设我们现在有一个微信小程序。
用户在小程序中购买一个商品:
text
商品:测试商品
金额:0.01 元
点击:
text
立即支付
然后弹出微信支付收银台。
用户确认金额以后:
text
验证指纹 / 密码
↓
支付成功
↓
返回我们的小程序
最终服务器中的订单状态从:
text
待支付
变成:
text
已支付
看起来非常简单。
但从技术角度来看,这个过程实际上至少涉及三个系统:
text
微信小程序
Java 后端
微信支付服务器
它们之间的大概关系是:
text
┌──────────────────────────┐
│ 微信小程序 │
│ │
│ 用户点击"立即支付" │
└────────────┬─────────────┘
│
│ ① 创建支付请求
▼
┌──────────────────────────┐
│ Java 后端服务 │
│ │
│ 创建业务订单 │
│ 调用微信支付 API v3 │
└────────────┬─────────────┘
│
│ ② JSAPI/小程序下单
▼
┌──────────────────────────┐
│ 微信支付服务器 │
│ │
│ 创建预支付交易 │
└────────────┬─────────────┘
│
│ ③ 返回 prepay_id
▼
┌──────────────────────────┐
│ Java 后端服务 │
│ │
│ 生成小程序调起支付参数 │
└────────────┬─────────────┘
│
│ ④ 返回支付参数
▼
┌──────────────────────────┐
│ 微信小程序 │
│ │
│ wx.requestPayment() │
└────────────┬─────────────┘
│
│ ⑤ 拉起微信收银台
▼
┌──────────────────────────┐
│ 微信支付收银台 │
│ │
│ 用户确认并完成付款 │
└────────────┬─────────────┘
│
│ ⑥ 支付成功
▼
┌──────────────────────────┐
│ 微信支付服务器 │
└────────────┬─────────────┘
│
│ ⑦ 支付结果通知
▼
┌──────────────────────────┐
│ Java 后端服务 │
│ │
│ 验签 / 解密 / 校验 │
│ 更新业务订单状态 │
└──────────────────────────┘
这就是我们整个系列最终需要打通的链路。
微信支付官方当前的小程序支付开发指引也是这个思路:
商户先调用 JSAPI/小程序下单接口获得:
text
prepay_id
然后小程序通过:
javascript
wx.requestPayment()
拉起微信支付收银台。
用户完成或取消支付后返回小程序;对于最终订单状态,商户还需要结合查询订单接口及微信支付发送的支付成功通知进行处理。citeturn165650search13turn165650search0
所以从一开始就要建立一个非常重要的认知:
微信支付不是"小程序调用一个支付 API 就结束了"。
真正的支付系统是:
text
前端
+
自己的后端
+
微信支付服务器
三方共同完成。
二、JSAPI 支付和小程序支付到底是什么?
这个地方是很多新手第一次看微信支付文档时最容易混淆的地方。
因为官方文档中经常会出现:
text
JSAPI支付
以及:
text
小程序支付
而它们下单时又都会看到:
text
/v3/pay/transactions/jsapi
所以很容易产生疑问:
小程序支付是不是就是 JSAPI 支付?
严格来说:
不是同一个支付场景,但当前普通商户的小程序支付和 JSAPI 支付共享支付权限以及 JSAPI/小程序下单接口。
2.1 什么是 JSAPI 支付?
根据微信支付官方目前的定义:
JSAPI 支付主要用于用户在微信客户端内部浏览器网页中完成微信支付。
最典型的场景就是:
text
微信公众号
↓
点击菜单
↓
打开 H5 网页
↓
选择商品
↓
微信内网页发起支付
例如:
text
微信
│
▼
公众号文章 / 菜单 / 分享链接
│
▼
微信内置浏览器
│
▼
商户 H5 页面
│
▼
JSAPI 支付
所以传统意义上的:
text
公众号支付
基本就是大家经常说的:
text
JSAPI 支付
微信支付官方当前对 JSAPI 支付的产品定义也是:为商户提供在微信客户端内部浏览器网页中使用微信支付收款的能力。citeturn165650search1
2.2 什么是小程序支付?
小程序支付就更加直观了。
官方定义是:
商户在自己的微信小程序中,通过微信支付完成收款。
例如:
text
微信
│
▼
XX商城小程序
│
▼
商品详情
│
▼
提交订单
│
▼
立即支付
│
▼
微信支付收银台
小程序支付最典型的前端 API 就是:
javascript
wx.requestPayment({
// 支付参数
})
微信支付官方当前明确说明:
text
小程序支付
=
在商户自身微信小程序中使用微信支付收款
并且当前准入条件中要求相应的小程序满足支付产品要求。citeturn165650search0
2.3 为什么小程序下单接口里面还有 jsapi?
因为微信支付目前的普通商户 API v3 中:
text
JSAPI 支付
和:
text
小程序支付
共享一个下单接口:
http
POST /v3/pay/transactions/jsapi
这个接口的官方名称就是:
text
JSAPI/小程序下单
它负责创建:
text
预支付交易
并返回:
text
prepay_id
官方文档目前明确写明,该接口适用于:
text
JSAPI 支付场景
或
小程序支付场景
并且请求中的 appid 必须与当前使用的 mchid 建立绑定关系。citeturn912615search6
所以:
text
JSAPI 支付
\
\
→ /v3/pay/transactions/jsapi
/
/
小程序支付
后端下单接口可以相同。
但是:
前端调起支付的方法不同。
2.4 两者最大的区别在哪里?
可以简单整理成:
| 项目 | JSAPI 支付 | 小程序支付 |
|---|---|---|
| 使用环境 | 微信客户端内部网页 | 微信小程序 |
| 常见场景 | 公众号/H5 | 微信小程序 |
| API v3 下单 | /v3/pay/transactions/jsapi |
/v3/pay/transactions/jsapi |
| 下单结果 | prepay_id |
prepay_id |
| 前端调起方式 | WeixinJSBridge 等 | wx.requestPayment() |
| AppID | 公众号 AppID | 小程序 AppID |
| JSAPI 支付授权目录 | 需要 | 小程序场景不需要 |
微信支付当前"小程序支付开发接入准备"文档特别说明:
JSAPI 支付与小程序支付共享同一个权限以及下单接口,但调起方式不同;JSAPI 需要校验授权目录,小程序场景不需要配置 JSAPI 支付授权目录。citeturn165650search16
这个区别一定要搞清楚。
因为很多旧教程会把:
text
JSAPI支付
直接等于:
text
小程序支付
实际上并不准确。
三、第一次接微信支付,一共有几个"平台"?
接下来到了微信支付新手最容易混乱的地方。
你很快会遇到:
text
微信公众平台
微信开放平台
微信支付商户平台
三个名字看起来非常像的平台。
第一次接微信支付的人很容易产生疑问:
我到底应该登录哪一个?
其实它们负责的是完全不同的东西。
可以先记住一句话:
text
公众平台
管理公众号 / 小程序
开放平台
主要管理移动应用等开放能力
商户平台
管理"钱"和微信支付
四、微信公众平台是干什么的?
如果我们开发:
text
微信公众号
或者:
text
微信小程序
最常接触的就是微信公众平台。
例如小程序的:
text
AppID
AppSecret
服务器域名
开发设置
版本管理
微信支付商户号绑定
都和这个应用账号有关。
对于本文的小程序支付场景:
text
小程序 AppID
就可以在对应公众平台的小程序开发设置中查看。
微信支付当前官方的 AppID 绑定说明中也明确区分:
- 服务号/公众号 AppID 可在公众平台查看;
- 小程序 AppID 可在公众平台开发设置中查看;
- 移动应用 AppID 则在微信开放平台查看。citeturn165650search2
所以:
text
微信公众平台
│
├── 公众号
│ └── AppID
│
└── 小程序
└── AppID
对于我们这个系列:
text
Spring Boot
+
微信小程序支付
重点就是:
text
小程序 AppID
五、微信开放平台又是干什么的?
这个名字和:
text
微信公众平台
特别容易弄混。
微信开放平台更多会出现在:
text
移动应用
网站应用
微信登录
开放能力
账号体系
等场景。
例如你自己开发了一个:
text
Android App
或者:
text
iOS App
想接微信支付,那么对应的移动应用 AppID 就属于微信开放平台体系。
可以简单理解:
text
小程序
公众号
↓
微信公众平台
Android / iOS App
↓
微信开放平台
注意:
这里说的是便于新手理解的主要使用场景,并不是在定义两个平台的全部能力。
对本系列来说,我们做的是:
text
微信小程序支付
因此主要操作:
text
微信公众平台
+
微信支付商户平台
微信开放平台不是我们当前最核心的后台。
六、微信支付商户平台是干什么的?
如果说:
text
微信公众平台
管理的是:
我的微信应用是谁?
那么:
text
微信支付商户平台
管理的就是:
谁在收钱?
这里最重要的身份就是:
text
商户号
也就是:
text
mchid
后面很多配置都在商户平台完成,例如:
text
查看商户号
开通支付产品
绑定 AppID
配置 APIv3 密钥
申请商户 API 证书
管理微信支付公钥
查看交易
查看账单
退款
资金管理
因此可以把三个体系画成:
text
微信生态
│
┌────────────┼────────────┐
│ │ │
▼ ▼ ▼
微信公众平台 微信开放平台 微信支付商户平台
│ │ │
│ │ │
公众号/小程序 移动应用等 微信支付
│ │ │
AppID AppID mchid
│ │ │
└────────────┼────────────┘
│
▼
支付业务
七、AppID 到底是什么?
终于到了第一个最关键的参数:
text
AppID
AppID 可以理解成:
一个微信应用的唯一身份标识。
例如我有一个商城小程序。
它可能拥有:
text
AppID = wx1234567890abcdef
这代表:
text
这是哪个微信小程序
如果我还有一个公众号:
text
AppID = wxabcdef1234567890
这是另外一个独立的微信应用。
所以:
text
小程序 AppID
≠
公众号 AppID
≠
移动应用 AppID
它们不能因为都属于同一家企业,就认为是同一个 AppID。
微信支付官方"开发必要参数说明"目前将 appid 定义为商户在微信开放平台或公众平台上的账号开发识别码,并且强调:
text
appid 必须与 mchid 建立绑定关系
之后才能用于对应支付场景。citeturn165650search11
八、商户号 mchid 又是什么?
第二个核心参数:
text
mchid
英文通常理解成:
text
Merchant ID
也就是:
text
商户号
它是微信支付为商户分配的唯一身份标识。
假设:
text
某某科技有限公司
注册并开通微信支付以后,微信支付会给这个支付商户分配:
text
mchid = 190000xxxx
以后 Java 后端调用微信支付 API 时,微信支付就是通过这个商户号识别:
到底是哪一个商户在调用支付接口?
微信支付当前开发必要参数说明明确指出:
text
mchid
是商户在微信支付系统中的唯一身份标识,调用接口时需要通过它确认商户身份。citeturn165650search11
8.1 AppID 和 mchid 有什么区别?
这是整篇文章最应该搞明白的问题之一。
一句话:
text
AppID
=
哪个微信应用
mchid
=
哪个支付商户
比如:
text
小程序:
钧逸商城
AppID:
wx123456
这个小程序背后的收款公司:
text
某某科技有限公司
微信支付商户号:
text
mchid:
190000001
那么关系就是:
text
┌────────────────────────┐
│ 微信小程序 │
│ │
│ AppID = wx123456 │
└───────────┬────────────┘
│
│ 授权绑定
│
▼
┌────────────────────────┐
│ 微信支付商户 │
│ │
│ mchid = 190000001 │
└────────────────────────┘
九、为什么 AppID 和商户号必须绑定?
假设:
text
AppID = wxAAA
属于:
text
小程序 A
而:
text
mchid = 100001
属于:
text
商户 A
微信支付不能允许任何一个人随便写:
json
{
"appid": "wxAAA",
"mchid": "100001"
}
就让它们一起收款。
否则我完全可以:
text
拿别人的小程序 AppID
+
绑定我自己的商户号
那整个支付体系就乱了。
所以微信支付要求:
AppID 与 mchid 之间必须建立授权绑定关系。
当前官方的普通商户 AppID 管理文档中,商户需要先从微信支付商户平台发起 AppID 关联申请,然后到相应的平台确认授权。
对于小程序,就是:
text
微信支付商户平台
│
│ 发起关联
▼
小程序 AppID
│
▼
微信公众平台
│
│ 确认授权
▼
绑定完成
而且官方当前说明,一个普通商户号可以关联多个受支持的 AppID 账号,实际绑定仍需满足对应账号类型、认证状态、主体及风险规则等要求。citeturn165650search2
十、一个商户号是不是只能绑定一个小程序?
不是。
实际企业很可能拥有:
text
商城小程序
会员小程序
门店小程序
预约小程序
但收款主体可能都是:
text
同一家公司
因此可以出现:
text
mchid
190000001
│
┌─────────┼─────────┐
│ │ │
▼ ▼ ▼
AppID A AppID B AppID C
│ │ │
▼ ▼ ▼
商城小程序 会员小程序 门店小程序
每个应用和商户号之间都需要按照微信支付要求建立对应关系。
十一、openid 又是什么?为什么支付还需要它?
小程序支付过程中还有一个非常重要的参数:
text
openid
很多新手容易把:
text
AppID
和:
text
openid
混起来。
它们完全不是一个东西。
AppID 表示:
text
哪个应用
openid 表示:
text
当前这个用户
在这个 AppID 下是谁
例如:
text
小程序 AppID
wx123456
用户张三在这个小程序中的:
text
openid
=
oABCxxxxxxxx
所以关系是:
text
微信用户
│
▼
某个小程序 AppID
│
▼
OpenID
微信支付官方的开发必要参数说明也指出:
text
openid
是用户在对应公众账号/小程序体系下的身份标识,不同应用下的 OpenID 可能不同。citeturn912615search7
所以调用小程序支付下单接口时,我们后面会看到类似参数:
json
{
"payer": {
"openid": "oABCxxxxxxxx"
}
}
也就是说微信支付需要知道:
这笔订单最终是哪个微信用户准备支付。
十二、API v3 是什么?为什么教程都在说 API v3?
如果你搜索比较老的微信支付教程,会看到很多:
text
XML
MD5
APIv2
例如:
xml
<xml>
<appid>xxx</appid>
<mch_id>xxx</mch_id>
</xml>
但是现在新项目接微信支付,应该优先按照:
text
微信支付 API v3
进行开发。
API v3 使用:
text
HTTP REST
+
JSON
+
非对称签名
+
HTTPS
这样的现代 API 设计。
例如我们后面小程序下单会调用:
http
POST /v3/pay/transactions/jsapi
请求:
json
{
"appid": "wx123456",
"mchid": "190000001",
"description": "测试商品",
"out_trade_no": "PAY202609140001",
"notify_url": "https://example.com/pay/wechat/notify",
"amount": {
"total": 1,
"currency": "CNY"
},
"payer": {
"openid": "oABCxxxx"
}
}
注意:
text
total = 1
不是:
text
1 元
而是:
text
1 分
这个我们到实际下单篇再详细讲。
微信支付 API v3 官方说明中,当前 API v3 主要使用 REST 风格、JSON 数据交互以及基于非对称密钥的 SHA256-RSA 签名机制,并使用 AES-256-GCM 对需要保护的回调数据进行加密。官方同时推荐开发者使用其提供的 Java/Go 工具库降低签名、验签等接入复杂度。citeturn912615search9
十三、接微信支付到底要准备哪些参数?
到了这里,我们终于可以整理微信支付 Java 开发真正需要的核心东西。
目前普通商户 API v3 场景下,主要需要理解:
| 参数 | 含义 | 主要作用 |
|---|---|---|
mchid |
微信支付商户号 | 标识收款商户 |
appid |
小程序/公众号等 AppID | 标识支付应用 |
openid |
用户身份 | 标识当前付款用户 |
| 商户 API 私钥 | 商户自己的私钥 | 对 API 请求进行签名 |
| 商户 API 证书序列号 | 商户证书编号 | 标识签名所用证书 |
| APIv3 密钥 | 商户自己设置的 32 位密钥 | 解密支付通知等密文 |
| 微信支付公钥 | 微信支付提供 | 验证微信支付响应/通知签名 |
| 微信支付公钥 ID | 对应微信支付公钥 | 确定使用哪把微信支付公钥 |
notify_url |
支付通知地址 | 微信支付通知自己的服务器 |
最终 Java 配置可能会变成:
yaml
wechat:
pay:
app-id: wx1234567890abcdef
mch-id: 1900000001
merchant-serial-number: xxxxxxxxx
private-key-path: classpath:cert/apiclient_key.pem
api-v3-key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
wechat-pay-public-key-id: PUB_KEY_ID_xxx
wechat-pay-public-key-path: classpath:cert/wechatpay_public_key.pem
notify-url: https://api.example.com/pay/wechat/notify
当然,这只是为了让大家提前知道这些参数以后会放在哪里。
第一篇暂时不写具体 Spring Boot 配置。
十四、APIv3 密钥到底是什么?
这个是第一次接微信支付时特别容易理解错的东西。
APIv3 密钥:
text
不是 AppSecret
不是商户私钥
不是证书密码
也不是微信支付公钥
它是一串由商户自己设置并保存的:
text
32 个字符
的密钥。
根据微信支付当前官方说明,APIv3 密钥主要用于:
text
微信支付回调密文解密
以及与平台证书模式相关的解密场景。
官方同时明确提醒:
APIv3 密钥属于敏感信息,设置后应由技术人员安全保存,泄露后需要重新设置。citeturn912615search2
举个例子。
微信支付通知我们的服务器:
http
POST /pay/wechat/notify
回调中的核心交易数据并不是直接:
json
{
"trade_state": "SUCCESS"
}
裸着传过来的。
而会涉及加密后的资源数据。
这时候我们就需要:
text
APIv3 Key
完成相应解密。
因此可以先记:
text
APIv3 Key
主要解决:
微信支付发给我的加密数据
我要怎么解开
十五、商户 API 证书和商户私钥又是什么?
接下来又出现:
text
商户 API 证书
以及:
text
商户 API 私钥
这也是很多人最容易懵的地方。
你可以暂时理解成一对:
text
商户身份凭证
在 API v3 中,我们的 Java 服务器向微信支付发送请求时,需要证明:
这个请求真的是这个商户发出来的,不是别人伪造的。
所以我们的服务器需要使用:
text
商户私钥
对请求进行数字签名。
大概是:
text
Java 后端
│
│ 商户私钥签名
▼
支付请求
│
▼
微信支付
│
│ 校验签名
▼
确认:
确实是该商户发送
商户私钥一定要:
text
严格保管
不要:
text
上传 GitHub
提交到公开 Git 仓库
放到前端代码
写进小程序
发到群里
因为它属于服务器端的核心安全凭据。
微信支付官方目前说明,API v3 请求需要通过商户侧私钥完成请求签名;商户 API 证书中包含商户号、公司名称、公钥等身份信息。citeturn912615search3turn165650search11
十六、商户 API 证书序列号又是什么?
后面代码里我们还会看到:
text
merchantSerialNumber
也就是:
text
商户 API 证书序列号
很多新手第一次看到会想:
有私钥还不够吗?怎么又来一个序列号?
因为一个商户可能存在证书更新等情况。
所以微信支付还需要知道:
text
你这次签名
到底用的是哪一张商户 API 证书对应的私钥?
于是请求中需要带:
text
serial_no
帮助标识对应的商户 API 证书。
可以理解成:
text
商户 API 私钥
=
真正负责签名
证书序列号
=
告诉微信:
我用的是哪一套商户证书身份
官方当前的开发必要参数说明也明确将:
text
商户 API 证书序列号
列为 API v3 请求签名认证的重要参数。citeturn912615search7
十七、微信支付公钥和平台证书到底是什么?
这里需要特别说明。
因为网上大量旧教程都会告诉你:
text
必须下载微信支付平台证书
但是按照当前微信支付官方 API v3 文档,已经不能只这么讲了。
目前验签主要可以理解成两种模式:
text
微信支付公钥模式
或者
微信支付平台证书模式
而当前官方文档明确把:
text
微信支付公钥
标记为推荐使用的方式。
微信支付官方当前的"开发必要参数说明"指出:
text
微信支付公钥
可用于:
- 验证 API v3 返回内容签名;
- 验证相关微信支付消息来源;
- 在涉及敏感参数时用于加密。
同时还有一个:
text
微信支付公钥 ID
用于标识具体使用的微信支付公钥。
对于平台证书,当前官方文档则建议新接入场景优先考虑微信支付公钥模式,因为管理更简单。citeturn912615search7turn912615search9
因此本教程后续如果没有特殊需求,会优先按照:
text
微信支付公钥模式
来讲。
十八、这些密钥和证书到底是什么关系?
现在把刚刚这些东西放到一张图里。
这是整篇文章最重要的一张关系图。
text
我们的 Java 后端
│
│
商户 API 私钥
│
请求签名
│
▼
微信支付 API
│
│
微信支付响应/通知
│
▼
我们的 Java 后端
│ │
│ │
微信支付公钥 APIv3 Key
│ │
验签 解密密文
│ │
└─────┬──────┘
▼
得到可信数据
简单记忆:
text
商户私钥
=
我证明我是我
微信支付公钥
=
我验证微信确实是微信
APIv3 Key
=
我解开微信支付发来的加密内容
这一句话建议新手直接记住。
十九、AppSecret 和 APIv3 Key 是一个东西吗?
不是。
这两个东西特别容易被新手搞混。
AppSecret
属于:
text
微信小程序 / 公众号
主要用于应用身份相关接口。
例如:
text
登录
获取 access_token
服务端调用微信开放接口
APIv3 Key
属于:
text
微信支付商户
主要用于:
text
微信支付 API v3
中的加密数据解密等支付安全场景。
所以:
text
AppSecret
↓
微信应用体系
APIv3 Key
↓
微信支付体系
完全是两套东西。
千万不要混淆。
二十、正式开发前,我们到底需要准备什么?
如果你要跟着本系列完成:
text
Spring Boot
+
微信小程序
+
微信支付 API v3
那么开始写代码之前,至少应该准备好以下内容。
| 项目 | 是否必须 | 说明 |
|---|---|---|
| 微信小程序 | 是 | 支付载体 |
| 小程序 AppID | 是 | 标识小程序 |
| 微信支付商户号 | 是 | 收款商户 |
| 小程序与商户号绑定 | 是 | 建立支付授权关系 |
| 对应支付产品权限 | 是 | 小程序支付需要相应权限 |
| 商户 API 私钥 | 是 | API v3 请求签名 |
| 商户 API 证书序列号 | 是 | 标识商户证书 |
| APIv3 密钥 | 是 | 回调等密文解密 |
| 微信支付公钥 | 推荐方案需要 | API v3 验签 |
| 微信支付公钥 ID | 推荐方案需要 | 标识公钥 |
| Java 后端 | 是 | 调用支付 API |
| HTTPS 公网接口 | 回调阶段需要 | 接收微信支付通知 |
二十一、小程序支付权限怎么准备?
当前官方的小程序支付接入流程,大致可以整理为:
text
注册微信小程序
↓
完成所需认证
↓
申请 / 准备微信支付商户号
↓
开通对应支付权限
↓
商户号发起 AppID 绑定
↓
小程序侧确认绑定
↓
准备支付开发参数
↓
开始 API v3 开发
微信支付当前的小程序支付接入准备文档明确说明:
- 需要准备对应的公众平台小程序账号;
- 按产品要求完成账号认证;
- 已有商户号时,可从商户侧申请对应支付权限并发起 AppID 授权绑定;
- 小程序支付与 JSAPI 支付共享权限和下单接口,但小程序支付不需要配置 JSAPI 支付授权目录。citeturn165650search16
二十二、如果还没有商户号怎么办?
那么首先需要申请微信支付商户号。
这里建议新手不要急着进入代码。
因为:
text
没有 mchid
后面绝大多数支付 API 根本没法正常开发。
商户号本质上代表:
text
真正接受微信支付结算的经营主体
所以申请过程中通常涉及:
text
主体信息
经营信息
联系人
结算账户
相关资质
等内容。
具体支持的主体类型和产品权限会随微信支付规则调整,所以申请时应直接以微信支付商户平台最新页面和官方文档为准。
二十三、正式开发前建议建立一个配置清单
我个人比较推荐,在第一次接微信支付的时候自己整理一张表。
例如:
text
================================
微信支付开发参数
================================
小程序 AppID:
wx________________
商户号 mchid:
__________________
APIv3 Key:
********************************
商户 API 证书序列号:
__________________
商户私钥:
apiclient_key.pem
微信支付公钥 ID:
__________________
微信支付公钥:
wechatpay_public_key.pem
支付回调地址:
https://api.example.com/pay/wechat/notify
================================
当然:
text
私钥
APIv3 Key
AppSecret
这种敏感信息不能真正放进博客、GitHub 或公开文档。
这里只是告诉大家:
在开始写 Java 代码前,先确认这些参数到底有没有准备完整。
否则写代码的时候会不断遇到:
text
这个参数是什么?
去哪里找?
为什么为空?
为什么签名失败?
最后你甚至不知道到底是:
text
代码有问题
还是:
text
商户平台配置根本没完成
二十四、第一篇最重要的:把整个账号关系真正记住
到这里,我们把前面的东西整合成一张完整关系图。
text
微信生态
│
┌──────────────┴──────────────┐
│ │
▼ ▼
微信公众平台 微信支付商户平台
│ │
│ │
微信小程序 微信商户
│ │
▼ ▼
AppID mchid
│ │
└──────────授权绑定────────────┘
│
▼
可以进行微信支付
│
▼
Java 后端服务
│
┌───────────────┼───────────────┐
│ │ │
▼ ▼ ▼
商户私钥 APIv3 Key 微信支付公钥
│ │ │
▼ ▼ ▼
请求签名 数据解密 响应验签
│ │ │
└───────────────┼───────────────┘
│
▼
微信支付 API v3
│
▼
/v3/pay/transactions/jsapi
│
▼
prepay_id
│
▼
微信小程序
│
▼
wx.requestPayment()
│
▼
微信支付收银台
如果这一张图能够完全看懂:
那么微信支付最容易让新手迷糊的基础概念,其实已经解决了一半。
二十五、再看一次完整支付流程
最后,在进入下一篇代码开发之前,再把整个支付流程完整过一遍。
假设用户在小程序购买:
text
商品:测试商品
金额:0.01 元
第一步:用户提交订单
text
小程序
↓
POST /api/pay/wechat/create
第二步:Java 创建自己的业务订单
数据库:
text
order_no = PAY202609140001
amount = 0.01
status = WAIT_PAY
第三步:Java 调微信支付
Java 后端调用:
http
POST /v3/pay/transactions/jsapi
携带:
text
appid
mchid
description
out_trade_no
notify_url
amount
openid
第四步:微信支付返回 prepay_id
例如:
json
{
"prepay_id": "wx201410272009395522657a690389285100"
}
prepay_id 可以理解为:
微信支付为这次支付创建的预支付交易会话标识。
第五步:Java 生成小程序支付参数
后端根据:
text
AppID
timeStamp
nonceStr
package
等信息完成调起支付所需要的签名。
然后返回给小程序。
第六步:小程序调用 wx.requestPayment()
javascript
wx.requestPayment({
timeStamp,
nonceStr,
package,
signType,
paySign
})
然后:
text
微信支付收银台
出现。
第七步:用户完成支付
用户:
text
确认订单
↓
验证密码 / 指纹
↓
支付成功
第八步:微信支付通知 Java 后端
微信支付服务器请求:
text
notify_url
例如:
http
POST https://api.example.com/pay/wechat/notify
Java 后端:
text
验签
↓
解密
↓
校验商户号
↓
校验金额
↓
幂等判断
↓
更新订单
最终:
text
WAIT_PAY
↓
SUCCESS
第九步:必要时主动查单
还有一个非常重要的原则:
不要单纯依赖小程序
wx.requestPayment()的 success 回调判断服务器中的业务订单已经支付成功。
按照微信支付当前开发指引,用户返回商户页面后,商户应结合微信支付订单查询结果处理业务;支付成功时微信支付也会向商户服务器发送支付成功通知。citeturn165650search10turn165650search13
这部分我们会在后面的:
text
支付回调
+
订单查询
中详细讲。
二十六、几个新手特别容易搞错的问题
最后把第一篇最容易混淆的内容集中总结一下。
1. AppID 是商户号吗?
不是。
text
AppID
=
微信应用身份
mchid
=
微信支付商户身份
2. APIv3 Key 是 AppSecret 吗?
不是。
text
AppSecret
=
微信应用开发凭据
APIv3 Key
=
微信支付 API v3 加密相关密钥
3. 商户私钥是 APIv3 Key 吗?
不是。
text
商户私钥
=
数字签名
APIv3 Key
=
相关支付密文解密
4. 小程序支付等于 JSAPI 支付吗?
不能直接画等号。
当前:
text
共享支付权限
共享 JSAPI/小程序下单接口
但是:
text
使用场景
前端调起方式
部分接入配置
不同。
5. 小程序 AppID 能不能随便配一个商户号?
不能。
需要:
text
AppID
↕
mchid
建立授权绑定关系。
6. Java 私钥可以放进小程序吗?
绝对不可以。
以下内容都应该只保存在安全的服务器环境:
text
商户私钥
APIv3 Key
AppSecret
7. wx.requestPayment success 就代表订单可以直接改成已支付吗?
不要这么设计。
客户端回调用于:
text
用户体验
最终可信业务状态应该结合:
text
微信支付通知
+
微信支付订单查询
进行确认。
二十七、本文总结
这一篇我们还没有开始真正写 Java 微信支付代码。
但是已经把微信支付中最容易把新手绕晕的一整套关系梳理完成了。
现在应该能够明确:
text
微信小程序
↓
AppID
解决:
用户在哪个微信应用中支付?
而:
text
微信支付商户
↓
mchid
解决:
到底是谁在收款?
两者:
text
AppID
│
授权绑定
│
mchid
建立支付关系。
然后 Java 服务器需要:
text
商户私钥
完成:
text
API 请求签名
使用:
text
微信支付公钥
完成:
text
微信支付响应/通知验签
使用:
text
APIv3 Key
完成:
text
相关加密数据解密
最后整个支付流程就是:
text
用户
↓
微信小程序
↓
Java 后端
↓
创建业务订单
↓
微信支付 API v3
↓
prepay_id
↓
Java 生成支付参数
↓
wx.requestPayment()
↓
微信支付收银台
↓
用户支付
↓
微信支付通知 Java 后端
↓
验签 + 解密 + 幂等
↓
更新业务订单
如果把这一条链路真正理解清楚,那么接下来真正开始写代码时,就不会再看到:
text
appid
mchid
serialNo
privateKey
apiV3Key
wechatPayPublicKey
openid
prepay_id
以后完全不知道它们分别是干什么的。
下一篇
下一篇正式进入 Java 项目实战:
《Java 接入微信支付保姆式教程(二):Spring Boot 接入微信支付并完成统一下单》
下一篇将基于一个已经存在的 Spring Boot 项目进行演示,不会浪费大量篇幅从零创建 Java 工程。
主要完成:
text
引入微信支付 Java SDK
↓
配置 mchid / AppID
↓
加载商户私钥
↓
配置微信支付公钥
↓
初始化微信支付 Client
↓
设计支付订单
↓
创建微信支付业务订单
↓
调用 JSAPI/小程序下单
↓
获得 prepay_id
也就是从下一篇开始:
我们真正开始写代码,完成第一笔微信支付订单的后端下单。
参考资料
本文主要参考微信支付当前官方文档整理,建议开发过程中始终以微信支付最新官方文档为最终依据。
主要参考:
- 微信支付商户文档中心:《小程序支付 - 产品介绍》
- 微信支付商户文档中心:《小程序支付 - 开发接入准备》
- 微信支付商户文档中心:《小程序支付 - 开发指引》
- 微信支付商户文档中心:《JSAPI支付 - 产品介绍》
- 微信支付商户文档中心:《JSAPI支付 - 开发接入准备》
- 微信支付商户文档中心:《JSAPI/小程序下单》
- 微信支付商户文档中心:《开发必要参数说明》
- 微信支付商户文档中心:《管理商户号绑定的 APPID 账号》
- 微信支付商户文档中心:《配置 APIv3 密钥》
- 微信支付商户文档中心:《申请商户 API 证书》
- 微信支付官方:《APIv3 概述》
需要特别注意:
微信支付产品能力、平台菜单、证书方案和接入要求可能持续调整。本文依据 2026 年 9 月可查询到的微信支付官方 API v3 文档整理,实际开发时请再次核对官方最新要求。