Google Pay 谷歌支付(gateway = stripe)

2023-05-16

Google pay 国际版开发


一、官网地址(科学上网)

官方对接文档 https://developers.google.com/pay/api/android/overview
Stripe对接Google Pay https://stripe.com/docs/google-pay
Stripe验证支付 https://stripe.com/docs/payments/accept-a-payment?integration=elements
Stripe管理后台 https://dashboard.stripe.com/dashboard

二、接入流程

Google Pay.jpg

三、主要流程

1、服务器请求orderId

2、调用Google Pay

3、通过Stripe完成支付

4、服务器完成验证

四、主要代码实现(1、4主要是服务器流程,以下主要是2、3流程)

项目配置

build.gradle 添加
    implementation 'com.google.android.gms:play-services-wallet:18.1.2'
    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'com.stripe:stripe-android:16.0.1'
AndroidManifest.xml 的 application添加
    <meta-data
          android:name="com.google.android.gms.wallet.api.enabled"
          android:value="true" />

调用Google Pay

    @RequiresApi(api = Build.VERSION_CODES.N)
    private void payWithGoogle( double price) {
        if (paymentsClient == null) {
            paymentsClient = createPaymentsClient(mActivity);
        }
        // 主要是Google Pay一些参数设置
        Optional<JSONObject> paymentDataRequestJson = createPaymentDataRequest(price);
        if (!paymentDataRequestJson.isPresent()) {
            return;
        }
        PaymentDataRequest request =
                PaymentDataRequest.fromJson(paymentDataRequestJson.get().toString());
        if (request != null) {
            if (mActivity!=null){
                mActivity.showCircle2Loading();
            }
          // 调起 Google Pay 
            AutoResolveHelper.resolveTask(
                    paymentsClient.loadPaymentData(request),
                    mActivity,
                    LOAD_PAYMENT_DATA_REQUEST_CODE
            );
        }
    }

Google Pay 基本设置

    @RequiresApi(api = Build.VERSION_CODES.N)
    private Optional<JSONObject> createPaymentDataRequest(double priceCents) {
        try {
            JSONObject paymentDataRequest = getBaseRequest();
            // 指定是否支持 Google Pay API 所支持的一种或多种付款方式。
            paymentDataRequest.put("allowedPaymentMethods", new JSONArray().put(getCardPaymentMethod()));
            // 有关根据用户是否同意交易来为交易授权的详细信息。包含总价和价格状态
            paymentDataRequest.put("transactionInfo", getTransactionInfo(priceCents));
            //商家信息
            paymentDataRequest.put("merchantInfo", getMerchantInfo());
            paymentDataRequest.put("shippingAddressRequired", false);
            paymentDataRequest.put("emailRequired", false);
            return Optional.of(paymentDataRequest);

        } catch (JSONException e) {
            return Optional.empty();
        }
    }
   private JSONObject getCardPaymentMethod() throws JSONException {
        JSONObject cardPaymentMethod = getBaseCardPaymentMethod();
        // 设置stripe为付款方式
        JSONObject tokenizationSpec = new GooglePayConfig(LIVE_API).getTokenizationSpecification();
        cardPaymentMethod.put("tokenizationSpecification", tokenizationSpec);
        return cardPaymentMethod;
    }

    /**
     * 金钱信息
     */
    private JSONObject getTransactionInfo(double price) throws JSONException {
        JSONObject transactionInfo = new JSONObject();
        transactionInfo.put("totalPrice", price+"");
        transactionInfo.put("totalPriceStatus", "FINAL");
        transactionInfo.put("countryCode", COUNTRY_CODE);
        transactionInfo.put("currencyCode", CURRENCY_CODE);
        transactionInfo.put("checkoutOption", "COMPLETE_IMMEDIATE_PURCHASE");

        return transactionInfo;
    }

    /**
     * 商家信息
     * merchantId 商家Id
     */
    private JSONObject getMerchantInfo() throws JSONException {
        return new JSONObject().put("merchantName", "Guruji").put("merchantId", "填写商家ID");
    }
    private JSONObject getBaseRequest() throws JSONException {
        return new JSONObject()
                .put("apiVersion", 2)
                .put("apiVersionMinor", 0);
    }

