如何實(shí)現(xiàn)一個項(xiàng)目配置多個商戶信息付款給對應(yīng)商戶
最近在對接支付寶支付時(shí),遇到了一個問題
用戶在付款時(shí)臣樱,需要直接付款到指定支付寶賬戶。
這個需求也無可厚非,就像我們公司有四個分公司框沟,分別在北京藏古、上海等地,如果錢只能到總公司的賬戶上忍燥,那在財(cái)務(wù)結(jié)算的時(shí)候就很麻煩拧晕。
簡單說一下問題背景:
公司準(zhǔn)備上線一個商城應(yīng)用,有分公司和服務(wù)商的概念梅垄,意思就是收錢的不是一個人厂捞。
前一陣子,螞蟻金服投了一大筆錢队丝,也算是達(dá)成了合作靡馁,所以在第三方支付中首選了支付寶,場景是手機(jī)網(wǎng)站支付机久,問題就在這出現(xiàn)了臭墨。目前支付寶只在當(dāng)面付中支持配置多個收款賬戶,也是在社區(qū)里逛了一陣子才知道這個信息的膘盖。
[圖片上傳失敗...(image-88cfb5-1540283092156)]
[圖片上傳失敗...(image-7f4e27-1540283092156)]
螞蟻金服開發(fā)者社區(qū)原貼:如何實(shí)現(xiàn)一個項(xiàng)目配置多個商戶信息付款給對應(yīng)商戶
上面的帖子明確說明了目前實(shí)現(xiàn)的兩種方式胧弛,很明顯方案二看起來比較優(yōu)雅,也比較好實(shí)現(xiàn)侠畔,但是很抱歉结缚,手機(jī)網(wǎng)站支付不支持方案二。
ps:判斷是否支持方案二的方法就是去看它的文檔软棺,如果請求參數(shù)中有app_auth_token這個參數(shù)就是支持方案二的红竭。
為了證實(shí)這個蛋疼的消息,我又專門發(fā)了一個帖子確認(rèn)了一遍
管理員明確的回復(fù)了我喘落,只能用方案一德崭,并且要申請N個應(yīng)用,并全部上線揖盘。
Google了一下眉厨,沒搜到用這種方式實(shí)現(xiàn)的代碼,只能自己寫了兽狭。憾股。
支付寶最終是根據(jù)請求過來的appid來判斷哪一個商戶收款(也就是請求是誰的appid就收款到誰的賬號下)
所以我申請了四個應(yīng)用。箕慧。服球。。
先定一個接口;
public interface AlipayClientConfig {
/**
* 網(wǎng)關(guān).
*/
String getGatewayUrl();
/**
* appid.
*/
String getAppId();
/**
* 私鑰.
*/
String getAppPrivateKey();
/**
* 格式 默認(rèn)json.
*/
String getFormat();
/**
* 編碼 默認(rèn)utf-8.
*/
String getCharset();
/**
* 支付寶公鑰.
*/
String getAlipayPublicKey();
/**
* 簽名方式.
*/
String getSignType();
}
在定義一個抽象類實(shí)現(xiàn)接口;
@Getter
@Setter
public class AlipayAbstractClientConfig implements AlipayClientConfig {
/**
* 網(wǎng)關(guān).
*/
private String gatewayUrl;
/**
* appid.
*/
private String appId;
/**
* 私鑰.
*/
private String appPrivateKey;
/**
* 格式 默認(rèn)json.
*/
private String format;
/**
* 編碼 默認(rèn)utf-8.
*/
private String charset;
/**
* 支付寶公鑰.
*/
private String alipayPublicKey;
/**
* 簽名方式.
*/
private String signType;
}
然后是四個配置文件繼承抽象類;
@Configuration(AlipayConstant.BEIJING_CLIENT)
@ConfigurationProperties(prefix = "alipay.apenapi.beijing")
@Getter
@Setter
public class AlipayBeiJingClientConfig extends AlipayAbstractClientConfig {
}
@Configuration(AlipayConstant.NANJING_CLIENT)
@ConfigurationProperties(prefix = "alipay.apenapi.nanjing")
@Getter
@Setter
public class AlipayNanJingClientConfig extends AlipayAbstractClientConfig {
}
@Configuration(AlipayConstant.SHANGHAI_CLIENT)
@ConfigurationProperties(prefix = "alipay.apenapi.shanghai")
@Getter
@Setter
public class AlipayShangHaiClientConfig extends AlipayAbstractClientConfig {
}
@Configuration(AlipayConstant.TIANJIN_CLIENT)
@ConfigurationProperties(prefix = "alipay.apenapi.tianjin")
@Getter
@Setter
public class AlipayTianJinClientConfig extends AlipayAbstractClientConfig {
}
注解的常量信息颠焦;
public interface AlipayConstant {
String BEIJING_CLIENT = "BJ";
String TIANJIN_CLIENT = "TJ";
String NANJING_CLIENT = "NJ";
String SHANGHAI_CLIENT = "SH";
}
再貼一下配置文件信息斩熊;
alipay:
apenapi:
tianjin:
gateway_url: https://openapi.alipay.com/gateway.do
app_id: 2018*********
app_private_key: KubiKtPbIoMLITLRMKTu9MwIwE8lC9Grg5
6c/00rsypY/b8SQh8ydYsEPt098JYAEhS6HvLQNz6W5XvCZNeAcv307kj3RYql2W
Xntkh9Rr0s/cEc1WnHmBeUF3
alipay_public_key: MIIBIjANBgkqhkistdzwIDAQAB
format: json
charset: utf-8
sign_type: RSA2
beijing:
gateway_url: https://openapi.alipay.com/gateway.do
app_id: 2018**********
app_private_key: JTj9Lz6G4W3RMO8QCCK8XYWdkEH5H5I
alipay_public_key: MIIBIjANBgB
format: json
charset: utf-8
sign_type: RSA2
shanghai:
gateway_url: https://openapi.alipay.com/gateway.do
app_id: 2018********
app_private_key: MIIEvAIBADANBgcpUyx/WxcdhuAYmF3Di
alipay_public_key: MIIBIjANBgkqhkiG9w0
format: json
charset: utf-8
sign_type: RSA2
nanjing:
gateway_url: https://openapi.alipay.com/gateway.do
app_id: 20181********
app_private_key: MIIEvgIBA
alipay_public_key: MIIBIjANBgk
format: json
charset: utf-8
sign_type: RSA2
在service層調(diào)用時(shí),只要動態(tài)的獲取不同的配置文件伐庭,即可初始化不同的AlipayClient粉渠,向支付寶發(fā)起請求分冈;
@Service
@Slf4j
@Transactional(readOnly = true)
public class AlipayServiceImpl implements AlipayService {
@Autowired
private AlipayDetailConfig alipayDetailConfig;
@Autowired
private Map<String, AlipayClientConfig> configMap;
@Override
public AlipayTradeWapPayResponse wapPay(AlipayWayPayRequest request) throws AlipayApiException {
String method = "wapPay";
log.debug("Enter {}", method);
log.debug("WapPay form info : orderCode:【{}】 、orderTotalAmount:【{}】 "
+ "霸株、orderSubject:【{}】 雕沉、orderDescription:【{}】 、quitUrl:【{}】 去件、companyCode:【{}】坡椒。",
request.getOrderCode(), request.getOrderTotalAmount(), request.getOrderSubject(),
request.getOrderDescription(), request.getQuitUrl(), request.getCompanyCode()
);
AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();
alipayRequest.setNotifyUrl(alipayDetailConfig.getNotifyUrl());
alipayRequest.setReturnUrl(alipayDetailConfig.getReturnUrl());
AlipayTradeWapPayModel payModel = new AlipayTradeWapPayModel();
//商戶訂單號
payModel.setOutTradeNo(request.getOrderCode());
//訂單總金額,單位為元尤溜,精確到小數(shù)點(diǎn)后兩位倔叼,取值范圍[0.01,100000000]
payModel.setTotalAmount(request.getOrderTotalAmount().toString());
//訂單標(biāo)題
payModel.setSubject(request.getOrderSubject());
//訂單描述
payModel.setBody(request.getOrderDescription());
//用戶付款中途退出返回商戶網(wǎng)站的地址
payModel.setQuitUrl(request.getQuitUrl());
//商品主類型 虛擬類商品不支持使用花唄渠道
payModel.setGoodsType(AlipayConstant.VIRTUAL_GOODS_TYPE);
//該筆訂單允許的最晚付款時(shí)間,逾期將關(guān)閉交易
payModel.setTimeoutExpress(alipayDetailConfig.getTimeoutExpress());
//銷售產(chǎn)品碼宫莱,與支付寶簽約的產(chǎn)品碼名稱
payModel.setProductCode(AlipayConstant.WAP_PAY_PRODUCT_CODE);
//設(shè)置回傳參數(shù)
payModel.setPassbackParams(request.getCompanyCode());
alipayRequest.setBizModel(payModel);
//返回支付信息
AlipayClient alipayClient = getAlipayClient(request.getCompanyCode());
log.debug("Exit {}", method);
return alipayClient.pageExecute(alipayRequest);
}
/**
* 根據(jù)分公司code返回對應(yīng)的client.
*
* @param companyCode 分公司code.
*/
private AlipayClient getAlipayClient(String companyCode) {
AlipayClientConfig config = configMap.get(companyCode);
return new DefaultAlipayClient(
config.getGatewayUrl(),
config.getAppId(),
config.getAppPrivateKey(),
config.getFormat(),
config.getCharset(),
config.getAlipayPublicKey(),
config.getSignType()
);
}
至此缀雳,算是比較優(yōu)雅的實(shí)現(xiàn)了付款給指定商戶賬號。
后記:微信支付早就解決了這個問題 梢睛,也因此在社區(qū)里肥印,一大批吐槽者瘋狂吐槽支付寶的設(shè)計(jì)思路和實(shí)現(xiàn)方式。