Java服务端实现Google Pay支付功能

这篇具有很好参考价值的文章主要介绍了Java服务端实现Google Pay支付功能。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Hello大家好,鉴于之前第一篇的博客关于Google pay支付,可能很多读者对整体功能不太清晰,然后最近对代码进行了重构,希望接下来这篇能够帮助读者们更快捷、更方便的集成Google Pay功能,好了话不多说,直接进入正题:

Google支付所需配置

可参考官网,创建应用、添加权限、生成json文件,这里我就不详细多说了,这种配置获取可根据官网、或者网上找的方法一大堆。像有些读者出现调用API时出现400的错误,基本都是配置错误导致的,主要是权限没配置好。

谷歌支付回调

谷歌开发这通知功能(Pub/Sub),这个我也不详细多说了,可参考官网。(如果不懂可以看之前的博客有参考地址)

好的接下来咱们直接进入代码层面,先说代码层面之前,我先给大家梳理下流程:
Java服务端实现Google Pay支付功能,java,googlecloud
下单逻辑读者们应该没啥问题吧,注意看里面的订单处理(1)和订单处理(2),分为客户端主动回调请求订单处理和Google回调服务端通知订单处理,订单处理(1)相信流程大家都没问题,但是订单处理(2),大家想想,如果Google回调通知订单,服务端怎么获取该用户发起的系统订单号呢?注意:Google下单时时支持字段透传的,也就是说,在步骤③的时候吧步骤②返回的系统订单号放入,那么这个Google支付完成后,回调Google将会透传这个字段给服务端,这个下面代码会讲(各位读者不要急)~,那这样这个回调通知是不是就产生了Google订单和系统订单关联关系了!

接下来看代码实现,具体下单逻辑我就不讲述了,这是读者们实现的,以下会讲解怎么集成Google Pay API。

代码集成实现

1、所需依赖
Google pay SDK依赖和认证依赖:

<!-- google pay依赖(使用最新版本)可取maven仓库查看,这边是GitHub发布的新版本 -->
        <dependency>
            <groupId>com.google.apis</groupId>
            <artifactId>google-api-services-androidpublisher</artifactId>
            <version>v3-rev20230815-2.0.0</version>
        </dependency>
<!-- google client依赖 https://mvnrepository.com/artifact/com.google.auth/google-auth-library-oauth2-http -->
        <dependency>
            <groupId>com.google.auth</groupId>
            <artifactId>google-auth-library-oauth2-http</artifactId>
            <version>1.19.0</version>
        </dependency>

2、Client对象创建

	    //存放多个实例的 AndroidPublisher Map
    public static Map<String, AndroidPublisher> ANDROID_PUBLISHER_MAP = new ConcurrentHashMap<>();
	
	/**
     * 必须实现对象创建逻辑,可能会存在空
     *
     * @param appName 应用唯一标识(单例模式创建)
     * @return
     */
    @Override
    public synchronized AndroidPublisher getAuthInstance(String appName) throws PaymentCoreException {
        AndroidPublisher androidPublisher = ANDROID_PUBLISHER_MAP.get(appName);
        if (androidPublisher != null) {
            return androidPublisher;
        }
        //工厂策略模式读取,这个是我存放的Google配置信息,大家可忽略,可自己实现
        GooglePayConfigEntity googlePayConfig = paymentConfigFactory.getPaymentConfig(ConstantUtil.GOOGLE_PAYMENT_CONFIG_IMPL, appName);
        InputStream input = null;
        try {
            //获取用户凭证 json文件流
            input = FileUtil.getImageStreamByUrl(googlePayConfig.getJsonFileUrl());
            //生成Credentials对象
            GoogleCredentials credentials = GoogleCredentials.fromStream(input);
            HttpTransport transport = GoogleNetHttpTransport.newTrustedTransport();
            HttpCredentialsAdapter httpCredentialsAdapter = new HttpCredentialsAdapter(credentials);
            //创建 AndroidPublisher对象
            androidPublisher = new AndroidPublisher.Builder(
                    transport,
                    GsonFactory.getDefaultInstance(),
                    httpCredentialsAdapter).build();
        } catch (Exception e) {
            throw new PaymentCoreException("[Google] client instance create exception: " + e.getMessage());
        } finally {
            FileUtil.closeStream(input);
        }
        if (androidPublisher != null) {
            //放入对象容器
            ANDROID_PUBLISHER_MAP.put(appName, androidPublisher);
        }
        return androidPublisher;
    }