Google Pay返回数据

{
  "apiVersionMinor": 0,
  "apiVersion": 2,
  "paymentMethodData": {
    "description": "中国招商银行 (CMB) •••• 5019",
    "tokenizationData": {
      "type": "PAYMENT_GATEWAY",
      "token": "{\n  \"id\": \"tok_1HcQIMBcf7rsT369XhdHf1aI\",\n  \"object\": \"token\",\n  \"card\": {\n    \"id\": \"card_1HcQIMBcf7rsT369lDDy6PIM\",\n    \"object\": \"card\",\n    \"address_city\": null,\n    \"address_country\": null,\n    \"address_line1\": null,\n    \"address_line1_check\": null,\n    \"address_line2\": null,\n    \"address_state\": null,\n    \"address_zip\": null,\n    \"address_zip_check\": null,\n    \"brand\": \"Visa\",\n    \"country\": \"US\",\n    \"cvc_check\": null,\n    \"dynamic_last4\": \"4242\",\n    \"exp_month\": 10,\n    \"exp_year\": 2025,\n    \"funding\": \"credit\",\n    \"last4\": \"5019\",\n    \"metadata\": {\n    },\n    \"name\": \"name\",\n    \"tokenization_method\": \"android_pay\"\n  },\n  \"client_ip\": \"173.194.101.160\",\n  \"created\": 1602744638,\n  \"livemode\": false,\n  \"type\": \"card\",\n  \"used\": false\n}\n"
    },
    "type": "CARD",
    "info": {
      "cardNetwork": "VISA",
      "cardDetails": "5019"
    }
  }
}

数据处理,然后通过Stripe生成PaymentMethodId

    public void onCheckResult(int resultCode,Intent data) {
        switch (resultCode) {
            case Activity.RESULT_OK: {
                onGooglePayResult(data);
                break;
            }
            case Activity.RESULT_CANCELED: {
                errorShowAndRetry();
                break;
            }
            case AutoResolveHelper.RESULT_ERROR:  {
                final Status status =
                        AutoResolveHelper.getStatusFromIntent(data);
                errorShowAndRetry();
                break;
            }
            default: {
                // Do nothing.
            }
        }

    }

    private void onGooglePayResult(@NonNull Intent data) {
        PaymentData paymentData = PaymentData.getFromIntent(data);
        if (paymentData == null) {
            errorShowAndRetry();
            return;
        }
        try {
            PaymentMethodCreateParams paymentMethodCreateParams = PaymentMethodCreateParams.createFromGooglePay(new JSONObject(paymentData.toJson()));
            mStripe.createPaymentMethod(
                    paymentMethodCreateParams,
                    new ApiResultCallback<PaymentMethod>() {
                        @Override
                        public void onSuccess(@NonNull PaymentMethod result) {
                            paymentGotoStripe(result.id);
                        }

                        @Override
                        public void onError(@NonNull Exception e) {
                            errorShowAndRetry();
                        }
                    }
            );
        } catch (Exception e) {
            errorShowAndRetry();
        }

    }

