在Spring Boot项目中集成Apple Pay,需要实现以下步骤:
配置Apple开发者账户:在Apple开发者中心创建商家ID,并生成相关的支付处理证书。
配置HTTPS:Apple Pay要求服务器必须使用HTTPS协议。您可以使用JDK自带的
keytool
工具生成自签名证书,或从受信任的证书颁发机构获取证书。集成支付SDK:在Spring Boot项目中,您可以使用第三方支付集成库,如
pay-spring-boot-starter
,来简化支付流程的实现。
以下是一个基于Spring Boot的场景示例,展示如何集成Apple Pay并处理支付回调:
1. 配置Apple Pay相关参数
在application.yml
中添加Apple Pay的相关配置:
applepay: merchantId: your_merchant_id merchantCertificatePath: path_to_your_merchant_certificate.p12 merchantCertificatePassword: your_certificate_password merchantIdentifier: your_merchant_identifier
2. 创建支付服务类
创建一个服务类ApplePayService
,用于处理支付请求和验证支付结果:
@Service public class ApplePayService { @Value("${applepay.merchantId}") private String merchantId; @Value("${applepay.merchantCertificatePath}") private String merchantCertificatePath; @Value("${applepay.merchantCertificatePassword}") private String merchantCertificatePassword; @Value("${applepay.merchantIdentifier}") private String merchantIdentifier; public String createPaymentSession(String validationUrl) { // 加载商户证书 KeyStore keyStore = KeyStore.getInstance("PKCS12"); try (InputStream keyInput = new FileInputStream(merchantCertificatePath)) { keyStore.load(keyInput, merchantCertificatePassword.toCharArray()); } // 创建SSL上下文 KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(keyStore, merchantCertificatePassword.toCharArray()); SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(kmf.getKeyManagers(), null, null); // 设置HTTPS连接 URL url = new URL(validationUrl); HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); connection.setSSLSocketFactory(sslContext.getSocketFactory()); connection.setRequestMethod("POST"); connection.setRequestProperty("Content-Type", "application/json"); // 构建请求数据 JSONObject requestData = new JSONObject(); requestData.put("merchantIdentifier", merchantIdentifier); requestData.put("displayName", "Your Store Name"); requestData.put("initiative", "web"); requestData.put("initiativeContext", "yourdomain.com"); // 发送请求 connection.setDoOutput(true); try (OutputStream os = connection.getOutputStream()) { os.write(requestData.toString().getBytes(StandardCharsets.UTF_8)); } // 读取响应 try (InputStream is = connection.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(is))) { StringBuilder response = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { response.append(line); } return response.toString(); } } public boolean validatePayment(String paymentData) { // Apple验证服务器的URL String url = "https://sandbox.itunes.apple.com/verifyReceipt"; // 沙盒环境 // String url = "https://buy.itunes.apple.com/verifyReceipt"; // 生产环境 try { // 构建验证请求的JSON数据 JSONObject requestJson = new JSONObject(); requestJson.put("receipt-data", paymentData); // 如果是自动续订订阅,需要添加以下字段 // requestJson.put("password", "your_shared_secret"); // 创建HTTP连接 URL verifyUrl = new URL(url); HttpURLConnection conn = (HttpURLConnection) verifyUrl.openConnection(); conn.setRequestMethod("POST"); conn.setRequestProperty("Content-Type", "application/json"); conn.setDoOutput(true); // 发送请求数据 try (OutputStream os = conn.getOutputStream()) { os.write(requestJson.toString().getBytes(StandardCharsets.UTF_8)); } // 读取响应数据 int responseCode = conn.getResponseCode(); if (responseCode == 200) { try (InputStream is = conn.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(is))) { StringBuilder response = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { response.append(line); } // 解析响应JSON JSONObject responseJson = new JSONObject(response.toString()); int status = responseJson.getInt("status"); // 根据status字段判断支付结果 if (status == 0) { // 验证成功,支付有效 return true; } else if (status == 21007) { // 收据是沙盒环境,但发送到了生产环境的验证服务器 // 需要重新发送到沙盒环境进行验证 // 这里可以递归调用validatePayment方法,使用沙盒环境的URL // 注意避免递归陷阱,确保不会无限递归 return validatePaymentInSandbox(paymentData); } else { // 验证失败,支付无效 return false; } } } else { // HTTP响应码非200,表示请求失败 return false; } } catch (Exception e) { e.printStackTrace(); return false; } } }
3. 创建支付控制器
创建一个控制器ApplePayController
,用于处理前端的支付请求和回调:
@RestController @RequestMapping("/applepay") public class ApplePayController { @Autowired private ApplePayService applePayService; @PostMapping("/payment-session") public ResponseEntity<String> createPaymentSession(@RequestBody Map<String, String> request) { String validationUrl = request.get("validationUrl"); String paymentSession = applePayService.createPaymentSession(validationUrl); return ResponseEntity.ok(paymentSession); } @PostMapping("/payment-result") public ResponseEntity<String> handlePaymentResult(@RequestBody Map<String, Object> paymentResult) { String paymentData = (String) paymentResult.get("paymentData"); boolean isValid = applePayService.validatePayment(paymentData); if (isValid) { // 处理支付成功的逻辑 return ResponseEntity.ok("Payment successful"); } else { // 处理支付失败的逻辑 return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Payment validation failed"); } } }
4. 前端集成Apple Pay
在前端页面中,使用Apple提供的JavaScript库来处理Apple Pay的支付流程:
<script type="text/javascript"> document.addEventListener('DOMContentLoaded', function() { if (window.ApplePaySession && ApplePaySession.canMakePayments()) { var applePayButton = document.getElementById('apple-pay-button'); applePayButton.style.display = 'block'; applePayButton.addEventListener('click', function() { var paymentRequest = { countryCode: 'US', currencyCode: 'USD', total: { label: 'Your Store Name', amount: '10.00' }, supportedNetworks: ['visa', 'masterCard', 'amex'], merchantCapabilities: ['supports3DS'] }; var session = new ApplePaySession(3, paymentRequest); session.onvalidatemerchant = function(event) { fetch('/applepay/payment-session', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ validationUrl: event.validationURL }) }) .then(function(response) { return response.json(); }) .then(function(merchantSession) { session.completeMerchantValidation(merchantSession); }); }; session.onpaymentauthorized = function(event) { var paymentData = event.payment.token.paymentData; fetch('/applepay/payment-result', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ paymentData: paymentData }) }) .then(function(response) { if (response.ok) { session.completePayment(ApplePaySession.STATUS_SUCCESS); } else { session.completePayment(ApplePaySession.STATUS_FAILURE); } }); }; session.begin();