欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring Boot整合海外第三方支付Coda Payments

程序员文章站 2024-02-26 13:06:34
...

 

前言

        由于公司项目需要对接海外支付,本次对接的是Coda Payments,该支付集成还需先开通账号才能看文档,比较麻烦。为方便大家后续集成,在此做个简单记录。


 

一、Coda Payment是什么?

        新加坡在线支付平台Coda Payments。

        官网:https://www.codapayments.com/

        控制台:https://online.codapayments.com/merchant/home.action

Spring Boot整合海外第三方支付Coda Payments

Spring Boot整合海外第三方支付Coda Payments

二、使用步骤

1.配置yml

# Coda Payments
coda-payment:
  api-key: <输入你的商户**>
  # 根据集成文档上修改你要的国家代码,当前值为印度
  country: 356
  # 根据集成文档上修改你要的货币代码,当前值为印度
  currency: 356
  # 根据集成文档上修改你要的支付类型,当前值对应paytm-wallet
  pay-type: 390
  # 此处是沙箱环境的,生产环境需要替换为:https://airtime.codapayments.com/airtime/api/restful/v1.0/Payment
  base-url: https://sandbox.codapayments.com/airtime/api/restful/v1.0/Payment
  # 付款初始化URL(获取txtId)
  payment-url: ${coda-payment.base-url}/init
  # 查询支付结果URL
  inquiry-payment-result-url: ${coda-payment.base-url}/inquiryPaymentResult
  # APP端支付页面URL,生产环境需要替换为:https://airtime.codapayments.com/airtime/begin?type=3&txn_id=%d&browser_type=mobile-web
  # 如果是Web端,则去除URL中的browser_type=mobile-web即可
  front-end-payment-page-url: https://sandbox.codapayments.com/airtime/begin?type=3&txn_id=%d&browser_type=mobile-web

2.对应的Config

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

/**
 * Coda Payment config
 *
 * @author Jiahai
 */
@Data
@Configuration
@ConfigurationProperties(prefix = "coda-payment")
public class CodaPaymentConfig {
    /**
     * 商户key
     */
    private String apiKey;

    /**
     * 国家编号
     */
    private Short country;

    private Short currency;
    private Short payType;

    /**
     * 付款初始化URL(获取txtId)
     */
    private String paymentUrl;

    /**
     * 查询支付结果URL
     */
    private String inquiryPaymentResultUrl;

    /**
     * 前端支付页面URL
     */
    private String frontEndPaymentPageUrl;
}

3.主要关注点:初始化交易ID、支付成功回调、根据交易ID查询订单支付情况。

(请求均为Post JSON)

例如,初始化交易ID

Spring Boot整合海外第三方支付Coda Payments

package com.wjh.codapayment.service;

import com.wjh.codapayment.config.CodaPaymentConfig;
import com.wjh.codapayment.request.*;
import com.wjh.codapayment.response.InitResultVO;
import com.wjh.codapayment.response.PaymentResultVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * CodaPayments 业务层
 *
 * @author Jiahai
 */
@Service
public class CodaPaymentsService {
    /**
     * 暂定:Coda Payments 充值"Q币"的itemInfo的code为 1
     */
    private String itemInfoRechargeCode = "1";

    /**
     * 暂定:Coda Payments 充值"Q币"的itemInfo的name为 Q coin
     */
    private String itemInfoRechargeName = "Q coin";

    /**
     * 固定值
     */
    private String profileEntryMapKeyUserId = "user_id";

    /**
     * 暂定:profile entry中 need_mno_id 为 yes
     */
    private final EntryMap NEED_MNO_ID_ENTRY_MAP = new EntryMap("need_mno_id", "yes");

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private CodaPaymentConfig codaPaymentConfig;

    /**
     * 初始化交易,生成 txtId
     *
     * @param orderId 系统订单ID
     * @return
     */
    public Long init(Long orderId) {
        InitRequest initRequest = this.initInitRequest(orderId);

        List<ItemInfo> itemInfoList = new ArrayList<>();
        itemInfoList.add(new ItemInfo("1", "itemInfoRechargeName", 169.00d, Short.parseShort("1")));
        initRequest.setItems(itemInfoList)
                .setProfile(new Profile()
                        .setEntry(Arrays.asList(new EntryMap(profileEntryMapKeyUserId, "1"), NEED_MNO_ID_ENTRY_MAP)));

        InitRequestVO initRequestVO = new InitRequestVO(initRequest);

        try {
            InitResultVO initResultVO = restTemplate.postForObject(codaPaymentConfig.getPaymentUrl(), initRequestVO, InitResultVO.class);
            if (initResultVO != null && initRequestVO.getInitRequest() != null && initResultVO.getInitResult().getResultCode() == 0) {
                return initResultVO.getInitResult().getTxnId();
            }
        } catch (RestClientException e) {
            System.out.println("失败");
            e.printStackTrace();
        }
        throw new IllegalArgumentException("失败");
    }