通过Stripe完成最后支付

     /**
     * 得到PaymentMethodId 去stripe 支付
     */
    private void paymentGotoStripe(String id){
        if ( mStripe != null && !TextUtils.isEmpty(mSecret)) {
            ConfirmPaymentIntentParams confirmParams = ConfirmPaymentIntentParams.createWithPaymentMethodId(id, mSecret);
            mStripe.confirmPayment(mActivity, confirmParams);
            Logger.logE("live pay, click pay ---");
        } else if (mStripe == null) {
            ToastUtils.showSystemToast(R.string.payment_in_progress_tips);
            Logger.logE("live pay, click pay --- order is null");
        }
    }

    /**
     * Google --> stripe--> CallBack
     * @param requestCode
     * @param data
     */
    public void paymentResultCallback(int requestCode,Intent data){
        mStripe.onPaymentResult(requestCode, data, new PaymentResultCallback(mActivity));
    }
    private final class PaymentResultCallback implements ApiResultCallback<PaymentIntentResult> {
        @NonNull
        private final WeakReference<PaymentActivity> activityRef;

        PaymentResultCallback(@NonNull PaymentActivity activity) {
            activityRef = new WeakReference<>(activity);
        }

        @Override
        public void onSuccess(@NonNull PaymentIntentResult result) {
            PaymentActivity activity = activityRef.get();
            if (activity == null) {
                return;
            }

            PaymentIntent paymentIntent = result.getIntent();
            PaymentIntent.Status status = paymentIntent.getStatus();
            if (status == PaymentIntent.Status.Succeeded) {
                // 后台验证订单
                PaymentNetManager.verifyStripeOrder(true,mOrderId, statusData);
            } else if (status == PaymentIntent.Status.RequiresPaymentMethod) {
                errorShowAndRetry();
            }
            Logger.logE("live pay, stripe succ, status = " + status);
        }

        @Override
        public void onError(@NonNull Exception e) {
            PaymentActivity activity = activityRef.get();
            if (activity == null) {
                return;
            }
            errorShowAndRetry();

            Logger.logE("live pay, stripe succ, error = " + e.getMessage());
        }
    }

五、Google Pay配置

配置地址 https://pay.google.com/business/console/u/2/payment/BCR2DN6TZP4O3TIO
集成项目
完成Google Pay配置
完成Google Pay配置

六、完整代码

 /**
 * Description: 国际版Google Pay
 * ---------------------
 * Author: xiangpan
 * Date: 2020/10/14 6:01 PM
 */

public class GooglePayGlobe implements DefaultLifecycleObserver {
    public static final int LOAD_PAYMENT_DATA_REQUEST_CODE = 5300;
    public static final String LIVE_API = "pk_test_51Hc6UgKbT4q9TnA8xWZpZwKjXagTRmgyMC5q8HaQqgP1XmiPYRAsLCUMriIoLe5nR2gVtpRY39SeL8x7r00J3duNXzg";
    //测试 ENVIRONMENT_TEST 正式 ENVIRONMENT_PRODUCTION
    public static final int PAYMENTS_ENVIRONMENT = WalletConstants.ENVIRONMENT_TEST;

    public static final List<String> SUPPORTED_NETWORKS = Arrays.asList(
            "AMEX",
            "DISCOVER",
            "JCB",
            "MASTERCARD",
            "VISA");

    public static final List<String> SUPPORTED_METHODS = Arrays.asList(
            "PAN_ONLY",
            "CRYPTOGRAM_3DS");

    public static final String COUNTRY_CODE = "US";

    public static final String CURRENCY_CODE = "USD";
    public MutableLiveData<StripeDto> statusData = new MutableLiveData<>();
    private PaymentActivity mActivity;
    private PaymentsClient paymentsClient;
    private Stripe mStripe;
    private String mOrderId;
    private String mSecret;
    private int mCreateOrderRetryTime = 0;
    private int mVerifyOrderRetryTime = 0;
    private ChargeUnitDto mChargeUnitDto;
    private String mCouponUuid;
    private double mPrice;

