〇. 注册VISA开发者中心账号

如果已注册过,请跳过该步,否则参考 VISA信用卡的SDK示范(Hello World) 进行注册。

一. 创建一个项目

如果已创建过,请跳过该步,否则参考 VISA信用卡的SDK示范(Hello World) 进行创建。

二、准备jks文件

如果已经有了jks文件,请跳过该步,否则参考VISA信用卡的SDK示范(Hello World)文章中的 三、Two-Way/Mutual SSL认证方式 部分生成jks文件。

三、创建VISA证书信任库(Trust Store)

1. 从VISA开发者中心下载证书

进入VISA开发者中心页面左侧的“Credentials”界面,根据下面说明或点击 这里 参考图片中标出来的红、绿、蓝框。

点击 "Sandbox Root CA" 链接下载 根证书(Root Certificate) ,将会下载一个 SBX-2024-Prod-Root.pem 这样的文件;

点击 "Sandbox Issuing CA" 链接下载 中间证书(Intermediate Certificate) ,将会下载一个 SBX-2024-Prod-Inter.pem 这样的文件;

点击 "DigiCert Global Root CA certificate" 链接下载 DigiCert根证书 ,将会下载一个 DigiCertGlobalRootCA.crt 这样的文件。

2. 创建信任库

接下来使用上面下载的3个证书创建信任库。

说明:下面命令将信任库创建在 C:\Users\ximinghui\Downloads\ 目录,且3个证书都也都位于该目录,示例密码密码为 123456, 请根据实际情况调整路径和密码。

# 创建信任库 keytool -genkey -alias dummy -keyalg RSA -keystore "C:\Users\ximinghui\Downloads\visa_truststore.jks" -storepass 123456 -keypass 123456 -dname "CN=dummy" # 删除临时条目 keytool -delete -alias dummy -keystore "C:\Users\ximinghui\Downloads\visa_truststore.jks" -storepass 123456 # 导入3个证书(DigiCert Root CA、Visa Root Certificate、Visa Intermediate Certificate) keytool -import -trustcacerts -alias digicert-root -file "C:\Users\ximinghui\Downloads\DigiCertGlobalRootCA.crt" -keystore "C:\Users\ximinghui\Downloads\visa_truststore.jks" -storepass 123456 keytool -import -trustcacerts -alias visa-root -file "C:\Users\ximinghui\Downloads\SBX-2024-Prod-Root.pem" -keystore "C:\Users\ximinghui\Downloads\visa_truststore.jks" -storepass 123456 keytool -import -trustcacerts -alias visa-intermediate -file "C:\Users\ximinghui\Downloads\SBX-2024-Prod-Inter.pem" -keystore "C:\Users\ximinghui\Downloads\visa_truststore.jks" -storepass 123456

四、测试VISA的PullFunds API

VISA开发者中心项目详情页侧边栏进入Assert页面,可以找到一些示范代码(GitHub仓库中的代码位置为https://github.com/vandofb/visa-java-sample-code/tree/master/vdp-sample-java-funds-transfer)。以下贴出的是我参考vdp-sample-java-funds-transfer写的Demo。

import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; import java.io.FileInputStream; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.security.KeyStore; import java.util.Base64; import java.util.UUID; public class Test { public static void main(String[] args) throws Exception { String username = "替换成你的username"; String password = "替换成你的password"; // 更新localTransactionDateTime时间为调用时的时间(注意时区) String requestBody = """ { "systemsTraceAuditNumber": "451001", "surcharge": "11.99", "senderPrimaryAccountNumber": "4895142232120006", "senderCurrencyCode": "USD", "senderCardExpiryDate": "2015-10", "retrievalReferenceNumber": "330000550000", "localTransactionDateTime": "2024-12-27T07:15:50", "foreignExchangeFeeTransaction": "11.99", "cavv": "0700100038238906000013405823891061668252", "cardAcceptor": { "terminalId": "ABCD1234", "name": "Visa Inc. USA-Foster City", "idCode": "ABCD1234ABCD123", "address": { "zipCode": "94404", "state": "CA", "county": "San Mateo", "country": "USA" } }, "businessApplicationId": "AA", "amount": "124.02", "acquiringBin": "408999", "acquirerCountryCode": "840" } """; // 构建 HttpClient HttpClient httpClient = HttpClient.newBuilder() .sslContext(createSSLContext()) .version(HttpClient.Version.HTTP_2) .build(); // 构建 HttpRequest HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://sandbox.api.visa.com/visadirect/fundstransfer/v1/pullfundstransactions")) .header("Authorization", "Basic " + Base64.getEncoder().encodeToString((username + ":" + password).getBytes())) .header("ex-correlation-id", UUID.randomUUID().toString().replace("-", "").substring(0, 10) + "_SC") .header("Content-Type", "application/json") .header("Accept", "application/json") .POST(HttpRequest.BodyPublishers.ofString(requestBody)) .build(); // 发送请求并接收响应 HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); // 输出响应信息 System.out.println("Response Code: " + response.statusCode()); System.out.println("Response Body: " + response.body()); } private static SSLContext createSSLContext() throws Exception { String keystorePath = "替换成你的路径,我的是C:/Users/ximinghui/Downloads/key.jks"; String trustStorePath = "替换成你的路径,我的是C:/Users/ximinghui/Downloads/visa_truststore.jks"; String keystorePassword = "替换成你的keystorePassword,我的是C000000"; String trustStorePassword = "替换成你的trustStorePassword,我的是123456"; // 加载密钥库(客户端证书) KeyStore keyStore = KeyStore.getInstance("JKS"); try (FileInputStream fis = new FileInputStream(keystorePath)) { keyStore.load(fis, keystorePassword.toCharArray()); } // 加载信任库(Visa的证书) KeyStore trustStore = KeyStore.getInstance("JKS"); try (FileInputStream fis = new FileInputStream(trustStorePath)) { trustStore.load(fis, trustStorePassword.toCharArray()); } // 初始化 KeyManagerFactory KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); keyManagerFactory.init(keyStore, keystorePassword.toCharArray()); // 初始化 TrustManagerFactory TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(trustStore); // 配置 SSLContext SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); return sslContext; } }

运行代码,调用API成功响应的状态码是2xx,响应体如下:

{ "transactionIdentifier": 429311337027961, "actionCode": "00", "approvalCode": "98765X", "responseCode": "5", "transmissionDateTime": "2024-12-27T09:39:48.000Z", "cavvResultCode": "8", "cpsAuthorizationCharacteristicsIndicator": "3333" }