全球支付-空中云汇(airwallex)

本文主要以前后端分离下单为内容对airwallex进行介绍

空中云汇api地址

https://www.airwallex.com/docs/api
在这里插入图片描述

在这里插入图片描述

接口解析

接口名称接口解析
商户token认证/api/v1/authentication/login根据 x-api-key 以及x-client-id 获取后续请求使用的商户token
获取支付方式/api/v1/pa/config/payment_method_types根据token,获取当前商户支持的支付方法
获取银行logo/api/v1/pa/config/banks获取银行logo
创建支付用户/api/v1/pa/customers/create这个用户是你要做的系统和空中云汇做一个关联,后续绑定银行卡等信息都会用到
获取支付用户临时token/api/v1/pa/customers/{id}/generate_client_secret后续下单后确认支付等需要支付用户的token
获取全部同意书/api/v1/pa/payment_consents支付同意书里包含支付方式以及绑定的银行卡信息
删除同意书/api/v1/pa/payment_consents/{id}/disable删除之前的同意书,删除之前绑定的银行卡信息
支付下单/api/v1/pa/payment_intents/create拉起后端支付,返回前端支付信息
查询支付/api/v1/pa/payment_intents/{id}查询支付信息
确认支付/api/v1/pa/payment_intents/{id}/confirm一般这个接口是需要购买native api才能提供,这个接口可以代替前端拉起支付接口
取消支付/api/v1/pa/payment_intents/{id}/cancel取消支付
发起退款/api/v1/pa/refunds/create根据之前下单接口发起退款
查询退款/api/v1/pa/refunds/{id}查询退款
查询所有退款/api/v1/pa/refunds查询所有退款

获取配置信息

1、登录空中云汇

地址
https://www.airwallex.com/app/login?region=cn
在这里插入图片描述

2、在账户-开发者中找到配置的API秘钥,获取到 CLIENT ID 以及 API 密钥 ,这两个信息可以token登录接口中使用

在这里插入图片描述
例如:

## 请求
curl --request POST \
--url 'https://api-demo.airwallex.com/api/v1/authentication/login' \
--header 'Content-Type: application/json' \
--header 'x-api-key: 72c0a50d840626050145ccf72b733e32f31bb21323d493f9d00290b37676a138bcdf1d6415d9f08aad117450e23a4f4f' \
--header 'x-client-id: 5f1vUssbSnq45temBX6CnB'
## 响应
{
  "expires_at": "2021-10-26T06:38:13+0000",
  "token": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0b20iLCJyb2xlcyI6WyJ1c2VyIl0sImlhdCI6MTQ4ODQxNTI1NywiZXhwIjoxNDg4NDE1MjY3fQ.UHqau03y5kEk5lFbTp7J4a-U6LXsfxIVNEsux85hj-Q"
}

3、配置webhook

根据自己情况配置需要的事件,建议至少将 交易订单已取消已成功 勾选
(1)按照空中云汇文档信息提示,webhook可以配置两个,而且必须要是 https 格式请求
(2)空中云汇webhook对请求响应时间有要求,业务逻辑最好是异步执行,先给返回响应状态
(3)webhook发送失败后间隔 5分钟,1小时,4小时,8小时,12小时,12小时 共重发6次,发送成功则终止重发
在这里插入图片描述

在Java中集成空中云汇并拉起支付,仅供参考,根据自己业务实际来进行

1、封装springboot 对象缓存类

@Component
public class ContextHolder implements ApplicationContextAware{
	
	private static ApplicationContext applicationContext = null;
	
	@Override
	public void setApplicationContext(ApplicationContext arg0) throws BeansException {
		if(ContextHolder.applicationContext == null){
			ContextHolder.applicationContext  = arg0;
	    }
		System.out.println("========ApplicationContext配置成功,ContextHolder.getAppContext()获取applicationContext对象,applicationContext="+ ContextHolder.applicationContext+"========");
	}
	
	//获取applicationContext
    public static ApplicationContext getApplicationContext() {
       return applicationContext;
    }
    //通过name获取 Bean.
    public static Object getBean(String name){
       return getApplicationContext().getBean(name);
    }
    //通过class获取Bean.
    public static <T> T getBean(Class<T> clazz){
       return getApplicationContext().getBean(clazz);
    }
    //通过name,以及Clazz返回指定的Bean
    public static <T> T getBean(String name,Class<T> clazz){
       return getApplicationContext().getBean(name, clazz);
    }

}

2、创建网络请求工具

public class HttpClientUtil {
    protected static Logger logger = LoggerFactory.getLogger(HttpClientUtil.class);