3、以下是各种API处理方法:

    /**
     * 一次性(单次)购买订单对象获取
     *
     * @param appName       应用唯一标识
     * @param packageName   包名称
     * @param productId     商品Id
     * @param purchaseToken 谷歌购买凭据
     * @return
     */
    public ProductPurchase getOneTimeGoogleOrder(String appName, String packageName, String productId, String purchaseToken) throws PaymentCoreException {
        AndroidPublisher authInstance = this.getAuthInstance(appName);
        if (authInstance == null) {
            throw new PaymentCoreException("[Google] AndroidPublisher instance is empty");
        }
        ProductPurchase products = null;
        try {
            products = authInstance.purchases().products().get(packageName, productId, purchaseToken).execute();
            log.info("Products order info: {}", JSONUtil.toJsonStr(products));
        } catch (IOException e) {
            throw new PaymentCoreException("[Google] Get google products order info exception: " + e.getMessage());
        }
        return products;
    }

	/**
     * 订阅购买订单获取(V2版本),最新订阅请使用V2,官方对V1已经不维护了,但是可以用哈!
     *
     * @param appName       应用唯一标识
     * @param packageName   包名称
     * @param purchaseToken 购买凭据
     * @return
     */
    public SubscriptionPurchaseV2 getSubscriptionGoogleOrderV2(String appName, String packageName, String purchaseToken) throws PaymentCoreException {
        AndroidPublisher authInstance = this.getAuthInstance(appName);
        if (authInstance == null) {
            throw new PaymentCoreException("[Google] AndroidPublisher instance is empty");
        }
        SubscriptionPurchaseV2 subscriptionsV2 = null;
        try {
            subscriptionsV2 = authInstance.purchases().subscriptionsv2().get(packageName, purchaseToken).execute();
            log.info("SubscriptionsV2 order info: {}", JSONUtil.toJsonStr(subscriptionsV2));
        } catch (IOException e) {
            throw new PaymentCoreException("[Google] Get google subscriptions v2 order info exception: " + e.getMessage());
        }
        return subscriptionsV2;
    }

	/**
     * 取消订阅方法
     *
     * @param appName        应用唯一标识
     * @param packageName    包名称
     * @param subscriptionId 订阅Id,其实就是商品Id
     * @param purchaseToken  购买凭据
     * @return
     */
    public void cancelSubscription(String appName, String packageName, String subscriptionId, String purchaseToken) throws PaymentCoreException {
        AndroidPublisher authInstance = this.getAuthInstance(appName);
        if (authInstance == null) {
            throw new PaymentCoreException("[Google] AndroidPublisher instance is empty");
        }
        try {
            authInstance.purchases().subscriptions().cancel(packageName, subscriptionId, purchaseToken).execute();
            log.info("Cancel subscription success");
        } catch (IOException e) {
            throw new PaymentCoreException("[Google] Cancel google subscriptions exception: " + e.getMessage());
        }
    }

    /**
     * 订阅退款方法
     *
     * @param appName        应用唯一标识
     * @param packageName    包名称
     * @param subscriptionId 订阅Id,其实就是商品Id
     * @param purchaseToken  购买凭据
     * @return
     */
    public void refundSubscription(String appName, String packageName, String subscriptionId, String purchaseToken) throws PaymentCoreException {
        AndroidPublisher authInstance = this.getAuthInstance(appName);
        if (authInstance == null) {
            throw new PaymentCoreException("[Google] AndroidPublisher instance is empty");
        }
        try {
            authInstance.purchases().subscriptions().refund(packageName, subscriptionId, purchaseToken).execute();
            log.info("Refund subscription success");
        } catch (IOException e) {
            throw new PaymentCoreException("[Google] Refund google subscriptions exception: " + e.getMessage());
        }
    }

    /**
     * 订阅撤销方法,但是不建议我们实现,让客户自己在Google play商店操作订阅的状态
     *
     * @param appName        应用唯一标识
     * @param packageName    包名称
     * @param subscriptionId 订阅Id,其实就是商品Id
     * @param purchaseToken  购买凭据
     * @return
     */
    public void revokeSubscription(String appName, String packageName, String subscriptionId, String purchaseToken) throws PaymentCoreException {
        AndroidPublisher authInstance = this.getAuthInstance(appName);
        if (authInstance == null) {
            throw new PaymentCoreException("[Google] AndroidPublisher instance is empty");
        }
        try {
            authInstance.purchases().subscriptions().revoke(packageName, subscriptionId, purchaseToken).execute();
            log.info("Revoke subscription success");
        } catch (IOException e) {
            throw new PaymentCoreException("[Google] Revoke google subscriptions exception: " + e.getMessage());
        }
        return;
    }

    /**
     * 订阅购买订单获取(旧版本),跟V2一样的逻辑, 但是google官网说明方法已经废弃,不维护
     *
     * @param appName        应用唯一标识
     * @param packageName    包名称
     * @param subscriptionId 订阅Id,其实就是商品Id
     * @param purchaseToken  购买凭据
     * @return
     */
    public SubscriptionPurchase getSubscriptionGoogleOrder(String appName, String packageName, String subscriptionId, String purchaseToken) throws PaymentCoreException {
        AndroidPublisher authInstance = this.getAuthInstance(appName);
        if (authInstance == null) {
            throw new PaymentCoreException("[Google] AndroidPublisher instance is empty");
        }
        SubscriptionPurchase subscriptions = null;
        try {
            subscriptions = authInstance.purchases().subscriptions().get(packageName, subscriptionId, purchaseToken).execute();
            log.info("Subscriptions order info: {}", JSONUtil.toJsonStr(subscriptions));
        } catch (IOException e) {
            throw new PaymentCoreException("[Google] Get google subscriptions order info exception: " + e.getMessage());
        }
        return subscriptions;
    }