    /**
     * 用户充值-回调
     *
     * @param httpServletRequest
     * @return
     */
    public String callbackForRecharge(HttpServletRequest httpServletRequest) {
        /**
         * TxnId - 5995344541934063522
         * OrderId - 1369124976459808
         * TotalPrice - 169.00
         * PaymentType - 390
         * ResultCode - 0
         * Checksum - 13facafd62479a8dcbb4a35e4d668657
         */

        RechargeRequest rechargeRequest = new RechargeRequest()
                .setTxnId(Long.valueOf(httpServletRequest.getParameter("TxnId")))
                .setOrderId(httpServletRequest.getParameter("OrderId"))
                .setResultCode(Integer.valueOf(httpServletRequest.getParameter("ResultCode")))
                .setTotalPrice(Float.valueOf(httpServletRequest.getParameter("TotalPrice")))
                .setPaymentType(Integer.valueOf(httpServletRequest.getParameter("PaymentType")))
                .setChecksum(httpServletRequest.getParameter("Checksum"));

        boolean flag = this.validate(rechargeRequest);
        if (flag) {
            // 校验通过
            // 1、查询数据库订单记录
            // -> 订单存在 && 支付平台是 Coda Payments
            // -> 订单处于“待支付”?
            // -> Coda Payments端 成功?(httpServletRequest中ResultCode为0则表示成功)

            // 支付成功,需要返回下面字符串,Coda Payments规定0表示成功。可以自定义返回别的状态码用于表示失败。
            return "ResultCode=0";
        } else {
            return "ResultCode=-1";
        }
    }

    /**
     * 根据txnId,查询支付信息
     *
     * @param txnId
     */
    public void inquiryPaymentResult(Long txnId) {
        // 初始化查询对象
        InquiryPaymentRequest inquiryPaymentRequest = new InquiryPaymentRequest()
                .setApikey(codaPaymentConfig.getApiKey())
                .setTxnId(txnId);
        InquiryPaymentRequestVO inquiryPaymentRequestVO = new InquiryPaymentRequestVO(inquiryPaymentRequest);
        // 查询
        try {
            PaymentResultVO paymentResultVO = restTemplate.postForObject(codaPaymentConfig.getInquiryPaymentResultUrl(), inquiryPaymentRequestVO, PaymentResultVO.class);
            if (paymentResultVO != null && paymentResultVO.getPaymentResult() != null) {
                if (paymentResultVO.getPaymentResult().getResultCode() == 0) {
                    // 成功 TODO
                } else {
                    // 失败 TODO
                }
            }
        } catch (RestClientException e) {
            System.out.println("失败");
            e.printStackTrace();
        }
    }

    /**
     * 初始化InitRequest
     *
     * @param orderId 订单ID
     * @return
     */
    private InitRequest initInitRequest(Long orderId) {
        return new InitRequest()
                .setApiKey(codaPaymentConfig.getApiKey())
                .setOrderId(orderId + "")
                .setCountry(codaPaymentConfig.getCountry())
                .setCurrency(codaPaymentConfig.getCurrency())
                .setPayType(codaPaymentConfig.getPayType());
    }

    /**
     * 回调校验
     *
     * @param rechargeRequest
     * @return
     */
    private boolean validate(RechargeRequest rechargeRequest) {
        if (rechargeRequest == null) {
            return false;
        }
        String values = rechargeRequest.getTxnId() + codaPaymentConfig.getApiKey() + rechargeRequest.getOrderId() + rechargeRequest.getResultCode();
        // MD5 校验
        return Objects.equals(rechargeRequest.getChecksum(), DigestUtils.md5DigestAsHex(values.getBytes()));
    }
}

4、项目结构

        request包与response包中的类较多,其实都是根据请求JSON而定制,相信大家自己看官方文档时就可轻松完成。

Spring Boot整合海外第三方支付Coda Payments

5、测试环境效果演示

Spring Boot整合海外第三方支付Coda PaymentsSpring Boot整合海外第三方支付Coda PaymentsSpring Boot整合海外第三方支付Coda PaymentsSpring Boot整合海外第三方支付Coda PaymentsSpring Boot整合海外第三方支付Coda Payments


总结
       对接该支付,需要先有账号才可看文档,这个不像国内微信支付这么方便了。

       还有,支付成功后,“成功页”或“失败页”需要自己写,比如success.html和fail.html。重定向URL需要“邮件”通知Coda  Payments人员去配置!!

       支付的回调URL也是需要“邮件”通知他们去配置!!