🎨 【微信支付】增加多配置切换功能

This commit is contained in:
Neror 2025-01-20 16:12:00 +00:00 committed by Binary Wang
parent 1e003ee571
commit 24ebc91dca
2 changed files with 55 additions and 45 deletions

View File

@ -39,16 +39,18 @@ public interface WxPayService {
* Map里 加入新的 {@link WxPayConfig}适用于动态添加新的微信商户配置. * Map里 加入新的 {@link WxPayConfig}适用于动态添加新的微信商户配置.
* *
* @param mchId 商户id * @param mchId 商户id
* @param appId 微信应用id
* @param wxPayConfig 新的微信配置 * @param wxPayConfig 新的微信配置
*/ */
void addConfig(String mchId, WxPayConfig wxPayConfig); void addConfig(String mchId, String appId, WxPayConfig wxPayConfig);
/** /**
* Map中 移除 {@link String mchId} 所对应的 {@link WxPayConfig}适用于动态移除微信商户配置. * Map中 移除 {@link String mchId} {@link String appId} 所对应的 {@link WxPayConfig}适用于动态移除微信商户配置.
* *
* @param mchId 对应商户的标识 * @param mchId 对应商户的标识
* @param appId 微信应用id
*/ */
void removeConfig(String mchId); void removeConfig(String mchId, String appId);
/** /**
* 注入多个 {@link WxPayConfig} 的实现. 并为每个 {@link WxPayConfig} 赋予不同的 {@link String mchId} * 注入多个 {@link WxPayConfig} 的实现. 并为每个 {@link WxPayConfig} 赋予不同的 {@link String mchId}
@ -70,17 +72,19 @@ public interface WxPayService {
* 进行相应的商户切换. * 进行相应的商户切换.
* *
* @param mchId 商户标识 * @param mchId 商户标识
* @param appId 微信应用id
* @return 切换是否成功 boolean * @return 切换是否成功 boolean
*/ */
boolean switchover(String mchId); boolean switchover(String mchId, String appId);
/** /**
* 进行相应的商户切换. * 进行相应的商户切换.
* *
* @param mchId 商户标识 * @param mchId 商户标识
* @param appId 微信应用id
* @return 切换成功 则返回当前对象方便链式调用否则抛出异常 * @return 切换成功 则返回当前对象方便链式调用否则抛出异常
*/ */
WxPayService switchoverTo(String mchId); WxPayService switchoverTo(String mchId, String appId);
/** /**
* 发送post请求得到响应字节数组. * 发送post请求得到响应字节数组.
@ -617,10 +621,10 @@ public interface WxPayService {
/** /**
* 调用统一下单接口并组装生成支付所需参数对象. * 调用统一下单接口并组装生成支付所需参数对象.
* *
* @param <T> 请使用{@link com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result}里的内部类或字段 * @param <T> 请使用{@link WxPayUnifiedOrderV3Result}里的内部类或字段
* @param tradeType the trade type * @param tradeType the trade type
* @param request 统一下单请求参数 * @param request 统一下单请求参数
* @return 返回 {@link com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result}里的内部类或字段 * @return 返回 {@link WxPayUnifiedOrderV3Result}里的内部类或字段
* @throws WxPayException the wx pay exception * @throws WxPayException the wx pay exception
*/ */
<T> T createOrderV3(TradeTypeEnum tradeType, WxPayUnifiedOrderV3Request request) throws WxPayException; <T> T createOrderV3(TradeTypeEnum tradeType, WxPayUnifiedOrderV3Request request) throws WxPayException;
@ -628,10 +632,10 @@ public interface WxPayService {
/** /**
* 服务商模式调用统一下单接口并组装生成支付所需参数对象. * 服务商模式调用统一下单接口并组装生成支付所需参数对象.
* *
* @param <T> 请使用{@link com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result}里的内部类或字段 * @param <T> 请使用{@link WxPayUnifiedOrderV3Result}里的内部类或字段
* @param tradeType the trade type * @param tradeType the trade type
* @param request 统一下单请求参数 * @param request 统一下单请求参数
* @return 返回 {@link com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result}里的内部类或字段 * @return 返回 {@link WxPayUnifiedOrderV3Result}里的内部类或字段
* @throws WxPayException the wx pay exception * @throws WxPayException the wx pay exception
*/ */
<T> T createPartnerOrderV3(TradeTypeEnum tradeType, WxPayPartnerUnifiedOrderV3Request request) throws WxPayException; <T> T createPartnerOrderV3(TradeTypeEnum tradeType, WxPayPartnerUnifiedOrderV3Request request) throws WxPayException;
@ -1615,7 +1619,8 @@ public interface WxPayService {
/** /**
* 获取服务商直股份签约计划服务类 * 获取服务商直股份签约计划服务类
* @return the partner pay score sign plan service *
* @return the partner pay score sign plan service
*/ */
PartnerPayScoreSignPlanService getPartnerPayScoreSignPlanService(); PartnerPayScoreSignPlanService getPartnerPayScoreSignPlanService();
} }

View File

@ -14,7 +14,6 @@ import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
import com.github.binarywang.wxpay.bean.transfer.TransferBillsNotifyResult; import com.github.binarywang.wxpay.bean.transfer.TransferBillsNotifyResult;
import com.github.binarywang.wxpay.config.WxPayConfig; import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.config.WxPayConfigHolder; import com.github.binarywang.wxpay.config.WxPayConfigHolder;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.constant.WxPayConstants.SignType; import com.github.binarywang.wxpay.constant.WxPayConstants.SignType;
import com.github.binarywang.wxpay.constant.WxPayConstants.TradeType; import com.github.binarywang.wxpay.constant.WxPayConstants.TradeType;
import com.github.binarywang.wxpay.exception.WxPayException; import com.github.binarywang.wxpay.exception.WxPayException;
@ -46,6 +45,7 @@ import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.zip.ZipException; import java.util.zip.ZipException;
import static com.github.binarywang.wxpay.constant.WxPayConstants.QUERY_COMMENT_DATE_FORMAT; import static com.github.binarywang.wxpay.constant.WxPayConstants.QUERY_COMMENT_DATE_FORMAT;
@ -122,7 +122,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
private final PartnerPayScoreService partnerPayScoreService = new PartnerPayScoreServiceImpl(this); private final PartnerPayScoreService partnerPayScoreService = new PartnerPayScoreServiceImpl(this);
@Getter @Getter
private final PartnerPayScoreSignPlanService partnerPayScoreSignPlanService=new PartnerPayScoreSignPlanServiceImpl(this); private final PartnerPayScoreSignPlanService partnerPayScoreSignPlanService = new PartnerPayScoreSignPlanServiceImpl(this);
@Getter @Getter
private final MerchantTransferService merchantTransferService = new MerchantTransferServiceImpl(this); private final MerchantTransferService merchantTransferService = new MerchantTransferServiceImpl(this);
@ -130,7 +130,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
@Getter @Getter
private final BrandMerchantTransferService brandMerchantTransferService = new BrandMerchantTransferServiceImpl(this); private final BrandMerchantTransferService brandMerchantTransferService = new BrandMerchantTransferServiceImpl(this);
protected Map<String, WxPayConfig> configMap = new HashMap<>(); protected Map<String, WxPayConfig> configMap = new ConcurrentHashMap<>();
@Override @Override
public WxPayConfig getConfig() { public WxPayConfig getConfig() {
@ -143,38 +143,37 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
@Override @Override
public void setConfig(WxPayConfig config) { public void setConfig(WxPayConfig config) {
final String defaultMchId = config.getMchId(); final String defaultKey = this.getConfigKey(config.getMchId(), config.getAppId());
this.setMultiConfig(ImmutableMap.of(defaultMchId, config), defaultMchId); this.setMultiConfig(ImmutableMap.of(defaultKey, config), defaultKey);
} }
@Override @Override
public void addConfig(String mchId, WxPayConfig wxPayConfig) { public void addConfig(String mchId, String appId, WxPayConfig wxPayConfig) {
synchronized (this) { synchronized (this) {
if (this.configMap == null) { if (this.configMap == null) {
this.setConfig(wxPayConfig); this.setConfig(wxPayConfig);
} else { } else {
WxPayConfigHolder.set(mchId); String configKey = this.getConfigKey(mchId, appId);
this.configMap.put(mchId, wxPayConfig); WxPayConfigHolder.set(configKey);
this.configMap.put(configKey, wxPayConfig);
} }
} }
} }
@Override @Override
public void removeConfig(String mchId) { public void removeConfig(String mchId, String appId) {
synchronized (this) { synchronized (this) {
if (this.configMap.size() == 1) { String configKey = this.getConfigKey(mchId, appId);
this.configMap.remove(mchId); this.configMap.remove(configKey);
log.warn("已删除最后一个商户号配置:{}须立即使用setConfig或setMultiConfig添加配置", mchId); if (this.configMap.isEmpty()) {
log.warn("已删除最后一个商户号配置mchId[{}],appid[{}]须立即使用setConfig或setMultiConfig添加配置", mchId, appId);
return; return;
} }
if (WxPayConfigHolder.get().equals(mchId)) { if (WxPayConfigHolder.get().equals(configKey)) {
this.configMap.remove(mchId); final String nextConfigKey = this.configMap.keySet().iterator().next();
final String defaultMpId = this.configMap.keySet().iterator().next(); WxPayConfigHolder.set(nextConfigKey);
WxPayConfigHolder.set(defaultMpId); log.warn("已删除默认商户号配置,商户号【{}】被设为默认配置", nextConfigKey);
log.warn("已删除默认商户号配置,商户号【{}】被设为默认配置", defaultMpId);
return;
} }
this.configMap.remove(mchId);
} }
} }
@ -184,28 +183,34 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
} }
@Override @Override
public void setMultiConfig(Map<String, WxPayConfig> wxPayConfigs, String defaultMchId) { public void setMultiConfig(Map<String, WxPayConfig> wxPayConfigs, String defaultConfigKey) {
this.configMap = Maps.newHashMap(wxPayConfigs); this.configMap = Maps.newHashMap(wxPayConfigs);
WxPayConfigHolder.set(defaultMchId); WxPayConfigHolder.set(defaultConfigKey);
} }
@Override @Override
public boolean switchover(String mchId) { public boolean switchover(String mchId, String appId) {
if (this.configMap.containsKey(mchId)) { String configKey = this.getConfigKey(mchId, appId);
WxPayConfigHolder.set(mchId); if (this.configMap.containsKey(configKey)) {
WxPayConfigHolder.set(configKey);
return true; return true;
} }
log.error("无法找到对应【{}】的商户号配置信息,请核实!", mchId); log.error("无法找到对应mchId=【{}】,appId=【{}】的商户号配置信息,请核实!", mchId, appId);
return false; return false;
} }
@Override @Override
public WxPayService switchoverTo(String mchId) { public WxPayService switchoverTo(String mchId, String appId) {
if (this.configMap.containsKey(mchId)) { String configKey = this.getConfigKey(mchId, appId);
WxPayConfigHolder.set(mchId); if (this.configMap.containsKey(configKey)) {
WxPayConfigHolder.set(configKey);
return this; return this;
} }
throw new WxRuntimeException(String.format("无法找到对应【%s】的商户号配置信息请核实", mchId)); throw new WxRuntimeException(String.format("无法找到对应mchId=【%s】,appId=【%s】的商户号配置信息请核实", mchId, appId));
}
private String getConfigKey(String mchId, String appId) {
return mchId + "_" + appId;
} }
@Override @Override
@ -302,7 +307,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
@Override @Override
public WxPayRefundQueryV3Result refundPartnerQueryV3(WxPayRefundQueryV3Request request) throws WxPayException { public WxPayRefundQueryV3Result refundPartnerQueryV3(WxPayRefundQueryV3Request request) throws WxPayException {
String url = String.format("%s/v3/refund/domestic/refunds/%s?sub_mchid=%s", this.getPayBaseUrl(), request.getOutRefundNo(),request.getSubMchid()); String url = String.format("%s/v3/refund/domestic/refunds/%s?sub_mchid=%s", this.getPayBaseUrl(), request.getOutRefundNo(), request.getSubMchid());
String response = this.getV3(url); String response = this.getV3(url);
return GSON.fromJson(response, WxPayRefundQueryV3Result.class); return GSON.fromJson(response, WxPayRefundQueryV3Result.class);
} }
@ -324,7 +329,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
} else if (configMap.get(result.getMchId()).getSignType() != null) { } else if (configMap.get(result.getMchId()).getSignType() != null) {
// 如果配置中signType有值则使用它进行验签 // 如果配置中signType有值则使用它进行验签
signType = configMap.get(result.getMchId()).getSignType(); signType = configMap.get(result.getMchId()).getSignType();
this.switchover(result.getMchId()); this.switchover(result.getMchId(), result.getAppid());
} }
} }
@ -347,7 +352,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
*/ */
private boolean verifyNotifySign(SignatureHeader header, String data) throws WxSignTestException { private boolean verifyNotifySign(SignatureHeader header, String data) throws WxSignTestException {
String wxPaySign = header.getSignature(); String wxPaySign = header.getSignature();
if(wxPaySign.startsWith("WECHATPAY/SIGNTEST/")){ if (wxPaySign.startsWith("WECHATPAY/SIGNTEST/")) {
throw new WxSignTestException("微信支付签名探测流量"); throw new WxSignTestException("微信支付签名探测流量");
} }
String beforeSign = String.format("%s\n%s\n%s\n", String beforeSign = String.format("%s\n%s\n%s\n",
@ -421,7 +426,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
WxPayRefundNotifyResult result; WxPayRefundNotifyResult result;
if (XmlConfig.fastMode) { if (XmlConfig.fastMode) {
result = BaseWxPayResult.fromXML(xmlData, WxPayRefundNotifyResult.class); result = BaseWxPayResult.fromXML(xmlData, WxPayRefundNotifyResult.class);
this.switchover(result.getMchId()); this.switchover(result.getMchId(), result.getAppid());
result.decryptReqInfo(this.getConfig().getMchKey()); result.decryptReqInfo(this.getConfig().getMchKey());
} else { } else {
result = WxPayRefundNotifyResult.fromXML(xmlData, this.getConfig().getMchKey()); result = WxPayRefundNotifyResult.fromXML(xmlData, this.getConfig().getMchKey());
@ -458,7 +463,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
try { try {
log.debug("扫码支付回调通知请求参数:{}", xmlData); log.debug("扫码支付回调通知请求参数:{}", xmlData);
WxScanPayNotifyResult result = BaseWxPayResult.fromXML(xmlData, WxScanPayNotifyResult.class); WxScanPayNotifyResult result = BaseWxPayResult.fromXML(xmlData, WxScanPayNotifyResult.class);
this.switchover(result.getMchId()); this.switchover(result.getMchId(), result.getAppid());
log.debug("扫码支付回调通知解析后的对象:{}", result); log.debug("扫码支付回调通知解析后的对象:{}", result);
result.checkResult(this, this.getConfig().getSignType(), false); result.checkResult(this, this.getConfig().getSignType(), false);
return result; return result;
@ -1306,7 +1311,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
@Override @Override
public WxPayFaceAuthInfoResult getWxPayFaceAuthInfo(WxPayFaceAuthInfoRequest request) throws WxPayException { public WxPayFaceAuthInfoResult getWxPayFaceAuthInfo(WxPayFaceAuthInfoRequest request) throws WxPayException {
if (StringUtils.isEmpty(request.getSignType())) { if (StringUtils.isEmpty(request.getSignType())) {
request.setSignType(WxPayConstants.SignType.MD5); request.setSignType(SignType.MD5);
} }
request.checkAndSign(this.getConfig()); request.checkAndSign(this.getConfig());