4、介绍以下重点参数:
appName: 用于SaaS环境区分项目的,一个环境一个appName。
packageName: Google配置的包应用名称。客户端传入。
subscriptionId: Google配置的商品Id,唯一标识。客户端传入。
purchaseToken: 用户购买的凭证。客户端传入。

5、判断订单是否成功:

单次(消耗):

/**
 * @author xxx  应用内商品的消耗状态。可能的值包括:0。尚未消耗 1. 已使用 (Products对象中的值)
 * @version 1.0
 * @date 2023/8/23 20:13
 */
public enum ConsumptionStateEnum {

    NOT_CONSUMED(0, "Yet to be consumed"),
    CONSUMED(1, "Consumed");

    public int code;
    public String msg;

    ConsumptionStateEnum(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
}

/**
 * @author xxx  订单的购买状态 可能的值包括:0。购买 1. 已取消 2. 待处理 (Products对象中的值)
 * @version 1.0
 * @date 2023/8/23 19:59
 */
public enum PurchaseStateEnum {

    PURCHASED(0, "Purchased"),
    CANCELED(1, "Canceled"),
    PENDING(2, "Pending");

    public int code;
    public String msg;

    PurchaseStateEnum(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
}

    /**
     * 校验单次购买是否成功
     *
     * @param productPurchase
     * @return
     */
    public boolean checkOneTimeGoogleOrderSuccess(ProductPurchase productPurchase) {
        if (ConsumptionStateEnum.CONSUMED.getCode() == productPurchase.getConsumptionState()
                && PurchaseStateEnum.PURCHASED.getCode() == productPurchase.getPurchaseState()) {
            return true;
        }
        return false;
    }

    /**
     * 校验单次购买是否失败
     *
     * @param productPurchase
     * @return
     */
    public boolean checkOneTimeGoogleOrderFail(ProductPurchase productPurchase) {
        if (PurchaseStateEnum.CANCELED.getCode() == productPurchase.getPurchaseState()) {
            return true;
        }
        return false;
    }

订阅

/**
 * @author xxx订阅的确认状态。 (subscriptionsv2)对象中的 acknowledgementState
 * ACKNOWLEDGEMENT_STATE_UNSPECIFIED	未指定的确认状态。
 * ACKNOWLEDGEMENT_STATE_PENDING	订阅尚未确认。
 * ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED	已确认订阅。
 * @version 1.0
 * @date 2023/8/23 20:55
 */
public enum SubscriptionAckStateEnum {

