Alipay(支付宝支付) 如何实现一个项目配置多个商户信息付款给对应商户

如何实现一个项目配置多个商户信息付款给对应商户

最近在对接支付宝支付时,遇到了一个问题

用户在付款时,需要直接付款到指定支付宝账户。

这个需求也无可厚非,就像我们公司有四个分公司,分别在北京、上海等地,如果钱只能到总公司的账户上,那在财务结算的时候就很麻烦。

简单说一下问题背景:

公司准备上线一个商城应用,有分公司和服务商的概念,意思就是收钱的不是一个人。

前一阵子,蚂蚁金服投了一大笔钱,也算是达成了合作,所以在第三方支付中首选了支付宝,场景是手机网站支付,问题就在这出现了。目前支付宝只在当面付中支持配置多个收款账户,也是在社区里逛了一阵子才知道这个信息的。

[图片上传失败...(image-88cfb5-1540283092156)]
[图片上传失败...(image-7f4e27-1540283092156)]
蚂蚁金服开发者社区原贴:如何实现一个项目配置多个商户信息付款给对应商户

上面的帖子明确说明了目前实现的两种方式,很明显方案二看起来比较优雅,也比较好实现,但是很抱歉,手机网站支付不支持方案二。

ps:判断是否支持方案二的方法就是去看它的文档,如果请求参数中有app_auth_token这个参数就是支持方案二的。

为了证实这个蛋疼的消息,我又专门发了一个帖子确认了一遍

手机网站支付遇到了一些问题

管理员明确的回复了我,只能用方案一,并且要申请N个应用,并全部上线。

Google了一下,没搜到用这种方式实现的代码,只能自己写了。。

支付宝最终是根据请求过来的appid来判断哪一个商户收款(也就是请求是谁的appid就收款到谁的账号下)

所以我申请了四个应用。。。。

先定一个接口;

public interface AlipayClientConfig {
  /**
   * 网关.
   */
  String getGatewayUrl();
  /**
   * appid.
   */
  String getAppId();
  /**
   * 私钥.
   */
  String getAppPrivateKey();
  /**
   * 格式 默认json.
   */
  String getFormat();
  /**
   * 编码 默认utf-8.
   */
  String getCharset();
  /**
   * 支付宝公钥.
   */
  String getAlipayPublicKey();
  /**
   * 签名方式.
   */
  String getSignType();
}

在定义一个抽象类实现接口;

@Getter
@Setter
public class AlipayAbstractClientConfig implements AlipayClientConfig {

  /**
   * 网关.
   */
  private String gatewayUrl;
  /**
   * appid.
   */
  private String appId;
  /**
   * 私钥.
   */
  private String appPrivateKey;
  /**
   * 格式 默认json.
   */
  private String format;
  /**
   * 编码 默认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层调用时,只要动态的获取不同的配置文件,即可初始化不同的AlipayClient,向支付宝发起请求;

@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());
    //订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000]
    payModel.setTotalAmount(request.getOrderTotalAmount().toString());
    //订单标题
    payModel.setSubject(request.getOrderSubject());
    //订单描述
    payModel.setBody(request.getOrderDescription());
    //用户付款中途退出返回商户网站的地址
    payModel.setQuitUrl(request.getQuitUrl());
    //商品主类型  虚拟类商品不支持使用花呗渠道
    payModel.setGoodsType(AlipayConstant.VIRTUAL_GOODS_TYPE);
    //该笔订单允许的最晚付款时间,逾期将关闭交易
    payModel.setTimeoutExpress(alipayDetailConfig.getTimeoutExpress());
    //销售产品码,与支付宝签约的产品码名称
    payModel.setProductCode(AlipayConstant.WAP_PAY_PRODUCT_CODE);
    //设置回传参数
    payModel.setPassbackParams(request.getCompanyCode());
    alipayRequest.setBizModel(payModel);
    //返回支付信息
    AlipayClient alipayClient = getAlipayClient(request.getCompanyCode());
    log.debug("Exit {}", method);
    return alipayClient.pageExecute(alipayRequest);
  }
  
  
    /**
   * 根据分公司code返回对应的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()
    );
  }

至此,算是比较优雅的实现了付款给指定商户账号。

后记:微信支付早就解决了这个问题 ,也因此在社区里,一大批吐槽者疯狂吐槽支付宝的设计思路和实现方式。

image
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353

推荐阅读更多精彩内容