最近在做自助洗车项目中,因每个门店需要使用自己的商户收款,所以需要wxjava多商户支持,在百度查了些资料,基本都是单个商户的使用案例,遂把项目中的一些总结分享。
先介绍下单商户的使用
- pom文件引入jar包
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java-pay-spring-boot-starter</artifactId>
<version>4.2.0</version>
</dependency>
- application.yml 配置商户信息
wx
pay:
notifyUrl: 通知URI
appId: 支付appid
mchId: 微信支付商户ID
mchKey: 商户api密匙
#subAppId: 子商户appID #服务商调用情况下需要
#subMchId: 子商户微信支付商户ID #服务商调用情况下需要
#keyPath: classpath:/static/apiclient_cert.p12 #需要退款等特殊操作需要证书,一般操作不用
- 然后在项目中注入service就可以使用了
@Autowired
private WxPayService wxPayService;
单个商户使用非常简单,至于如何使用可以去wxjava github上面查看文档,或可以直接打开源码,每个方法上面都有详细的介绍
多商户如何使用
- 我们先分析下单商户是如何自动注入的
@Configuration
@EnableConfigurationProperties(WxPayProperties.class)
@ConditionalOnClass(WxPayService.class)
@ConditionalOnProperty(prefix = "wx.pay", value = "enabled", matchIfMissing = true)
public class WxPayAutoConfiguration {
private WxPayProperties properties;
@Autowired
public WxPayAutoConfiguration(WxPayProperties properties) {
this.properties = properties;
}
/**
* 构造微信支付服务对象.
*
* @return 微信支付service
*/
@Bean
@ConditionalOnMissingBean(WxPayService.class) //当没有WxPayService的时候就会自动创建此对象
public WxPayService wxPayService() {
final WxPayServiceImpl wxPayService = new WxPayServiceImpl();
WxPayConfig payConfig = new WxPayConfig();
payConfig.setAppId(StringUtils.trimToNull(this.properties.getAppId()));
payConfig.setMchId(StringUtils.trimToNull(this.properties.getMchId()));
payConfig.setMchKey(StringUtils.trimToNull(this.properties.getMchKey()));
payConfig.setSubAppId(StringUtils.trimToNull(this.properties.getSubAppId()));
payConfig.setSubMchId(StringUtils.trimToNull(this.properties.getSubMchId()));
payConfig.setKeyPath(StringUtils.trimToNull(this.properties.getKeyPath()));
//以下是apiv3以及支付分相关
payConfig.setServiceId(StringUtils.trimToNull(this.properties.getServiceId()));
payConfig.setPayScoreNotifyUrl(StringUtils.trimToNull(this.properties.getPayScoreNotifyUrl()));
payConfig.setPrivateKeyPath(StringUtils.trimToNull(this.properties.getPrivateKeyPath()));
payConfig.setPrivateCertPath(StringUtils.trimToNull(this.properties.getPrivateCertPath()));
payConfig.setCertSerialNo(StringUtils.trimToNull(this.properties.getCertSerialNo()));
payConfig.setApiV3Key(StringUtils.trimToNull(this.properties.getApiv3Key()));
wxPayService.setConfig(payConfig);
return wxPayService;
}
}
- 通过注解 @ConditionalOnMissingBean(WxPayService.class) 可以知道当没有WxPayService的时候就会自动创建此对象,那我们不用spring创建,自己创建一个WxPayService,然后添加多个商户信息。
@Bean
public WxPayService wxPayService() {
final WxPayServiceImpl wxPayService = new WxPayServiceImpl();
//通过数据库或者配置文件读取出所有的wxpay配置,我们这里用空的list模拟;
List<Object> payConfigList = new ArrayList<>();
for (Object o : payConfigList) {
WxPayConfig payConfig = new WxPayConfig();
//通过代码 将 o 对应赋值到payConfig。 此处忽略
/*
payConfig.setAppId(StringUtils.trimToNull(this.properties.getAppId()));
payConfig.setMchId(StringUtils.trimToNull(this.properties.getMchId()));
payConfig.setMchKey(StringUtils.trimToNull(this.properties.getMchKey()));
payConfig.setSubAppId(StringUtils.trimToNull(this.properties.getSubAppId()));
payConfig.setSubMchId(StringUtils.trimToNull(this.properties.getSubMchId()));
payConfig.setKeyPath(StringUtils.trimToNull(this.properties.getKeyPath()));
//以下是apiv3以及支付分相关
payConfig.setServiceId(StringUtils.trimToNull(this.properties.getServiceId()));
payConfig.setPayScoreNotifyUrl(StringUtils.trimToNull(this.properties.getPayScoreNotifyUrl()));
payConfig.setPrivateKeyPath(StringUtils.trimToNull(this.properties.getPrivateKeyPath()));
payConfig.setPrivateCertPath(StringUtils.trimToNull(this.properties.getPrivateCertPath()));
payConfig.setCertSerialNo(StringUtils.trimToNull(this.properties.getCertSerialNo()));
payConfig.setApiV3Key(StringUtils.trimToNull(this.properties.getApiv3Key()));*/
//注意这里是addConfig,而不是setConfig
//第一个参数的作用是以后可以通过设置的这个key去拿到对应的wxPayService,因为现在是多个商户,通过这个key就能拿到对 应每个商户的service去调用
//理论上这个key是可以放其他数据的,但是这里一定要记住,如果你没有特殊需求,这里就放mchId,否则你会引起不必要的麻 烦。这个我在文末会说。
wxPayService.addConfig(payConfig.getMchId(),payConfig);
}
return wxPayService;
}
- 业务代码中如何使用
@Autowired
private WxPayService wxPayService;
@PostMapping("/create")
@Login
public R create(@RequestBody WxPayUnifiedOrderRequest request) throws WxPayException {
//忽略业务代码
//我们这里模拟mchId是通过业务代码查询出来门店对应的微信支付商户ID
long mchId = "123"
//switchoverTo 就是通过key找到对应的商户配置,返回service就可以调用了。
WxPayService myWxPayService = wxPayService.switchoverTo(mchId);
return R.ok().put("orderInfo", myWxPayService.createOrder(request));
}
血泪教训,一定要注意的事项
- 一定不能在服务商模式中这样使用,一定不能在服务商模式中这样使用,一定不能在服务商模式中这样使用。
- 还是上条,因为我在业务中把之前直联通道改成服务商模式后,导致收款出现问题,应该是付给店A的,付到店B这样的严重问题,后来用了一天时间才把账目对上。最后检查发现是addConfig的 key问题导致,因为服务商模式下mchId都是同样的,这样获取到的永远是第一个使用过的,导致出现问题,血泪教训,这个问题我在下篇文章中将会具体说明。
文末补充为什么addConfig没有特殊需求就放mchId
我们先查看addConfig的源码
@Override
public void addConfig(String mchId, WxPayConfig wxPayConfig) {
synchronized (this) {
if (this.configMap == null) {
this.setConfig(wxPayConfig); //注意跳转这里根本没有使用你设置的key
} else {
WxPayConfigHolder.set(mchId);
this.configMap.put(mchId, wxPayConfig);
}
}
}
@Override
public void setConfig(WxPayConfig config) {
final String defaultMchId = config.getMchId();
//注意这里map key使用的是什么
this.setMultiConfig(ImmutableMap.of(defaultMchId, config), defaultMchId);
}
- wxPayService默认有个configMap用来缓存所有的配置信息
protected Map<String, WxPayConfig> configMap;
- 第一次addConfig时,因为configMap == null 它就会调用setConfig,而setConfig代码你会发现,它根本没有设置你的key,而是用了WxpayConfig默认的mchId,所以说如果你要设置自己的key在这里就会出现问题,导致你以后switchoverTo(”你设置的key“)时拿不到你想要的wxPayService了。这也就是我为什么建议没有特殊需求就放mchId。
- 如何解决这个问题呢,就是你自己写一个service继承WxPayServiceImpl,重写这个addConfig方法。
写文不易,如果对您有帮助,点赞支持下~
下篇文章将会分享服务商模式如何使用以及遇到的坑~
有任何疑问也可以wx:157239486 交流
标签:springBoot,trimToNull,商户,微信,wxPayService,StringUtils,payConfig,wxjava,properties From: https://www.cnblogs.com/dixueli/p/16854175.html