    ACKNOWLEDGEMENT_STATE_UNSPECIFIED("ACKNOWLEDGEMENT_STATE_UNSPECIFIED", "Unspecified acknowledgement state"),
    ACKNOWLEDGEMENT_STATE_PENDING("ACKNOWLEDGEMENT_STATE_PENDING", "The subscription is not acknowledged yet"),
    ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED("ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED", "The subscription is acknowledged");

    public String code;
    public String msg;

    SubscriptionAckStateEnum(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public String getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
}

/**
 * @author xxx订阅的当前状态。 (subscriptionsv2)对象中的 subscriptionState
 * SUBSCRIPTION_STATE_UNSPECIFIED	未指定订阅状态。
 * SUBSCRIPTION_STATE_PENDING	已创建订阅,但在注册期间正在等待付款。在此状态下,所有商品均正在等待付款。
 * SUBSCRIPTION_STATE_ACTIVE	订阅处于有效状态。- (1) 如果订阅是自动续订型方案,则至少有一项是自动续订状态并且未过期。- (2) 如果订阅是预付费方案,至少有一项不会过期。
 * SUBSCRIPTION_STATE_PAUSED	订阅已暂停。只有在订阅是自动续订型方案时,才会显示该状态。在此状态下,所有商品均处于暂停状态。
 * SUBSCRIPTION_STATE_IN_GRACE_PERIOD	订阅处于宽限期。只有在订阅是自动续订型方案时,才会显示该状态。在此状态下,所有商品均处于宽限期。
 * SUBSCRIPTION_STATE_ON_HOLD	订阅已暂停(已暂停)。只有在订阅是自动续订型方案时,才会显示该状态。在此状态下,所有商品均处于保全状态。
 * SUBSCRIPTION_STATE_CANCELED	订阅已取消,但尚未过期。只有在订阅是自动续订型方案时,才会显示该状态。所有商品的 autoRenewEnabled 都设为 false。
 * SUBSCRIPTION_STATE_EXPIRED	订阅已过期。所有内容的过期时间都是过去的时间。
 * @version 1.0
 * @date 2023/8/23 20:37
 */
public enum SubscriptionStateEnum {

    SUBSCRIPTION_STATE_UNSPECIFIED("SUBSCRIPTION_STATE_UNSPECIFIED", "Unspecified subscription state"),
    SUBSCRIPTION_STATE_PENDING("SUBSCRIPTION_STATE_PENDING", "Subscription was created"),
    SUBSCRIPTION_STATE_ACTIVE("SUBSCRIPTION_STATE_ACTIVE", "Subscription is active"),
    SUBSCRIPTION_STATE_PAUSED("SUBSCRIPTION_STATE_PAUSED", "Subscription is paused"),
    SUBSCRIPTION_STATE_IN_GRACE_PERIOD("SUBSCRIPTION_STATE_IN_GRACE_PERIOD", "Subscription is in grace period"),
    SUBSCRIPTION_STATE_ON_HOLD("SUBSCRIPTION_STATE_ON_HOLD", "Subscription is on hold (suspended)"),
    SUBSCRIPTION_STATE_EXPIRED("SUBSCRIPTION_STATE_EXPIRED", "Subscription is expired"),
    SUBSCRIPTION_STATE_CANCELED("SUBSCRIPTION_STATE_CANCELED", "Subscription is canceled but not expired yet");

    public String code;
    public String msg;

    SubscriptionStateEnum(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public String getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }

}