	/**
     * 空中云汇支付请求
     * @param url 请求url
     * @param obj 请求body
     * @param operatorId 商户id
     * @return
     * @throws Exception
     */
    public static String sendAirwallexHttpPost(String url, Object obj,String operatorId) throws Exception {
        HttpPost post = new HttpPost(url);
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(30000).setConnectionRequestTimeout(30000)
                .setSocketTimeout(30000).build();
        post.setConfig(requestConfig);
        post.addHeader("Content-Type", "application/json;charset=UTF-8");
        post.setHeader("Accept", "application/json");
        if (StringUtils.isNotBlank(operatorId)) {
            AirwallexPaySourceServiceImpl paySourceService = ContextHolder.getBean(AirwallexPaySourceServiceImpl.class);
            String airwallexToken = paySourceService.getAirwallexToken(operatorId);
            post.setHeader("Authorization",airwallexToken);
        }
        CloseableHttpAsyncClient httpClient = null;
        try {
            String json = GsonUtil.toJson(obj);
            logger.info("sendAirwallexHttpPost before operatorId :{} url :{}  body :{}",operatorId,url,json);
            StringEntity entity = new StringEntity(json,"UTF-8");//解决中文乱码问题
            entity.setContentEncoding("UTF-8");
            entity.setContentType("application/json");
            post.setEntity(entity);
            SSLContext ctx = SSLContext.getInstance("TLS");
            X509TrustManager tm = new X509TrustManager() {
                public void checkClientTrusted(X509Certificate[] xcs, String string) {
                }
                public void checkServerTrusted(X509Certificate[] xcs, String string) {
                }
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            };
            ctx.init(null, new TrustManager[] { tm }, null);

            SSLIOSessionStrategy sslSessionStrategy = new SSLIOSessionStrategy(ctx, new String[] { "TLSv1","TLSv1.1","TLSv1.2" }, null,
                    SSLIOSessionStrategy.getDefaultHostnameVerifier());

            httpClient = HttpAsyncClients.custom().setSSLStrategy(sslSessionStrategy).build();
            httpClient.start();
            Future<HttpResponse> future = httpClient.execute(post, null);
            HttpResponse response = future.get();

            StringBuffer sb = new StringBuffer();
            BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent(),"UTF-8"));
            String line;
            while ((line = rd.readLine()) != null) {
                sb.append(line);
            }
            String body = sb.toString();
            logger.info("sendAirwallexHttpPost after operatorId :{} url :{}  response :{}",operatorId,url,body);
            return body;
        } catch (Exception e) {
            logger.error(e.getMessage(),e.getStackTrace());
            throw e;
        } finally {
            if (httpClient != null) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    logger.error(e.getMessage());
                }
            }
        }
    }
	 /**
     * 空中云汇支付请求
     * @param url 请求url
     * @param obj 请求body
     * @param operatorId 商户id
     * @return
     * @throws Exception
     */
    public static String sendAirwallexHttpPostLogin(String url,Map<String,String> header) throws Exception {
        HttpPost post = new HttpPost(url);
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(30000).setConnectionRequestTimeout(30000)
                .setSocketTimeout(30000).build();
        post.setConfig(requestConfig);
        post.addHeader("Content-Type", "application/json;charset=UTF-8");
        post.setHeader("Accept", "application/json");
        if (!CollectionUtils.isEmpty(header)) {
            for (Entry<String, String> stringStringEntry : header.entrySet()) {
                post.setHeader(stringStringEntry.getKey(), stringStringEntry.getValue());
            }
        }
        CloseableHttpAsyncClient httpClient = null;
        try {
            SSLContext ctx = SSLContext.getInstance("TLS");
            X509TrustManager tm = new X509TrustManager() {
                public void checkClientTrusted(X509Certificate[] xcs, String string) {
                }
                public void checkServerTrusted(X509Certificate[] xcs, String string) {
                }
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            };
            ctx.init(null, new TrustManager[] { tm }, null);


            SSLIOSessionStrategy sslSessionStrategy = new SSLIOSessionStrategy(ctx, new String[] { "TLSv1","TLSv1.1","TLSv1.2" }, null,
                    SSLIOSessionStrategy.getDefaultHostnameVerifier());

            httpClient = HttpAsyncClients.custom().setSSLStrategy(sslSessionStrategy).build();
            httpClient.start();
            Future<HttpResponse> future = httpClient.execute(post, null);
            HttpResponse response = future.get();

            StringBuffer sb = new StringBuffer();
            BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent(),"UTF-8"));
            String line;
            while ((line = rd.readLine()) != null) {
                sb.append(line);
            }
            String body = sb.toString();
            logger.info("sendAirwallexHttpPostLogin  url :{}  header :{}",url,GsonUtil.toJson(header));
            return body;
        } catch (Exception e) {
            logger.error(e.getMessage(),e.getStackTrace());
            throw e;
        } finally {
            if (httpClient != null) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    logger.error(e.getMessage());
                }
            }
        }
    }

   
    /**
     * 空中云汇支付请求
     * 发送信息到服务端 GET方式
     * @param url
     * @return
     * @throws Exception
     */
    public static String sendAirwallexHttpGet(String url,String operatorId) throws Exception {
        logger.info("sendAirwallexHttpGet before operatorId :{} url :{}  ",operatorId,url);
        HttpGet httpGet = new HttpGet(url);
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(30000).setConnectionRequestTimeout(30000)
                .setSocketTimeout(30000).build();
        httpGet.setConfig(requestConfig);
        httpGet.addHeader("Content-Type", "application/json;charset=UTF-8");
        httpGet.setHeader("Accept", "application/json");
        if (StringUtils.isNotBlank(operatorId)) {
            AirwallexPaySourceServiceImpl paySourceService = ContextHolder.getBean(AirwallexPaySourceServiceImpl.class);
            String airwallexToken = paySourceService.getAirwallexToken(operatorId);
            httpGet.setHeader("Authorization",airwallexToken);
        }
        CloseableHttpAsyncClient httpClient = null;
        try {
            SSLContext ctx = SSLContext.getInstance("TLS");
            X509TrustManager tm = new X509TrustManager() {
                public void checkClientTrusted(X509Certificate[] xcs, String string) {
                }
                public void checkServerTrusted(X509Certificate[] xcs, String string) {
                }
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            };
            ctx.init(null, new TrustManager[] { tm }, null);

            SSLIOSessionStrategy sslSessionStrategy = new SSLIOSessionStrategy(ctx, new String[] { "TLSv1","TLSv1.1","TLSv1.2" }, null,
                    SSLIOSessionStrategy.getDefaultHostnameVerifier());

            httpClient = HttpAsyncClients.custom().setSSLStrategy(sslSessionStrategy).build();
            httpClient.start();
            Future<HttpResponse> future = httpClient.execute(httpGet, null);
            HttpResponse response = future.get();

            StringBuffer sb = new StringBuffer();
            BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent(),"UTF-8"));
            String line;
            while ((line = rd.readLine()) != null) {
                sb.append(line);
            }
            String body = sb.toString();
            logger.info("sendAirwallexHttpGet after operatorId :{} response :{}  ",operatorId,body);
            return body;
        } catch (Exception e) {
            logger.error(e.getMessage(),e.getStackTrace());
            throw e;
        } finally {
            if (httpClient != null) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    logger.error(e.getMessage());
                }
            }
        }
    }
    
}