    @RequiresApi(api = Build.VERSION_CODES.N)
    @Override
    public void onCreate(@NonNull LifecycleOwner owner) {
        mActivity = (com.ev.live.payment.PaymentActivity) owner;
        paymentsClient = createPaymentsClient(mActivity);
        statusData.observe(mActivity, stripeDto -> {
            if (stripeDto != null && stripeDto.code == 0) {
                Logger.logE("live pay stripe, observ " + stripeDto.isFail + " status  = " + stripeDto.status);
                if (stripeDto.status == StripeDto.STRIPE_ORDER_SUCC) {
                    mStripe = new Stripe(mActivity, LIVE_API);
                    mOrderId = stripeDto.orderId;
                    mSecret = stripeDto.client_secret;
                    mPrice = stripeDto.amount;
                    payWithGoogle(mPrice);
//                    AnalyticUtil.firebaseEvent(AnalyticUtil.STRIPE_ORDER_SUCC, getStaticsBundle());
                } else if (stripeDto.status == StripeDto.STRIPE_ORDER_FAIL) {
                    if (mCreateOrderRetryTime < 3) {
                        PaymentNetManager.requestStripeOrder(true,mChargeUnitDto.id, mCouponUuid, statusData);
                    }else {
                        stripeDto.status = StripeDto.STRIPE_ORDER_FAIL_FINAL;
                        stripeDto.isFail = true;
                        statusData.postValue(stripeDto);
                    }
                    mCreateOrderRetryTime ++;
                } else if (stripeDto.status == StripeDto.STRIPE_VERIFY_FAIL) {
                    if (mVerifyOrderRetryTime < 3) {
                        PaymentNetManager.verifyStripeOrder(true,mOrderId, statusData);
                    }
                    mVerifyOrderRetryTime++;
//                    AnalyticUtil.firebaseEvent(AnalyticUtil.STRIPE_VERIFY_FAIL, getStaticsBundle());
                }
            }
        });

    }

    @Override
    public void onDestroy(@NonNull LifecycleOwner owner) {
        mActivity = null;
    }

    /**
     * Google 支付
     * @param dto
     * @param couponUuid
     */
    public void startPayment(ChargeUnitDto dto, String couponUuid) {
        if (dto != null) {
            mChargeUnitDto = dto;
            mCouponUuid = couponUuid;
            PaymentNetManager.requestStripeOrder(true,mChargeUnitDto.id, mCouponUuid, statusData);
        }
//        AnalyticUtil.threeChannelEvent(PAYPAL_ORDER_CLICK, getStaticsBundle());
    }