    /**
     * 校验订阅订单是否支付成功
     *
     * @param subscriptionsV2
     * @return
     */
    public boolean checkSubscriptionSuccess(SubscriptionPurchaseV2 subscriptionsV2) {
        String acknowledgementState = subscriptionsV2.getAcknowledgementState();
        if (SubscriptionAckStateEnum.ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED.getCode().equals(acknowledgementState)) {
            return true;
        }
        return false;
    }

以上就是集成的代码实现。

回调处理

可看官网文档,但是这边我都给你弄成JavaBean了,也没必要去看(以下忽略getter/setter):

回调实体:

/**
 * @author xxx 谷歌开发者通知对象
 * @version 1.0
 * @date 2023/10/8 16:12
 */
public class DeveloperNotification implements Serializable {
    /**
     * 此通知的版本。最初,此值为“1.0”。此版本与其他版本字段不同。
     */
    private String version;

    /**
     * 与此通知相关的应用的软件包名称(例如“com.some.thing”)。
     */
    private String packageName;

    /**
     * 事件发生的时间戳,以从公元纪年开始计算的毫秒数表示。
     */
    private long eventTimeMillis;

    /**
     * 如果此字段存在,则此通知与订阅相关,并且此字段包含与订阅相关的其他信息。请注意,此字段与 testNotification 和 oneTimeProductNotification 互斥。
     */
    private SubscriptionNotification subscriptionNotification;

    /**
     * 如果此字段存在,则此通知与一次性购买相关,并且此字段包含与购买交易相关的其他信息。请注意,此字段与 testNotification 和 subscriptionProductNotification 互斥。
     */
    private OneTimeProductNotification oneTimeProductNotification;

    /**
     * 如果此字段存在,则此通知与测试发布相关。这些只通过 Google Play 管理中心发送。请注意,此字段与 subscriptionNotification 和 oneTimeProductNotification 互斥。
     */
    private TestNotification testNotification;
}

/**
 * @author xxx 谷歌开发者回调订阅通知信息
 * @version 1.0
 * @date 2023/10/8 15:55
 */
public class SubscriptionNotification implements Serializable {
    /**
     * 通知的版本。最初,此值为“1.0”。此版本与其他版本字段不同。
     */
    private String version;

    /**
     * 订阅的 notificationType 可以具有以下值:
     * (1) SUBSCRIPTION_RECOVERED - 从帐号保留状态恢复了订阅。
     * (2) SUBSCRIPTION_RENEWED - 续订了处于活动状态的订阅。
     * (3) SUBSCRIPTION_CANCELED - 自愿或非自愿地取消了订阅。如果是自愿取消,在用户取消时发送。
     * (4) SUBSCRIPTION_PURCHASED - 购买了新的订阅。
     * (5) SUBSCRIPTION_ON_HOLD - 订阅已进入帐号保留状态(如果已启用)。
     * (6) SUBSCRIPTION_IN_GRACE_PERIOD - 订阅已进入宽限期(如果已启用)。
     * (7) SUBSCRIPTION_RESTARTED - 用户已通过 Play > 帐号 > 订阅恢复了订阅。订阅已取消,但在用户恢复时尚未到期。如需了解详情,请参阅恢复。
     * (8) SUBSCRIPTION_PRICE_CHANGE_CONFIRMED - 用户已成功确认订阅价格变动。
     * (9) SUBSCRIPTION_DEFERRED - 订阅的续订时间点已延期。
     * (10) SUBSCRIPTION_PAUSED - 订阅已暂停。
     * (11) SUBSCRIPTION_PAUSE_SCHEDULE_CHANGED - 订阅暂停计划已更改。
     * (12) SUBSCRIPTION_REVOKED - 用户在到期时间之前已撤消订阅。
     * (13) SUBSCRIPTION_EXPIRED - 订阅已到期。
     */
    private int notificationType;

    /**
     * 购买订阅时向用户设备提供的令牌。
     */
    private String purchaseToken;

    /**
     * 所购买订阅的商品 ID(例如“monthly001”)。
     */
    private String subscriptionId; 
}    

/**
 * @author xxx 谷歌开发者回调单次通知信息
 * @version 1.0
 * @date 2023/10/8 16:09
 */
public class OneTimeProductNotification implements Serializable {
    /**
     * 通知的版本。最初,此值为“1.0”。此版本与其他版本字段不同。
     */
    private String version;