3、 拉起各个接口请求,以下接口简写,请根据自己实际情况进行调整

(1)使用商户的 CLIENT ID 和 API 密钥 获取token

	public String getAirwallexToken(String operatorId) {
		//从redis中获取token ,token默认设置有效期20分钟过期
        String token = redisTemplate.opsForValue()....省略;
        if (StringUtils.isNotBlank(token)) {
            return token;
        }
        
        String clientId = "";
        String apiKey = "";
        Map<String,String> headerMap = new HashMap<>();
        headerMap.put("x-client-id",clientId);
        headerMap.put("x-api-key",apiKey);
        String result = null;
        try {
            //获取token信息
            result = HttpClientUtil.sendAirwallexHttpPostLogin(String.format("%s%s", "https://api-demo.airwallex.com", "/api/v1/authentication/login"), headerMap);
        }catch (Exception e) {
            log.error("sendAirwallexHttpPost getToken error : "+operatorId+e.getMessage(),e);
        }
        if (StringUtils.isNotBlank(result)) {
            //省略。。。。。
            //加入到redis中,过期时间20分钟
            
        }
        return token;
    }

(2) 创建用户

		Map<String,Object> params = new HashMap<>();
        params.put("request_id",request_id);
        params.put("merchant_customer_id",merchant_customer_id);
        params.put("first_name",first_name);
        params.put("last_name",last_name);
        params.put("email",email);

        String result = null;
        try {
            result = HttpClientUtil.sendAirwallexHttpPost(String.format("%s%s", "https://api-demo.airwallex.com", "/api/v1/pa/customers/create"), params,operatorId);
        }catch (Exception e) {
            log.error("sendAirwallexHttpPost error : "+operatorId+e.getMessage(),e);
        }

(3)下单支付接口

		Map<String,Object> params = new HashMap<>();
        params.put("request_id",request_id);
        params.put("merchant_order_id",merchant_order_id);
        params.put("amount",amount);
        params.put("currency",currency);

        params.put("customer_id",customer_id);

        //构建额外配置参数
        Map<String,Object> metadata = new HashMap<>();
        metadata.put("accountId",accountId);
        params.put("metadata",metadata);

        String result = null;
        try {
            result = HttpClientUtil.sendAirwallexHttpPost(String.format("%s%s", "https://api-demo.airwallex.com", "/api/v1/pa/payment_intents/create"), params,operatorId);
        }catch (Exception e) {
            log.error("sendAirwallexHttpPost error : "+operatorId+e.getMessage(),e);
        }

前端拉起空中云汇支付

在这里插入图片描述

参考网址
https://www.airwallex.com/docs/payments__embedded-elements

在这里插入图片描述
git地址
https://github.com/airwallex/airwallex-payment-demo/tree/master/docs
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值