Skip to content

Commit 12a9f83

Browse files
authored
🆕 #3842 【微信支付】添加 wx-java-pay-multi-spring-boot-starter 模块支持多公众号关联配置
1 parent 47b4431 commit 12a9f83

File tree

12 files changed

+1041
-0
lines changed

12 files changed

+1041
-0
lines changed

spring-boot-starters/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
<module>wx-java-mp-multi-spring-boot-starter</module>
2424
<module>wx-java-mp-spring-boot-starter</module>
2525
<module>wx-java-pay-spring-boot-starter</module>
26+
<module>wx-java-pay-multi-spring-boot-starter</module>
2627
<module>wx-java-open-multi-spring-boot-starter</module>
2728
<module>wx-java-open-spring-boot-starter</module>
2829
<module>wx-java-qidian-spring-boot-starter</module>
Lines changed: 316 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,316 @@
1+
# wx-java-pay-multi-spring-boot-starter
2+
3+
## 快速开始
4+
5+
本starter支持微信支付多公众号关联配置,适用于以下场景:
6+
- 一个服务商需要为多个公众号提供支付服务
7+
- 一个系统需要支持多个公众号的支付业务
8+
- 需要根据不同的appId动态切换支付配置
9+
10+
## 使用说明
11+
12+
### 1. 引入依赖
13+
14+
在项目的 `pom.xml` 中添加以下依赖:
15+
16+
```xml
17+
<dependency>
18+
<groupId>com.github.binarywang</groupId>
19+
<artifactId>wx-java-pay-multi-spring-boot-starter</artifactId>
20+
<version>${version}</version>
21+
</dependency>
22+
```
23+
24+
### 2. 添加配置
25+
26+
`application.yml``application.properties` 中配置多个公众号的支付信息。
27+
28+
#### 配置示例(application.yml)
29+
30+
##### V2版本配置
31+
```yml
32+
wx:
33+
pay:
34+
configs:
35+
# 配置1 - 可以使用appId作为key
36+
wx1234567890abcdef:
37+
appId: wx1234567890abcdef
38+
mchId: 1234567890
39+
mchKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
40+
keyPath: classpath:cert/app1/apiclient_cert.p12
41+
notifyUrl: https://example.com/pay/notify
42+
# 配置2 - 也可以使用自定义标识作为key
43+
config2:
44+
appId: wx9876543210fedcba
45+
mchId: 9876543210
46+
mchKey: yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
47+
keyPath: classpath:cert/app2/apiclient_cert.p12
48+
notifyUrl: https://example.com/pay/notify
49+
```
50+
51+
##### V3版本配置
52+
```yml
53+
wx:
54+
pay:
55+
configs:
56+
# 公众号1配置
57+
wx1234567890abcdef:
58+
appId: wx1234567890abcdef
59+
mchId: 1234567890
60+
apiV3Key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
61+
certSerialNo: 62C6CEAA360BCxxxxxxxxxxxxxxx
62+
privateKeyPath: classpath:cert/app1/apiclient_key.pem
63+
privateCertPath: classpath:cert/app1/apiclient_cert.pem
64+
notifyUrl: https://example.com/pay/notify
65+
# 公众号2配置
66+
wx9876543210fedcba:
67+
appId: wx9876543210fedcba
68+
mchId: 9876543210
69+
apiV3Key: yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
70+
certSerialNo: 73D7DFBB471CDxxxxxxxxxxxxxxx
71+
privateKeyPath: classpath:cert/app2/apiclient_key.pem
72+
privateCertPath: classpath:cert/app2/apiclient_cert.pem
73+
notifyUrl: https://example.com/pay/notify
74+
```
75+
76+
##### V3服务商版本配置
77+
```yml
78+
wx:
79+
pay:
80+
configs:
81+
# 服务商为公众号1提供服务
82+
config1:
83+
appId: wxe97b2x9c2b3d # 服务商appId
84+
mchId: 16486610 # 服务商商户号
85+
subAppId: wx118cexxe3c07679 # 子商户公众号appId
86+
subMchId: 16496705 # 子商户号
87+
apiV3Key: Dc1DBwSc094jAKDGR5aqqb7PTHr
88+
privateKeyPath: classpath:cert/apiclient_key.pem
89+
privateCertPath: classpath:cert/apiclient_cert.pem
90+
# 服务商为公众号2提供服务
91+
config2:
92+
appId: wxe97b2x9c2b3d # 服务商appId(可以相同)
93+
mchId: 16486610 # 服务商商户号(可以相同)
94+
subAppId: wx228dexxf4d18890 # 子商户公众号appId(不同)
95+
subMchId: 16496706 # 子商户号(不同)
96+
apiV3Key: Dc1DBwSc094jAKDGR5aqqb7PTHr
97+
privateKeyPath: classpath:cert/apiclient_key.pem
98+
privateCertPath: classpath:cert/apiclient_cert.pem
99+
```
100+
101+
#### 配置示例(application.properties)
102+
103+
```properties
104+
# 公众号1配置
105+
wx.pay.configs.wx1234567890abcdef.app-id=wx1234567890abcdef
106+
wx.pay.configs.wx1234567890abcdef.mch-id=1234567890
107+
wx.pay.configs.wx1234567890abcdef.apiv3-key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
108+
wx.pay.configs.wx1234567890abcdef.cert-serial-no=62C6CEAA360BCxxxxxxxxxxxxxxx
109+
wx.pay.configs.wx1234567890abcdef.private-key-path=classpath:cert/app1/apiclient_key.pem
110+
wx.pay.configs.wx1234567890abcdef.private-cert-path=classpath:cert/app1/apiclient_cert.pem
111+
wx.pay.configs.wx1234567890abcdef.notify-url=https://example.com/pay/notify
112+
113+
# 公众号2配置
114+
wx.pay.configs.wx9876543210fedcba.app-id=wx9876543210fedcba
115+
wx.pay.configs.wx9876543210fedcba.mch-id=9876543210
116+
wx.pay.configs.wx9876543210fedcba.apiv3-key=yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
117+
wx.pay.configs.wx9876543210fedcba.cert-serial-no=73D7DFBB471CDxxxxxxxxxxxxxxx
118+
wx.pay.configs.wx9876543210fedcba.private-key-path=classpath:cert/app2/apiclient_key.pem
119+
wx.pay.configs.wx9876543210fedcba.private-cert-path=classpath:cert/app2/apiclient_cert.pem
120+
wx.pay.configs.wx9876543210fedcba.notify-url=https://example.com/pay/notify
121+
```
122+
123+
### 3. 使用示例
124+
125+
自动注入的类型:`WxPayMultiServices`
126+
127+
```java
128+
import com.binarywang.spring.starter.wxjava.pay.service.WxPayMultiServices;
129+
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request;
130+
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryV3Result;
131+
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result;
132+
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
133+
import com.github.binarywang.wxpay.service.WxPayService;
134+
import org.springframework.beans.factory.annotation.Autowired;
135+
import org.springframework.stereotype.Service;
136+
137+
@Service
138+
public class PayService {
139+
@Autowired
140+
private WxPayMultiServices wxPayMultiServices;
141+
142+
/**
143+
* 为不同的公众号创建支付订单
144+
*
145+
* @param configKey 配置标识(即 wx.pay.configs.&lt;configKey&gt; 中的 key,可以是 appId 或自定义标识)
146+
*/
147+
public void createOrder(String configKey, String openId, Integer totalFee, String body) throws Exception {
148+
// 根据配置标识获取对应的WxPayService
149+
WxPayService wxPayService = wxPayMultiServices.getWxPayService(configKey);
150+
151+
if (wxPayService == null) {
152+
throw new IllegalArgumentException("未找到配置标识对应的微信支付配置: " + configKey);
153+
}
154+
155+
// 使用WxPayService进行支付操作
156+
WxPayUnifiedOrderV3Request request = new WxPayUnifiedOrderV3Request();
157+
request.setOutTradeNo(generateOutTradeNo());
158+
request.setDescription(body);
159+
request.setAmount(new WxPayUnifiedOrderV3Request.Amount().setTotal(totalFee));
160+
request.setPayer(new WxPayUnifiedOrderV3Request.Payer().setOpenid(openId));
161+
request.setNotifyUrl(wxPayService.getConfig().getNotifyUrl());
162+
163+
// V3统一下单
164+
WxPayUnifiedOrderV3Result.JsapiResult result =
165+
wxPayService.createOrderV3(TradeTypeEnum.JSAPI, request);
166+
167+
// 返回给前端用于调起支付
168+
// ...
169+
}
170+
171+
/**
172+
* 服务商模式示例
173+
*/
174+
public void serviceProviderExample(String configKey) throws Exception {
175+
// 使用配置标识获取WxPayService
176+
WxPayService wxPayService = wxPayMultiServices.getWxPayService(configKey);
177+
178+
if (wxPayService == null) {
179+
throw new IllegalArgumentException("未找到配置: " + configKey);
180+
}
181+
182+
// 获取子商户的配置信息
183+
String subAppId = wxPayService.getConfig().getSubAppId();
184+
String subMchId = wxPayService.getConfig().getSubMchId();
185+
186+
// 进行支付操作
187+
// ...
188+
}
189+
190+
/**
191+
* 查询订单示例
192+
*
193+
* @param configKey 配置标识(即 wx.pay.configs.&lt;configKey&gt; 中的 key)
194+
*/
195+
public void queryOrder(String configKey, String outTradeNo) throws Exception {
196+
WxPayService wxPayService = wxPayMultiServices.getWxPayService(configKey);
197+
198+
if (wxPayService == null) {
199+
throw new IllegalArgumentException("未找到配置标识对应的微信支付配置: " + configKey);
200+
}
201+
202+
// 查询订单
203+
WxPayOrderQueryV3Result result = wxPayService.queryOrderV3(null, outTradeNo);
204+
// 处理查询结果
205+
// ...
206+
}
207+
208+
private String generateOutTradeNo() {
209+
// 生成商户订单号
210+
return "ORDER_" + System.currentTimeMillis();
211+
}
212+
}
213+
```
214+
215+
### 4. 配置说明
216+
217+
#### 必填配置项
218+
219+
| 配置项 | 说明 | 示例 |
220+
|--------|------|------|
221+
| appId | 公众号或小程序的appId | wx1234567890abcdef |
222+
| mchId | 商户号 | 1234567890 |
223+
224+
#### V2版本配置项
225+
226+
| 配置项 | 说明 | 是否必填 |
227+
|--------|------|----------|
228+
| mchKey | 商户密钥 | 是(V2) |
229+
| keyPath | p12证书文件路径 | 部分接口需要 |
230+
231+
#### V3版本配置项
232+
233+
| 配置项 | 说明 | 是否必填 |
234+
|--------|------|----------|
235+
| apiV3Key | API V3密钥 | 是(V3) |
236+
| certSerialNo | 证书序列号 | 是(V3) |
237+
| privateKeyPath | apiclient_key.pem路径 | 是(V3) |
238+
| privateCertPath | apiclient_cert.pem路径 | 是(V3) |
239+
240+
#### 服务商模式配置项
241+
242+
| 配置项 | 说明 | 是否必填 |
243+
|--------|------|----------|
244+
| subAppId | 子商户公众号appId | 服务商模式必填 |
245+
| subMchId | 子商户号 | 服务商模式必填 |
246+
247+
#### 可选配置项
248+
249+
| 配置项 | 说明 | 默认值 |
250+
|--------|------|--------|
251+
| notifyUrl | 支付结果通知URL ||
252+
| refundNotifyUrl | 退款结果通知URL ||
253+
| serviceId | 微信支付分serviceId ||
254+
| payScoreNotifyUrl | 支付分回调地址 ||
255+
| payScorePermissionNotifyUrl | 支付分授权回调地址 ||
256+
| useSandboxEnv | 是否使用沙箱环境 | false |
257+
| apiHostUrl | 自定义API主机地址 | https://api.mch.weixin.qq.com |
258+
| strictlyNeedWechatPaySerial | 是否所有V3请求都添加序列号头 | false |
259+
| fullPublicKeyModel | 是否完全使用公钥模式 | false |
260+
| publicKeyId | 公钥ID ||
261+
| publicKeyPath | 公钥文件路径 ||
262+
263+
## 常见问题
264+
265+
### 1. 如何选择配置的key?
266+
267+
配置的key(即 `wx.pay.configs.<configKey>` 中的 `<configKey>` 部分)可以自由选择:
268+
- 可以使用appId作为key(如 `wx.pay.configs.wx1234567890abcdef`),这样调用 `getWxPayService("wx1234567890abcdef")` 时就像直接用 appId 获取服务
269+
- 可以使用自定义标识(如 `wx.pay.configs.config1`),调用时使用 `getWxPayService("config1")`
270+
271+
**注意**`getWxPayService(configKey)` 方法的参数是配置文件中定义的 key,而不是 appId。只有当你使用 appId 作为配置 key 时,才能直接传入 appId。
272+
273+
### 2. V2和V3配置可以混用吗?
274+
275+
可以。不同的配置可以使用不同的版本,例如:
276+
```yml
277+
wx:
278+
pay:
279+
configs:
280+
app1: # V2配置
281+
appId: wx111
282+
mchId: 111
283+
mchKey: xxx
284+
app2: # V3配置
285+
appId: wx222
286+
mchId: 222
287+
apiV3Key: yyy
288+
privateKeyPath: xxx
289+
```
290+
291+
### 3. 证书文件如何放置?
292+
293+
证书文件可以放在以下位置:
294+
- `src/main/resources` 目录下,使用 `classpath:` 前缀
295+
- 服务器绝对路径,直接填写完整路径
296+
- 建议为不同配置使用不同的目录组织证书
297+
298+
### 4. 服务商模式如何配置?
299+
300+
服务商模式需要同时配置服务商信息和子商户信息:
301+
- `appId` 和 `mchId` 填写服务商的信息
302+
- `subAppId` 和 `subMchId` 填写子商户的信息
303+
304+
## 注意事项
305+
306+
1. **配置安全**:生产环境中的密钥、证书等敏感信息,建议使用配置中心或环境变量管理
307+
2. **证书管理**:不同公众号的证书文件要分开存放,避免混淆
308+
3. **懒加载**:WxPayService 实例采用懒加载策略,只有在首次调用时才会创建
309+
4. **线程安全**:WxPayMultiServices 的实现是线程安全的
310+
5. **配置更新**:如需动态更新配置,可调用 `removeWxPayService(configKey)` 方法移除缓存的实例
311+
312+
## 更多信息
313+
314+
- [WxJava 项目首页](https://github.com/Wechat-Group/WxJava)
315+
- [微信支付官方文档](https://pay.weixin.qq.com/wiki/doc/api/)
316+
- [微信支付V3接口文档](https://pay.weixin.qq.com/wiki/doc/apiv3/index.shtml)
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<parent>
6+
<artifactId>wx-java-spring-boot-starters</artifactId>
7+
<groupId>com.github.binarywang</groupId>
8+
<version>4.8.0</version>
9+
</parent>
10+
<modelVersion>4.0.0</modelVersion>
11+
12+
<artifactId>wx-java-pay-multi-spring-boot-starter</artifactId>
13+
<name>WxJava - Spring Boot Starter for Pay::支持多公众号关联配置</name>
14+
<description>微信支付开发的 Spring Boot Starter::支持多公众号关联配置</description>
15+
16+
<dependencies>
17+
<dependency>
18+
<groupId>com.github.binarywang</groupId>
19+
<artifactId>weixin-java-pay</artifactId>
20+
<version>${project.version}</version>
21+
</dependency>
22+
<dependency>
23+
<groupId>org.springframework.boot</groupId>
24+
<artifactId>spring-boot-starter-test</artifactId>
25+
<version>${spring.boot.version}</version>
26+
<scope>test</scope>
27+
</dependency>
28+
</dependencies>
29+
30+
<build>
31+
<plugins>
32+
<plugin>
33+
<groupId>org.springframework.boot</groupId>
34+
<artifactId>spring-boot-maven-plugin</artifactId>
35+
<version>${spring.boot.version}</version>
36+
</plugin>
37+
<plugin>
38+
<groupId>org.apache.maven.plugins</groupId>
39+
<artifactId>maven-source-plugin</artifactId>
40+
<version>2.2.1</version>
41+
<executions>
42+
<execution>
43+
<id>attach-sources</id>
44+
<goals>
45+
<goal>jar-no-fork</goal>
46+
</goals>
47+
</execution>
48+
</executions>
49+
</plugin>
50+
</plugins>
51+
</build>
52+
53+
</project>

0 commit comments

Comments
 (0)