    /**
     * 通知的类型。它可以具有以下值:
     * (1) ONE_TIME_PRODUCT_PURCHASED - 用户成功购买了一次性商品。
     * (2) ONE_TIME_PRODUCT_CANCELED - 用户已取消待处理的一次性商品购买交易。
     */
    private int notificationType;

    /**
     * 购买订阅时向用户设备提供的令牌。
     */
    private String purchaseToken;

    /**
     * 购买的一次性商品的商品 ID(例如“sword_001”)。
     */
    private String sku;
}

/**
 * @author xxx 订阅通知类型,具体描述可参考SubscriptionNotification实体
 * @version 1.0
 * @date 2023/10/8 19:15
 */
public enum SubscriptionNotifyTypeEnum {

    SUBSCRIPTION_RECOVERED(1),
    SUBSCRIPTION_RENEWED(2),
    SUBSCRIPTION_CANCELED(3),
    SUBSCRIPTION_PURCHASED(4),
    SUBSCRIPTION_ON_HOLD(5),
    SUBSCRIPTION_IN_GRACE_PERIOD(6),
    SUBSCRIPTION_RESTARTED(7),
    SUBSCRIPTION_PRICE_CHANGE_CONFIRMED(8),
    SUBSCRIPTION_DEFERRED(9),
    SUBSCRIPTION_PAUSED(10),
    SUBSCRIPTION_PAUSE_SCHEDULE_CHANGED(11),
    SUBSCRIPTION_REVOKED(12),
    SUBSCRIPTION_EXPIRED(13);

    private int type;

    SubscriptionNotifyTypeEnum(int type) {
        this.type = type;
    }