    private PaymentsClient createPaymentsClient(Activity activity) {
        Wallet.WalletOptions walletOptions =
                new Wallet.WalletOptions.Builder().setEnvironment(PAYMENTS_ENVIRONMENT).build();
        return Wallet.getPaymentsClient(activity, walletOptions);
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    private void payWithGoogle( double price) {
        if (paymentsClient == null) {
            paymentsClient = createPaymentsClient(mActivity);
        }
        Optional<JSONObject> paymentDataRequestJson = createPaymentDataRequest(price);
        if (!paymentDataRequestJson.isPresent()) {
            return;
        }
        PaymentDataRequest request =
                PaymentDataRequest.fromJson(paymentDataRequestJson.get().toString());
        if (request != null) {
            if (mActivity!=null){
                mActivity.showCircle2Loading();
            }
            AutoResolveHelper.resolveTask(
                    paymentsClient.loadPaymentData(request),
                    mActivity,
                    LOAD_PAYMENT_DATA_REQUEST_CODE
            );
        }
    }

    /**
     * {
     * "apiVersionMinor": 0,
     * "apiVersion": 2,
     * "paymentMethodData": {
     * "description": "中国招商银行 (CMB) •••• 5019",
     * "tokenizationData": {
     * "type": "PAYMENT_GATEWAY",
     * "token": "{\n  \"id\": \"tok_1HcQIMBcf7rsT369XhdHf1\",\n  \"object\": \"token\",\n  \"card\": {\n    \"id\": \"card_1HcQIMBcf7rsT369lDDy6PIM\",\n    \"object\": \"card\",\n    \"address_city\": null,\n    \"address_country\": null,\n    \"address_line1\": null,\n    \"address_line1_check\": null,\n    \"address_line2\": null,\n    \"address_state\": null,\n    \"address_zip\": null,\n    \"address_zip_check\": null,\n    \"brand\": \"Visa\",\n    \"country\": \"US\",\n    \"cvc_check\": null,\n    \"dynamic_last4\": \"4242\",\n    \"exp_month\": 10,\n    \"exp_year\": 2025,\n    \"funding\": \"credit\",\n    \"last4\": \"5019\",\n    \"metadata\": {\n    },\n    \"name\": \"name\",\n    \"tokenization_method\": \"android_pay\"\n  },\n  \"client_ip\": \"173.194.101.160\",\n  \"created\": 1602744638,\n  \"livemode\": false,\n  \"type\": \"card\",\n  \"used\": false\n}\n"
     * },
     * "type": "CARD",
     * "info": {
     * "cardNetwork": "VISA",
     * "cardDetails": "5019"
     * }
     * }
     * }
     *
     * @param data
     * @param resultCode
     */
    public void onCheckResult(int resultCode,Intent data) {
        switch (resultCode) {
            case Activity.RESULT_OK: {
                onGooglePayResult(data);
                break;
            }
            case Activity.RESULT_CANCELED: {
                errorShowAndRetry();
                break;
            }
            case AutoResolveHelper.RESULT_ERROR:  {
                final Status status =
                        AutoResolveHelper.getStatusFromIntent(data);
                errorShowAndRetry();
                break;
            }
            default: {
                // Do nothing.
            }
        }

    }

    private void onGooglePayResult(@NonNull Intent data) {
        PaymentData paymentData = PaymentData.getFromIntent(data);
        if (paymentData == null) {
            errorShowAndRetry();
            return;
        }
        try {
            PaymentMethodCreateParams paymentMethodCreateParams = PaymentMethodCreateParams.createFromGooglePay(new JSONObject(paymentData.toJson()));
            mStripe.createPaymentMethod(
                    paymentMethodCreateParams,
                    new ApiResultCallback<PaymentMethod>() {
                        @Override
                        public void onSuccess(@NonNull PaymentMethod result) {
                            paymentGotoStripe(result.id);
                        }

                        @Override
                        public void onError(@NonNull Exception e) {
                            errorShowAndRetry();
                        }
                    }
            );
        } catch (Exception e) {
            errorShowAndRetry();
        }

    }

    /**
     * 得到PaymentMethodId 去stripe 支付
     */
    private void paymentGotoStripe(String id){
        if ( mStripe != null && !TextUtils.isEmpty(mSecret)) {
            ConfirmPaymentIntentParams confirmParams = ConfirmPaymentIntentParams.createWithPaymentMethodId(id, mSecret);
            mStripe.confirmPayment(mActivity, confirmParams);
            Logger.logE("live pay, click pay ---");
        } else if (mStripe == null) {
            ToastUtils.showSystemToast(R.string.payment_in_progress_tips);
            Logger.logE("live pay, click pay --- order is null");
        }
    }

    /**
     * Google --> stripe--> CallBack
     * @param requestCode
     * @param data
     */
    public void paymentResultCallback(int requestCode,Intent data){
        mStripe.onPaymentResult(requestCode, data, new PaymentResultCallback(mActivity));
    }

    /**
     * 判断用户是否支持Google pay支付
     *
     */
    @RequiresApi(api = Build.VERSION_CODES.N)
    public void possiblyShowGooglePayButton(View view) {
        if (paymentsClient == null) {
            paymentsClient = createPaymentsClient(mActivity);
        }
        final Optional<JSONObject> isReadyToPayJson = getIsReadyToPayRequest();
        if (!isReadyToPayJson.isPresent()) {
            return;
        }
        IsReadyToPayRequest request = IsReadyToPayRequest.fromJson(isReadyToPayJson.get().toString());
        Task<Boolean> task = paymentsClient.isReadyToPay(request);
        task.addOnCompleteListener(mActivity,
                new OnCompleteListener<Boolean>() {
                    @Override
                    public void onComplete(@NonNull Task<Boolean> task) {
                        if (task.isSuccessful()) {
                            if (task.getResult()) {
                                view.setVisibility(View.VISIBLE);
                            } else {
                                view.setVisibility(View.GONE);
                            }

                        } else {
                            view.setVisibility(View.GONE);
                            Log.w("isReadyToPay failed", task.getException());
                        }
                    }
                });
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    private Optional<JSONObject> createPaymentDataRequest(double priceCents) {
        try {
            JSONObject paymentDataRequest = getBaseRequest();
            // 指定是否支持 Google Pay API 所支持的一种或多种付款方式。
            paymentDataRequest.put("allowedPaymentMethods", new JSONArray().put(getCardPaymentMethod()));
            // 有关根据用户是否同意交易来为交易授权的详细信息。包含总价和价格状态
            paymentDataRequest.put("transactionInfo", getTransactionInfo(priceCents));
            //商家信息
            paymentDataRequest.put("merchantInfo", getMerchantInfo());
            paymentDataRequest.put("shippingAddressRequired", false);
            paymentDataRequest.put("emailRequired", false);
            return Optional.of(paymentDataRequest);

        } catch (JSONException e) {
            return Optional.empty();
        }
    }

    private JSONObject getCardPaymentMethod() throws JSONException {
        JSONObject cardPaymentMethod = getBaseCardPaymentMethod();
        JSONObject tokenizationSpec = new GooglePayConfig(LIVE_API).getTokenizationSpecification();
        cardPaymentMethod.put("tokenizationSpecification", tokenizationSpec);
        return cardPaymentMethod;
    }

    /**
     * 金钱信息
     */
    private JSONObject getTransactionInfo(double price) throws JSONException {
        JSONObject transactionInfo = new JSONObject();
        transactionInfo.put("totalPrice", price+"");
        transactionInfo.put("totalPriceStatus", "FINAL");
        transactionInfo.put("countryCode", COUNTRY_CODE);
        transactionInfo.put("currencyCode", CURRENCY_CODE);
        transactionInfo.put("checkoutOption", "COMPLETE_IMMEDIATE_PURCHASE");

        return transactionInfo;
    }

    /**
     * 商家信息
     * merchantId 商家Id
     */
    private JSONObject getMerchantInfo() throws JSONException {
        return new JSONObject().put("merchantName", "Guruji").put("merchantId", "BCR2DN6T4XFIT7KA");
    }


    @RequiresApi(api = Build.VERSION_CODES.N)
    private Optional<JSONObject> getIsReadyToPayRequest() {
        try {
            JSONObject isReadyToPayRequest = getBaseRequest();
            isReadyToPayRequest.put(
                    "allowedPaymentMethods", new JSONArray().put(getBaseCardPaymentMethod()));
            isReadyToPayRequest.put("existingPaymentMethodRequired", true);
            return Optional.of(isReadyToPayRequest);

        } catch (JSONException e) {
            return Optional.empty();
        }
    }

    private JSONObject getBaseCardPaymentMethod() throws JSONException {
        JSONObject cardPaymentMethod = new JSONObject();
        cardPaymentMethod.put("type", "CARD");

        JSONObject parameters = new JSONObject();
        parameters.put("allowedAuthMethods", getAllowedCardAuthMethods());
        parameters.put("allowedCardNetworks", getAllowedCardNetworks());
        // Optionally, you can add billing address/phone number associated with a CARD payment method.
        parameters.put("billingAddressRequired", false);

        cardPaymentMethod.put("parameters", parameters);

        return cardPaymentMethod;
    }

    private JSONArray getAllowedCardAuthMethods() {
        return new JSONArray(SUPPORTED_METHODS);
    }

    private JSONArray getAllowedCardNetworks() {
        return new JSONArray(SUPPORTED_NETWORKS);
    }

    private JSONObject getBaseRequest() throws JSONException {
        return new JSONObject()
                .put("apiVersion", 2)
                .put("apiVersionMinor", 0);
    }

    private Bundle getStaticsBundle() {
        Bundle bundle = new Bundle();
        if (!TextUtils.isEmpty(mOrderId)) {
            bundle.putString("order_id", mOrderId);
        }
        return bundle;
    }

    private void errorShowAndRetry () {
        StripeDto stripeDto = new StripeDto();
        stripeDto.isFail = true;
        stripeDto.status = StripeDto.STRIPE_PAY_FAIL;
       statusData.setValue(stripeDto);
    }

    private final class PaymentResultCallback implements ApiResultCallback<PaymentIntentResult> {
        @NonNull
        private final WeakReference<PaymentActivity> activityRef;

        PaymentResultCallback(@NonNull PaymentActivity activity) {
            activityRef = new WeakReference<>(activity);
        }

        @Override
        public void onSuccess(@NonNull PaymentIntentResult result) {
            PaymentActivity activity = activityRef.get();
            if (activity == null) {
                return;
            }

            PaymentIntent paymentIntent = result.getIntent();
            PaymentIntent.Status status = paymentIntent.getStatus();
            if (status == PaymentIntent.Status.Succeeded) {
                PaymentNetManager.verifyStripeOrder(true,mOrderId, statusData);
            } else if (status == PaymentIntent.Status.RequiresPaymentMethod) {
                errorShowAndRetry();
            }
            Logger.logE("live pay, stripe succ, status = " + status);
        }

        @Override
        public void onError(@NonNull Exception e) {
            PaymentActivity activity = activityRef.get();
            if (activity == null) {
                return;
            }
            errorShowAndRetry();

            Logger.logE("live pay, stripe succ, error = " + e.getMessage());
        }
    }
}



希望可以帮助遇到同样问题的你😁😁😁😁
如有建议和意见,请及时沟通。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Google Pay 谷歌支付(gateway = stripe) 的相关文章

  • zxing二维码的生成与解码(C#)(附例子)

    二维码的生成 using com google zxing qrcode using com google zxing using com google zxing common using ByteMatrix com google zx
  • Android控件之AutoCompleteTextView、MultiAutoCompleteTextView探究

    在Android中提供了两种智能输入框 它们是AutoCompleteTextView MultiAutoCompleteTextView 它们的功能大致一样 显示效果像Google搜索一样 当你在搜索框里输入一些字符时 至少两个字符 会自
  • Distcc

    由于通过google git提取的android源代码没有配置分布式编译 需要借助一些工具搭建一个分布式编译环境来提升android编译速度 下面的步骤是在centos 5 2上进行的 我们可以参考一下 1 安装distcc RPM包 rp
  • 11款插件让你的Chrome成为全世界最好用的浏览器|Chrome插件推荐

    文章来源 知乎 收录于 风云社区 SCOEE 提供mac软件下载 更多专题 可关注小编 微学徒 查看我的文章 也可上 风云社区 SCOEE 查找和下载相关软件资源 一 综合类 新买苹果电脑 mac系统中小白应该了解哪些东西 Mac新手必看教
  • 基于Spring Gateway路由判断器实现各种灰度发布场景

    文章目录 1 灰度发布实现 1 1 按随机用户的流量百分比实现灰度 1 2 按人群划分实现的灰度 1 2 1 通过Header信息实现灰度 1 2 2 通过Query信息实现灰度 1 2 3 通过RemoteAdd判断来源IP实现灰度 2
  • 比尔盖茨现身西雅图SAS 2007“治疗失眠”

    结束了4月18 21号的访华活动 比尔盖茨又现身在了西雅图5月8号开始的为时两天的第八届微软战略合作伙伴高峰会议上 Strategic Account Summit Conference 这次会议请来了众多重量级的大腕嘉宾 包括负责微软网络
  • Google人机认证解决方法

    针对Chrome浏览器 下载gooreplacer 下载地址1 下载地址2 安装 gooreplacer crx Chrome无法从该网站添加应用 扩展程序和用户脚本 将 crx后缀改为 rar 之后开发者模式安装 重定向网址 重定向 将网
  • 微服务·架构组件之网关- Spring Cloud Gateway

    微服务 架构组件之网关 Spring Cloud Gateway 引言 微服务架构已成为构建现代化应用程序的关键范式之一 它将应用程序拆分成多个小型 可独立部署的服务 Spring Cloud Gateway是Spring Cloud生态系
  • 创建Google play开发者账号,并验证身份通过

    一 注册前准备 最好准备一台没有怎么用过Google的电脑和 准备一个没有注册过Google的手机号 准备一张信用卡或者借记卡 需要支付 25 支持的类型如下图 这里还需注意 最后账号注册成功还需要验证身份也就是实名认证 那么Google去
  • 了解搜索引擎技术

    百度 Google搜索引擎核心技术是怎么实现的 搜索引擎 搜索引擎 search engine 是指根据一定的策略 运用特定的计算机程序搜集互联网上的信息 在对信息进行组织和处理后 并将处理后的信息显示给用户 是为用户提供检索服务的系统 全
  • DNS污染与DNS劫持

    先认识一下什么是DNS DNS 是域名系统 Domain Name System 的缩写 在Internet上域名与IP地址之间是一对一 或者多对一 的 域名虽然便于人们记忆 但机器之间只能互相认识IP地址 它们之间的转换工作称为域名解析
  • gateway+nacos秒级上下线

    gateway nacos秒级上下线 spring cloud gateway和nacos是我们常用的组件 如果不做处理 服务启动或停止后在gateway上并不会立即上线或者下线 带来的问题就是 部署服务的时候 要把新的服务启动 等待gat
  • 信息收集 (一)Google Hack & robots文件

    一 Google Hack 在渗透测试中 信息收集是尤为重要的一部分 甚至可以占到整个渗透的百分之六十至七十 可见掌握好信息收集的方法十分重要 那GoogleHacking作为常用且方便的信息收集搜索引擎工具 它是利用谷歌搜索强大 可以搜出
  • 以一个最简单的例子把OO的JavaScript说明白

    OO的JavaScript并不高深 麻烦就麻烦在google出来的国人介绍文章经常罗罗嗦嗦 而且之间的说法还各有不同 摆在一起就让人看了头大 这里重拾简单主义 以一个最简单的例子把OO Javascript说明白 1 一个颇为精简的例子 只
  • spring gateway 的搭建与配置

    步骤 建项目 给主启动类添加Eureka的注解 EnableEurekaClient 添加并配置application yml 第一步 新建gateway的项目 gateway 8205 需要用到的组件
  • 【历史上的今天】10 月 2 日:ENIAC 计算机退休;贝尔德发明电视;香港科技大学办学

    整理 王启隆 透过 历史上的今天 从过去看未来 从现在亦可以改变未来 今天是 2021 年 10 月 2 日 在历史上今天发生的科技关键事件不比昨天要少 举世闻名的通用电子计算机 ENIAC 便在今天退休 我国享誉世界的学府香港科技大学正式
  • SpringCloud——GateWay网关(详解+案例)

    目录 一 相关概念 1 网关概念 2 网关作用 3 网关架构图 4 网关三大核心 二 案例 1 案例说明 2 搭建GateWay网关9527服务 1 创建maven工程 2 导入依赖 3 配置application yml文件 4 创建主启
  • 微服务架构中的开发环境搭建[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我们正致力于在微服务架构中开发网络应用程序 我们考虑在 API 网关后面运行服务 该网关将处理身份验证并将请求代理到适当的服务 我们在
  • 使用 ECS 时保护来自 EC2 实例的出站流量规则

    即使我在私有子网中创建 EC2 实例 如果我想将它们注册到 ECS 集群 它们也必须能够将流量发送到 Internet 我正在使用 NAT 网关来执行此操作 但我仍然感到不安全 因为实例可以在被接管时将私人信息发送到任何地方 我可以用于实例
  • HTTP代理、隧道、网关有什么区别? [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 全部 我看到 RFC 2616 中的条款 http www w3 org Protocols rfc2616 rfc2616 sec1 html se

随机推荐