简单实现一个苹果支付的场景

在Spring Boot项目中集成Apple Pay,需要实现以下步骤:

  1. 配置Apple开发者账户:在Apple开发者中心创建商家ID,并生成相关的支付处理证书。

  2. 配置HTTPS :Apple Pay要求服务器必须使用HTTPS协议。您可以使用JDK自带的keytool工具生成自签名证书,或从受信任的证书颁发机构获取证书。

  3. 集成支付SDK :在Spring Boot项目中,您可以使用第三方支付集成库,如pay-spring-boot-starter,来简化支付流程的实现。

以下是一个基于Spring Boot的场景示例,展示如何集成Apple Pay并处理支付回调:

1. 配置Apple Pay相关参数

application.yml中添加Apple Pay的相关配置:

yaml 复制代码
applepay:
  merchantId: your_merchant_id
  merchantCertificatePath: path_to_your_merchant_certificate.p12
  merchantCertificatePassword: your_certificate_password
  merchantIdentifier: your_merchant_identifier

2. 创建支付服务类

创建一个服务类ApplePayService,用于处理支付请求和验证支付结果:

java 复制代码
@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,用于处理前端的支付请求和回调:

java 复制代码
@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的支付流程:

html 复制代码
<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();
        
相关推荐
liuxin3344556627 分钟前
科研实验室的数字化转型:Spring Boot系统
数据库·spring boot·php
小林学习编程33 分钟前
从零开始理解Spring Security的认证与授权
java·后端·spring
写bug的羊羊34 分钟前
Spring Boot整合Nacos启动时 Failed to rename context [nacos] as [xxx]
java·spring boot·后端
2402_857589361 小时前
实验室管理效率提升:Spring Boot技术的力量
java·spring boot·后端
The shackles1 小时前
spring boot接收参数
spring boot
2401_857636391 小时前
Spring Boot图书馆管理系统:疫情中的技术实现
java·spring boot·后端
2401_857622661 小时前
实验室管理软件:Spring Boot技术构建
java·spring boot·后端
小林学习编程1 小时前
Springboot + vue 健身房管理系统项目部署
vue.js·spring boot·后端
qq_q9922502771 小时前
django基于python 语言的酒店推荐系统
后端·python·django
小李L1 小时前
Python3 Flask 应用中使用阿里短信发送
后端·python·flask