    public int getType() {
        return type;
    }
}    

Google回调接口实现:

/**
     * 谷歌回调通知,订单处理
     *
     * @param body
     */
    @RequestMapping(value = "/notify/payment/google", method = RequestMethod.POST)
    public void googleNotify(@RequestBody(required = false) byte[] body) {
        String bodyStr = new String(body, "utf-8");
        //转成JSON
            /**  参数信息
             *{
             *   "message": {
             *     "attributes": {
             *       "key": "value"
             *     },
             *     "data": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
             *     "messageId": "136969346945"
             *   },
             *   "subscription": "projects/myproject/subscriptions/mysubscription"
             * }
             */
            JSONObject bodyJson = JSONObject.parseObject(URLDecoder.decode(bodyStr, "utf-8"));
            //base64解码data
            String data = EncryptionUtil.base64Decode(bodyJson.getJSONObject("message").getString("data"));
            DeveloperNotification developerNotification = JSONObject.parseObject(data, DeveloperNotification.class);
			//判断developerNotification对象中有哪个对象
			if (subscriptionNotification != null) {
                //为订阅通知,调用上述的方法获取订单校验即可
            }
            if (oneTimeProductNotification != null) {
                //为单次通知,调用上述的方法获取订单校验即可
            }
    }

订阅订单处理:

注意,里面包含了流程图中订单处理(2)获取系统订单的方式

/**
     * 订阅回调通知
     *
     * @param subscriptionNotification
     * @param packageName
     * @param appName
     */
    private void subscriptionNotify(SubscriptionNotification subscriptionNotification, String packageName, String appName) {
        int notificationType = subscriptionNotification.getNotificationType();
        String purchaseToken = subscriptionNotification.getPurchaseToken();
        //获取订阅订单信息
        try {
            SubscriptionPurchaseV2 subscriptionGoogleOrderV2 = getSubscriptionGoogleOrderV2(appName, packageName, purchaseToken);
            //判断订单状态
            if (!googlePayment.checkSubscriptionSuccess(subscriptionGoogleOrderV2)) {
                return;
            }
            //判断通知类型
            if (SubscriptionNotifyTypeEnum.SUBSCRIPTION_PURCHASED.getType() == notificationType) {
                //购买了新订阅,如果是上面流程图(2)处理,教你们怎么获取系统订单,让客户端设置相应的属性即可
                ExternalAccountIdentifiers externalAccountIdentifiers = subscriptionGoogleOrderV2.getExternalAccountIdentifiers();
                String obfuscatedExternalAccountId = externalAccountIdentifiers.getObfuscatedExternalAccountId();
                String obfuscatedExternalProfileId = externalAccountIdentifiers.getObfuscatedExternalProfileId();
                String externalAccountId = externalAccountIdentifiers.getExternalAccountId();
                responseVO = newSubscription(subscriptionGoogleOrderV2);
            }
            if (SubscriptionNotifyTypeEnum.SUBSCRIPTION_CANCELED.getType() == notificationType) {
                //取消了订阅
                responseVO = cancelSubscription(subscriptionGoogleOrderV2);
            }
            if (SubscriptionNotifyTypeEnum.SUBSCRIPTION_RENEWED.getType() == notificationType) {
                //续订了订阅
                //根据现在请求谷歌的googleOrderId获取续订包的订单,获取用户跟productId
                        //续订的谷歌订单是有规则的,比如你第一次购买产生的订单是GPA.123-456-789,那第一次续订的产生的订单号是GPA.123-456-789..0,第二次GPA.123-456-789..1,依次类推。
                        //续订这里还有一个坑,当订阅包降级购买的时候,谷歌并不是通知你购买了新订阅包而是续订,比如你购买的高级订阅包是GPA.123-456-789,当你切换低级的订阅包的时候订单号为GPA.111-222-333..0,你会发现订单号变了,这时候就难办了,拿不到之前用户的信息(谷歌返回的订单参数是没有项目里面用户信息的),经过联调发现,他们两个订单的linkedPurchaseToken是一样的,可以参考上图中参数的介绍
                        //当降级和自动续订的时候都会走这个通知,所以里面有两个逻辑,需要自己去判断,这两者的不同上面都写的很清楚了。
                responseVO = renewSubscription(subscriptionGoogleOrderV2);
            }
            if (SubscriptionNotifyTypeEnum.SUBSCRIPTION_ON_HOLD.getType() == notificationType) {
                //订阅进入保留状态,用户拒绝付款
                responseVO = onHoldSubscription(subscriptionGoogleOrderV2);
            }
            if (SubscriptionNotifyTypeEnum.SUBSCRIPTION_RECOVERED.getType() == notificationType) {
                //从保留状态恢复了订阅
                responseVO = recoverSubscription(subscriptionGoogleOrderV2);
            }
            if (SubscriptionNotifyTypeEnum.SUBSCRIPTION_RESTARTED.getType() == notificationType) {
                //重新注册了订阅,用户已通过“Play”>“帐号”>“订阅”重新激活其订阅(需要选择使用订阅恢复功能)
                responseVO = restartSubscription(subscriptionGoogleOrderV2);
            }
            if (SubscriptionNotifyTypeEnum.SUBSCRIPTION_REVOKED.getType() == notificationType) {
                //用户撤销订阅
                responseVO = revokeSubscription(subscriptionGoogleOrderV2);
            }
            if (SubscriptionNotifyTypeEnum.SUBSCRIPTION_EXPIRED.getType() == notificationType) {
                //订阅过期
                responseVO = expiredSubscription(subscriptionGoogleOrderV2);
            }
            if (SubscriptionNotifyTypeEnum.SUBSCRIPTION_IN_GRACE_PERIOD.getType() == notificationType) {
                //订阅进入宽限期
                responseVO = inGracePeriodSubscription(subscriptionGoogleOrderV2);
            }
            if (SubscriptionNotifyTypeEnum.SUBSCRIPTION_PAUSED.getType() == notificationType) {
                //订阅暂停
                responseVO = pauseSubscription(subscriptionGoogleOrderV2);
            }
        } catch (PaymentCoreException e) {
            log.error("Google get subscription order v2 exception: {}", e.getMessage());
            e.printStackTrace();
        } finally {
            //记录处理结果
        }
    }

所有的代码均已讲解,各位读者对这个支付功能还有什么疑惑呢,在评论区探讨的,码字不易~讲解不易!!!点个赞再走。记住,我还是那个会撩头发的程序猿!!!

转载请标明出处谢谢大家~文章来源地址https://www.toymoban.com/news/detail-735773.html

到了这里,关于Java服务端实现Google Pay支付功能的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Electron中苹果支付 Apple Pay inAppPurchase 内购支付

    正在开发中,开发好了,写一个完整详细的过程,保证无脑集成即可 一般情况下,在你看这篇文章的时候,说明你已经开发的app差不多了。 但是要上架app到Mac App Store,则要在appstoreconnect这个地方创建一个app。 在此处创建一个有两种方法:一是 在mac上下载transfore的一个官方

    2024年01月19日
    浏览(39)
  • JAVA 小程序支付+服务商分账

    产品介绍: 服务商分账,主要用于服务商帮助特约商户完成订单收单成功后的资金分配。 使用场景举例: 1、服务商抽成 在各个行业中,服务商为特约商户提供增值服务,服务商与特约商户协商,可以从特约商户的交易流水中抽取一定的手续费。 引用自微信服务商分账 流程

    2024年02月09日
    浏览(44)
  • (短信服务)java SpringBoot 阿里云短信功能实现发送手机验证码

    阿里云官网: https://www.aliyun.com/ 点击官网首页注册按钮。 注册成功后,点击登录按钮进行登录。登录后进入短信服务管理页面,选择国内消息菜单: 短信签名是短信发送者的署名,表示发送方的身份。 切换到【模板管理】标签页: 短信模板包含短信发送内容、场景、变量信息

    2024年02月02日
    浏览(56)
  • 【Java实战】Feign调用文件下载服务接口实现文件下载功能

    最近需要实现Feign调用服务提供者的文件下载接口,进行文件下载功能,这里对功能的实现做一个简单的记录 通过调用服务提供者的文件下载接口,将文件传输的流数据通过 feign.Response 来接收,服务消费者再将数据转化 首先,在项目中引入Feign的依赖。你可以使用Maven进行管

    2024年02月12日
    浏览(80)
  • Java实现微信支付v3的支付回调

    以前都是自己手搓api的, 现在有轮子了, 尝试记录一下如何使用 我的做法是首先打开v3的代码仓库, 直接进去看看他们的文档, 可以看到这么一坨东西 开发前准备 2. 先引入maven 初始化商户配置 先从请求头中获取构建RequestParam需要的参数 初始化解析器 进行验签, 解密并转换成

    2024年02月12日
    浏览(53)
  • Java服务端集成Google FCM推送的注意事项和实际经验

    公司的app要上海外,涉及到推送功能,经过综合考虑,选择Google FCM进行消息推送。 查看一些集成博客和官方文档,看的似懂非懂,迷迷惑惑。本篇文章除了将我实际集成的经验分享出来,也会对看到的博客及其中产生的疑惑、注意事项一一评论。 从官方文档和众多博客中,

    2024年02月10日
    浏览(45)
  • Java实现微信支付

    文章有不当之处,欢迎指正。 突然想到自己还有个博客,碰巧再写微信小程序支付,所以浅写一下。 正文开始。。。。。。。。。。。。 官方文档:微信支付文档 看过之后你会发现开发有点麻烦,所以接下来选择使用第三方sdk开发,减少工作量, 大佬GitHub地址:GitHub 大家

    2024年02月10日
    浏览(32)
  • Java实现支付宝沙箱环境支付,SDK接口远程调试

    转发自cpolar内网穿透的文章:Java支付宝沙箱环境支付,SDK接口远程调试【内网穿透】 Maven Spring boot Jdk 1.8 获取支付宝支付Java SDK,maven项目可以选择maven版本,普通java项目可以在GitHub下载,这里以maven为例 SDK下载地址:https://doc.open.alipay.com/docs/doc.htm?treeId=193articleId=103419docType=1 选择

    2024年02月06日
    浏览(62)
  • Java实现Google授权登录,OAuth 2.0登录

    首先创建OAuth 2.0 客户端 ID 配置url,必须是 https 的,同时复制好客户端id 和密钥 配置回调url 回调接口

    2024年02月14日
    浏览(49)
  • Java 实现微信支付详细教程

    摘要 :最近的一个项目中涉及到了支付业务,其中用到了微信支付和支付宝支付,在做的过程中也遇到些问题,所以现在总结梳理一下,分享给有需要的人,也为自己以后回顾留个思路。 首先,微信支付,只支持企业用户,个人用户是不能接入微信支付的,所以要想接入微

    2024年02月15日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包