天天看點

java對接PayPal實作自動續費功能歡迎大家進群,一起探讨學習微信公衆号,每天給大家提供技術幹貨部落客技術平台位址部落客開源微服架構前後端分離技術部落格項目源碼位址,歡迎各位star

歡迎大家進群,一起探讨學習

java對接PayPal實作自動續費功能歡迎大家進群,一起探讨學習微信公衆号,每天給大家提供技術幹貨部落客技術平台位址部落客開源微服架構前後端分離技術部落格項目源碼位址,歡迎各位star

微信公衆号,每天給大家提供技術幹貨

java對接PayPal實作自動續費功能歡迎大家進群,一起探讨學習微信公衆号,每天給大家提供技術幹貨部落客技術平台位址部落客開源微服架構前後端分離技術部落格項目源碼位址,歡迎各位star

部落客技術平台位址

部落客開源微服架構前後端分離技術部落格項目源碼位址,歡迎各位star

由于同僚對接PayPal使用的是過期的自動續費api,很多的功能受限,是以我同僚要求我幫她整合下最新的自動續費demo,正好是國慶節有時間,是以就寫了以下案例

1.maven依賴

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.3.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.73</version>
        </dependency>
        <dependency>
            <groupId>org.json</groupId>
            <artifactId>json</artifactId>
            <version>20200518</version>
        </dependency>
        <dependency>
            <groupId>com.paypal.sdk</groupId>
            <artifactId>rest-api-sdk</artifactId>
            <version>LATEST</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
        </dependency>
    </dependencies>
           

2.由于有sdk的自動續費已經過時了,新出的自動續費還沒有java的sdk是以你需要用http的方式請求PayPal的api接口

過時的api文檔位址:

1. https://developer.paypal.com/docs/api/payments.billing-agreements/v1/
   
 2. https://developer.paypal.com/docs/api/payments.billing-plans/v1/

           

utils類

package com.ratta.util;

import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import java.util.Map;


/**
 * RestTemplate 遠端調用工具類
 *
 * @author bright
 * @createDate 2020-08-29
 */
public class RestTemplateUtils {

    private final static RestTemplate restTemplate = new RestTemplate();

    // ----------------------------------GET-------------------------------------------------------

    /**
     * GET請求調用方式
     *
     * @param url          請求URL
     * @param responseType 傳回對象類型
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> get(String url, Class<T> responseType) {
        return restTemplate.getForEntity(url, responseType);
    }

    /**
     * GET請求調用方式
     *
     * @param url          請求URL
     * @param responseType 傳回對象類型
     * @param uriVariables URL中的變量,按順序依次對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> get(String url, Class<T> responseType, Object... uriVariables) {
        return restTemplate.getForEntity(url, responseType, uriVariables);
    }

    /**
     * GET請求調用方式
     *
     * @param url          請求URL
     * @param responseType 傳回對象類型
     * @param uriVariables URL中的變量,與Map中的key對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> get(String url, Class<T> responseType, Map<String, ?> uriVariables) {
        return restTemplate.getForEntity(url, responseType, uriVariables);
    }

    /**
     * 帶請求頭的GET請求調用方式
     *
     * @param url          請求URL
     * @param headers      請求頭參數
     * @param responseType 傳回對象類型
     * @param uriVariables URL中的變量,按順序依次對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> get(String url, Map<String, String> headers, Class<T> responseType, Object... uriVariables) {
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setAll(headers);
        return get(url, httpHeaders, responseType, uriVariables);
    }

    /**
     * 帶請求頭的GET請求調用方式
     *
     * @param url          請求URL
     * @param headers      請求頭參數
     * @param responseType 傳回對象類型
     * @param uriVariables URL中的變量,按順序依次對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> get(String url, HttpHeaders headers, Class<T> responseType, Object... uriVariables) {
        HttpEntity<?> requestEntity = new HttpEntity<>(headers);
        return exchange(url, HttpMethod.GET, requestEntity, responseType, uriVariables);
    }

    /**
     * 帶請求頭的GET請求調用方式
     *
     * @param url          請求URL
     * @param headers      請求頭參數
     * @param responseType 傳回對象類型
     * @param uriVariables URL中的變量,與Map中的key對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> get(String url, Map<String, String> headers, Class<T> responseType, Map<String, ?> uriVariables) {
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setAll(headers);
        return get(url, httpHeaders, responseType, uriVariables);
    }

    /**
     * 帶請求頭的GET請求調用方式
     *
     * @param url          請求URL
     * @param headers      請求頭參數
     * @param responseType 傳回對象類型
     * @param uriVariables URL中的變量,與Map中的key對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> get(String url, HttpHeaders headers, Class<T> responseType, Map<String, ?> uriVariables) {
        HttpEntity<?> requestEntity = new HttpEntity<>(headers);
        return exchange(url, HttpMethod.GET, requestEntity, responseType, uriVariables);
    }

    // ----------------------------------POST-------------------------------------------------------

    /**
     * POST請求調用方式
     *
     * @param url          請求URL
     * @param responseType 傳回對象類型
     * @return
     */
    public static <T> ResponseEntity<T> post(String url, Class<T> responseType) {
        return restTemplate.postForEntity(url, HttpEntity.EMPTY, responseType);
    }

    /**
     * POST請求調用方式
     *
     * @param url          請求URL
     * @param requestBody  請求參數體
     * @param responseType 傳回對象類型
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> post(String url, Object requestBody, Class<T> responseType) {
        return restTemplate.postForEntity(url, requestBody, responseType);
    }

    /**
     * POST請求調用方式
     *
     * @param url          請求URL
     * @param requestBody  請求參數體
     * @param responseType 傳回對象類型
     * @param uriVariables URL中的變量,按順序依次對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> post(String url, Object requestBody, Class<T> responseType, Object... uriVariables) {
        return restTemplate.postForEntity(url, requestBody, responseType, uriVariables);
    }

    /**
     * POST請求調用方式
     *
     * @param url          請求URL
     * @param requestBody  請求參數體
     * @param responseType 傳回對象類型
     * @param uriVariables URL中的變量,與Map中的key對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> post(String url, Object requestBody, Class<T> responseType, Map<String, ?> uriVariables) {
        return restTemplate.postForEntity(url, requestBody, responseType, uriVariables);
    }

    /**
     * 帶請求頭的POST請求調用方式
     *
     * @param url          請求URL
     * @param headers      請求頭參數
     * @param requestBody  請求參數體
     * @param responseType 傳回對象類型
     * @param uriVariables URL中的變量,按順序依次對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> post(String url, Map<String, String> headers, Object requestBody, Class<T> responseType, Object... uriVariables) {
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setAll(headers);
        return post(url, httpHeaders, requestBody, responseType, uriVariables);
    }

    /**
     * 帶請求頭的POST請求調用方式
     *
     * @param url          請求URL
     * @param headers      請求頭參數
     * @param requestBody  請求參數體
     * @param responseType 傳回對象類型
     * @param uriVariables URL中的變量,按順序依次對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> post(String url, HttpHeaders headers, Object requestBody, Class<T> responseType, Object... uriVariables) {
        HttpEntity<Object> requestEntity = new HttpEntity<Object>(requestBody, headers);
        return post(url, requestEntity, responseType, uriVariables);
    }

    /**
     * 帶請求頭的POST請求調用方式
     *
     * @param url          請求URL
     * @param headers      請求頭參數
     * @param requestBody  請求參數體
     * @param responseType 傳回對象類型
     * @param uriVariables URL中的變量,與Map中的key對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> post(String url, Map<String, String> headers, Object requestBody, Class<T> responseType, Map<String, ?> uriVariables) {
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setAll(headers);
        return post(url, httpHeaders, requestBody, responseType, uriVariables);
    }

    /**
     * 帶請求頭的POST請求調用方式
     *
     * @param url          請求URL
     * @param headers      請求頭參數
     * @param requestBody  請求參數體
     * @param responseType 傳回對象類型
     * @param uriVariables URL中的變量,與Map中的key對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> post(String url, HttpHeaders headers, Object requestBody, Class<T> responseType, Map<String, ?> uriVariables) {
        HttpEntity<Object> requestEntity = new HttpEntity<Object>(requestBody, headers);
        return post(url, requestEntity, responseType, uriVariables);
    }

    /**
     * 自定義請求頭和請求體的POST請求調用方式
     *
     * @param url           請求URL
     * @param requestEntity 請求頭和請求體封裝對象
     * @param responseType  傳回對象類型
     * @param uriVariables  URL中的變量,按順序依次對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> post(String url, HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables) {
        return restTemplate.exchange(url, HttpMethod.POST, requestEntity, responseType, uriVariables);
    }

    /**
     * 自定義請求頭和請求體的POST請求調用方式
     *
     * @param url           請求URL
     * @param requestEntity 請求頭和請求體封裝對象
     * @param responseType  傳回對象類型
     * @param uriVariables  URL中的變量,與Map中的key對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> post(String url, HttpEntity<?> requestEntity, Class<T> responseType, Map<String, ?> uriVariables) {
        return restTemplate.exchange(url, HttpMethod.POST, requestEntity, responseType, uriVariables);
    }

    // ----------------------------------PUT-------------------------------------------------------

    /**
     * PUT請求調用方式
     *
     * @param url          請求URL
     * @param responseType 傳回對象類型
     * @param uriVariables URL中的變量,按順序依次對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> put(String url, Class<T> responseType, Object... uriVariables) {
        return put(url, HttpEntity.EMPTY, responseType, uriVariables);
    }

    /**
     * PUT請求調用方式
     *
     * @param url          請求URL
     * @param requestBody  請求參數體
     * @param responseType 傳回對象類型
     * @param uriVariables URL中的變量,按順序依次對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> put(String url, Object requestBody, Class<T> responseType, Object... uriVariables) {
        HttpEntity<Object> requestEntity = new HttpEntity<Object>(requestBody);
        return put(url, requestEntity, responseType, uriVariables);
    }

    /**
     * PUT請求調用方式
     *
     * @param url          請求URL
     * @param requestBody  請求參數體
     * @param responseType 傳回對象類型
     * @param uriVariables URL中的變量,與Map中的key對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> put(String url, Object requestBody, Class<T> responseType, Map<String, ?> uriVariables) {
        HttpEntity<Object> requestEntity = new HttpEntity<Object>(requestBody);
        return put(url, requestEntity, responseType, uriVariables);
    }

    /**
     * 帶請求頭的PUT請求調用方式
     *
     * @param url          請求URL
     * @param headers      請求頭參數
     * @param requestBody  請求參數體
     * @param responseType 傳回對象類型
     * @param uriVariables URL中的變量,按順序依次對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> put(String url, Map<String, String> headers, Object requestBody, Class<T> responseType, Object... uriVariables) {
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setAll(headers);
        return put(url, httpHeaders, requestBody, responseType, uriVariables);
    }

    /**
     * 帶請求頭的PUT請求調用方式
     *
     * @param url          請求URL
     * @param headers      請求頭參數
     * @param requestBody  請求參數體
     * @param responseType 傳回對象類型
     * @param uriVariables URL中的變量,按順序依次對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> put(String url, HttpHeaders headers, Object requestBody, Class<T> responseType, Object... uriVariables) {
        HttpEntity<Object> requestEntity = new HttpEntity<Object>(requestBody, headers);
        return put(url, requestEntity, responseType, uriVariables);
    }

    /**
     * 帶請求頭的PUT請求調用方式
     *
     * @param url          請求URL
     * @param headers      請求頭參數
     * @param requestBody  請求參數體
     * @param responseType 傳回對象類型
     * @param uriVariables URL中的變量,與Map中的key對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> put(String url, Map<String, String> headers, Object requestBody, Class<T> responseType, Map<String, ?> uriVariables) {
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setAll(headers);
        return put(url, httpHeaders, requestBody, responseType, uriVariables);
    }

    /**
     * 帶請求頭的PUT請求調用方式
     *
     * @param url          請求URL
     * @param headers      請求頭參數
     * @param requestBody  請求參數體
     * @param responseType 傳回對象類型
     * @param uriVariables URL中的變量,與Map中的key對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> put(String url, HttpHeaders headers, Object requestBody, Class<T> responseType, Map<String, ?> uriVariables) {
        HttpEntity<Object> requestEntity = new HttpEntity<Object>(requestBody, headers);
        return put(url, requestEntity, responseType, uriVariables);
    }

    /**
     * 自定義請求頭和請求體的PUT請求調用方式
     *
     * @param url           請求URL
     * @param requestEntity 請求頭和請求體封裝對象
     * @param responseType  傳回對象類型
     * @param uriVariables  URL中的變量,按順序依次對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> put(String url, HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables) {
        return restTemplate.exchange(url, HttpMethod.PUT, requestEntity, responseType, uriVariables);
    }

    /**
     * 自定義請求頭和請求體的PUT請求調用方式
     *
     * @param url           請求URL
     * @param requestEntity 請求頭和請求體封裝對象
     * @param responseType  傳回對象類型
     * @param uriVariables  URL中的變量,與Map中的key對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> put(String url, HttpEntity<?> requestEntity, Class<T> responseType, Map<String, ?> uriVariables) {
        return restTemplate.exchange(url, HttpMethod.PUT, requestEntity, responseType, uriVariables);
    }

    // ----------------------------------DELETE-------------------------------------------------------

    /**
     * DELETE請求調用方式
     *
     * @param url          請求URL
     * @param responseType 傳回對象類型
     * @param uriVariables URL中的變量,按順序依次對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> delete(String url, Class<T> responseType, Object... uriVariables) {
        return delete(url, HttpEntity.EMPTY, responseType, uriVariables);
    }

    /**
     * DELETE請求調用方式
     *
     * @param url          請求URL
     * @param responseType 傳回對象類型
     * @param uriVariables URL中的變量,與Map中的key對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> delete(String url, Class<T> responseType, Map<String, ?> uriVariables) {
        return delete(url, HttpEntity.EMPTY, responseType, uriVariables);
    }

    /**
     * DELETE請求調用方式
     *
     * @param url          請求URL
     * @param requestBody  請求參數體
     * @param responseType 傳回對象類型
     * @param uriVariables URL中的變量,按順序依次對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> delete(String url, Object requestBody, Class<T> responseType, Object... uriVariables) {
        HttpEntity<Object> requestEntity = new HttpEntity<Object>(requestBody);
        return delete(url, requestEntity, responseType, uriVariables);
    }

    /**
     * DELETE請求調用方式
     *
     * @param url          請求URL
     * @param requestBody  請求參數體
     * @param responseType 傳回對象類型
     * @param uriVariables URL中的變量,與Map中的key對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> delete(String url, Object requestBody, Class<T> responseType, Map<String, ?> uriVariables) {
        HttpEntity<Object> requestEntity = new HttpEntity<Object>(requestBody);
        return delete(url, requestEntity, responseType, uriVariables);
    }

    /**
     * 帶請求頭的DELETE請求調用方式
     *
     * @param url          請求URL
     * @param headers      請求頭參數
     * @param responseType 傳回對象類型
     * @param uriVariables URL中的變量,按順序依次對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> delete(String url, Map<String, String> headers, Class<T> responseType, Object... uriVariables) {
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setAll(headers);
        return delete(url, httpHeaders, responseType, uriVariables);
    }

    /**
     * 帶請求頭的DELETE請求調用方式
     *
     * @param url          請求URL
     * @param headers      請求頭參數
     * @param responseType 傳回對象類型
     * @param uriVariables URL中的變量,按順序依次對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> delete(String url, HttpHeaders headers, Class<T> responseType, Object... uriVariables) {
        HttpEntity<Object> requestEntity = new HttpEntity<Object>(headers);
        return delete(url, requestEntity, responseType, uriVariables);
    }

    /**
     * 帶請求頭的DELETE請求調用方式
     *
     * @param url          請求URL
     * @param headers      請求頭參數
     * @param responseType 傳回對象類型
     * @param uriVariables URL中的變量,與Map中的key對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> delete(String url, Map<String, String> headers, Class<T> responseType, Map<String, ?> uriVariables) {
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setAll(headers);
        return delete(url, httpHeaders, responseType, uriVariables);
    }

    /**
     * 帶請求頭的DELETE請求調用方式
     *
     * @param url          請求URL
     * @param headers      請求頭參數
     * @param responseType 傳回對象類型
     * @param uriVariables URL中的變量,與Map中的key對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> delete(String url, HttpHeaders headers, Class<T> responseType, Map<String, ?> uriVariables) {
        HttpEntity<Object> requestEntity = new HttpEntity<Object>(headers);
        return delete(url, requestEntity, responseType, uriVariables);
    }

    /**
     * 帶請求頭的DELETE請求調用方式
     *
     * @param url          請求URL
     * @param headers      請求頭參數
     * @param requestBody  請求參數體
     * @param responseType 傳回對象類型
     * @param uriVariables URL中的變量,按順序依次對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> delete(String url, Map<String, String> headers, Object requestBody, Class<T> responseType, Object... uriVariables) {
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setAll(headers);
        return delete(url, httpHeaders, requestBody, responseType, uriVariables);
    }

    /**
     * 帶請求頭的DELETE請求調用方式
     *
     * @param url          請求URL
     * @param headers      請求頭參數
     * @param requestBody  請求參數體
     * @param responseType 傳回對象類型
     * @param uriVariables URL中的變量,按順序依次對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> delete(String url, HttpHeaders headers, Object requestBody, Class<T> responseType, Object... uriVariables) {
        HttpEntity<Object> requestEntity = new HttpEntity<Object>(requestBody, headers);
        return delete(url, requestEntity, responseType, uriVariables);
    }

    /**
     * 帶請求頭的DELETE請求調用方式
     *
     * @param url          請求URL
     * @param headers      請求頭參數
     * @param requestBody  請求參數體
     * @param responseType 傳回對象類型
     * @param uriVariables URL中的變量,與Map中的key對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> delete(String url, Map<String, String> headers, Object requestBody, Class<T> responseType, Map<String, ?> uriVariables) {
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setAll(headers);
        return delete(url, httpHeaders, requestBody, responseType, uriVariables);
    }

    /**
     * 帶請求頭的DELETE請求調用方式
     *
     * @param url          請求URL
     * @param headers      請求頭參數
     * @param requestBody  請求參數體
     * @param responseType 傳回對象類型
     * @param uriVariables URL中的變量,與Map中的key對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> delete(String url, HttpHeaders headers, Object requestBody, Class<T> responseType, Map<String, ?> uriVariables) {
        HttpEntity<Object> requestEntity = new HttpEntity<Object>(requestBody, headers);
        return delete(url, requestEntity, responseType, uriVariables);
    }

    /**
     * 自定義請求頭和請求體的DELETE請求調用方式
     *
     * @param url           請求URL
     * @param requestEntity 請求頭和請求體封裝對象
     * @param responseType  傳回對象類型
     * @param uriVariables  URL中的變量,按順序依次對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> delete(String url, HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables) {
        return restTemplate.exchange(url, HttpMethod.DELETE, requestEntity, responseType, uriVariables);
    }

    /**
     * 自定義請求頭和請求體的DELETE請求調用方式
     *
     * @param url           請求URL
     * @param requestEntity 請求頭和請求體封裝對象
     * @param responseType  傳回對象類型
     * @param uriVariables  URL中的變量,與Map中的key對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> delete(String url, HttpEntity<?> requestEntity, Class<T> responseType, Map<String, ?> uriVariables) {
        return restTemplate.exchange(url, HttpMethod.DELETE, requestEntity, responseType, uriVariables);
    }

    // ----------------------------------通用方法-------------------------------------------------------

    /**
     * 通用調用方式
     *
     * @param url           請求URL
     * @param method        請求方法類型
     * @param requestEntity 請求頭和請求體封裝對象
     * @param responseType  傳回對象類型
     * @param uriVariables  URL中的變量,按順序依次對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables) {
        return restTemplate.exchange(url, method, requestEntity, responseType, uriVariables);
    }

    /**
     * 通用調用方式
     *
     * @param url           請求URL
     * @param method        請求方法類型
     * @param requestEntity 請求頭和請求體封裝對象
     * @param responseType  傳回對象類型
     * @param uriVariables  URL中的變量,與Map中的key對應
     * @return ResponseEntity 響應對象封裝類
     */
    public static <T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity, Class<T> responseType, Map<String, ?> uriVariables) {
        return restTemplate.exchange(url, method, requestEntity, responseType, uriVariables);
    }

    /**
     * 擷取RestTemplate執行個體對象,可自由調用其方法
     *
     * @return RestTemplate執行個體對象
     */
    public static RestTemplate getRestTemplate() {
        return restTemplate;
    }

}
           

3.BO類

ApplicationContextBO

package com.ratta.bo;

import lombok.Data;

import java.io.Serializable;

/**
 * @author: bright
 * @date:Created in 2020/10/6 18:50
 * @describe :
 */
@Data
public class ApplicationContextBO implements Serializable {
    /**
     * 該标簽将覆寫PayPal網站上PayPal帳戶中的公司名稱
     */
    private String brand_name;

    /**
     * 貝寶付款體驗顯示的BCP 47格式的頁面區域設定。PayPal支援五個字元的代碼。
     * 例如,da-DK,he-IL,id-ID,ja-JP,no-NO,pt-BR,ru-RU,sv-SE,th-TH,zh-CN,zh-HK,或zh-TW。
     */
    private String locale;

    /**
     * 送貨位址的來源位置。 可能的值為:
     * GET_FROM_FILE。在貝寶網站上獲得客戶提供的送貨位址。
     * NO_SHIPPING。從PayPal網站編輯送貨位址。推薦用于數字商品。
     * SET_PROVIDED_ADDRESS。擷取商家提供的位址。客戶無法在PayPal網站上更改此位址。如果商家未通過位址,則客戶可以在PayPal頁面上選擇位址。
     * 預設值:GET_FROM_FILE。
     */
    private String shipping_preference;

    /**
     * 将标簽名稱配置為訂閱同意體驗Continue或Subscribe Now為訂閱同意體驗配置。 可能的值為:
     * CONTINUE。将客戶重定向到PayPal訂閱同意頁面後,将出現“繼續”按鈕。當您要控制訂閱的激活并且不希望PayPal激活訂閱時,請使用此選項。
     * SUBSCRIBE_NOW。将客戶重定向到PayPal訂閱同意頁面後,将顯示立即訂閱按鈕。當您希望貝寶激活訂閱時,請使用此選項。
     * 預設值:SUBSCRIBE_NOW
     */
    private String user_action;


    /**
     * 客戶和商家的付款首選項。目前僅支援PAYPAL付款方式。
     */
    private PaymentMethodBO payment_method;

    /**
     * 客戶準許付款後将客戶重定向到的URL
     */
    private String return_url;

    /**
     * 客戶取消付款後,将客戶重定向到的URL
     */
    private String cancel_url;

}

           

BillingCyclesBO

package com.ratta.bo;

import lombok.Data;

import java.io.Serializable;

/**
 * @author: bright
 * @date:Created in 2020/10/6 16:54
 * @describe :
 */
@Data
public class BillingCyclesBO implements Serializable {


    private PricingSchemeBO pricing_scheme;

    /**
     * 此結算周期的頻率詳細資訊。
     */
    private FrequencyBO frequency;

    /**
     * 計費周期的任期類型。如果計劃具有試用周期,則每個計劃僅允許2個試用周期。 可能的值為:
     * REGULAR。定期的結算周期。
     * TRIAL。試用帳單周期。
     */
    private String tenure_type;

    /**
     * 在其他計費周期中,該周期的運作順序。例如,試用計費周期的sequence值為,
     * 1而普通計費周期的的sequence值為2,是以試用周期在正常周期之前運作。
     */
    private Integer sequence;

    /**
     * 此計費周期執行的次數。試驗結算周期才能執行的有限次數(間值1和999對total_cycles)。
     * 定期計費周期可以執行無限倍(值0對total_cycles)或有限次數(間值1和999對total_cycles)
     */
    private Integer total_cycles;
}

           

FixedPriceBO

package com.ratta.bo;

import lombok.Data;

import java.io.Serializable;

/**
 * @author: bright
 * @date:Created in 2020/10/6 17:08
 * @describe :
 */
@Data
public class FixedPriceBO implements Serializable {
    /**
     * 辨別貨币的三字元ISO-4217貨币代碼。
     */
    private String currency_code;

    /**
     * 該值可能是:
     * 整數,例如: JPY此類通常不是小數。
     * TND此類貨币的小數部分可細分為千分之一。
     * 有關貨币代碼所需的小數位數
     */
    private String value;
}

           

FrequencyBO

package com.ratta.bo;

import lombok.Data;

import java.io.Serializable;

/**
 * @author: bright
 * @date:Created in 2020/10/6 16:57
 * @describe :
 */
@Data
public class FrequencyBO implements Serializable {
    /**
     * 訂閱收費或計費的時間間隔。 可能的值為:
     * DAY。每日結算周期。
     * WEEK。每周結算周期。
     * MONTH。每月結算周期。
     * YEAR。每年的帳單周期。
     */
    private String interval_unit;

    /**
     * 訂閱者計費之後的時間間隔數。例如,如果interval_unit是DAY用interval_count的 2,
     * 該訂閱收費每兩天一次。下表列出了最大允許值interval_count的每個interval_unit
     */
    private Integer interval_count;
}

           

PaymentMethodBO

package com.ratta.bo;

import lombok.Data;

import java.io.Serializable;

/**
 * @author: bright
 * @date:Created in 2020/10/6 19:01
 * @describe :
 */
@Data
public class PaymentMethodBO implements Serializable {
    /**
     * 客戶在商家站點上選擇的付款方式。
     * 預設值:PAYPAL。
     */
    private String payer_selected;

    /**
     * 商家首選的付款方式。 可能的值為:
     * UNRESTRICTED。接受來自客戶的任何類型的付款。
     * IMMEDIATE_PAYMENT_REQUIRED。僅接受客戶的即時付款。例如,
     * 信用卡,貝寶餘額或即時ACH。確定在捕獲時,付款不具有“待處理”狀态。
     * 預設值:UNRESTRICTED。
     */
    private String payee_preferred;
}

           

PaymentPreferencesBO

package com.ratta.bo;

import lombok.Data;

import java.io.Serializable;

/**
 * @author: bright
 * @date:Created in 2020/10/6 17:11
 * @describe :
 */
@Data
public class PaymentPreferencesBO implements Serializable {
    /**
     * 服務的初始設定費用
     */
    private SetupFeeBO setup_fee;

}

           

PlanBO

package com.ratta.bo;

import lombok.Data;

import java.io.Serializable;

/**
 * @author: bright
 * @date:Created in 2020/10/6 16:52
 * @describe :
 */
@Data
public class PlanBO implements Serializable {
    /**
     * 産品的ID。
     */
    private String product_id;

    /**
     * 計劃名稱。
     */
    private String name;

    /**
     * 計劃的詳細說明。
     */
    private String description;

    /**
     * 用于試用計費和正常計費的一系列計費周期。一個計劃最多可以有兩個試用周期,而隻有一個正常周期
     */
    private BillingCyclesBO[] billing_cycles;

    /**
     * 訂閱的付款首選項。
     */
    private PaymentPreferencesBO payment_preferences;
}

           

PricingSchemeBO

package com.ratta.bo;

import lombok.Data;

import java.io.Serializable;

/**
 * @author: bright
 * @date:Created in 2020/10/6 17:07
 * @describe :
 */
@Data
public class PricingSchemeBO implements Serializable {
    /**
     * 訂閱收取的固定金額。固定金額的更改适用于現有和将來的訂閱。
     * 對于現有訂閱,價格更改後10天内的付款不受影響
     */
    private FixedPriceBO fixed_price;
}

           

ProductsBO

package com.ratta.bo;

import lombok.Data;

import java.io.Serializable;

/**
 * @author: bright
 * @date:Created in 2020/10/6 15:51
 * @describe :
 */
@Data
public class ProductsBO implements Serializable {
    private String name;
    private String description;
    private String type;
    private String category;
    private String image_url;
    private String home_url;
}

           

SetupFeeBO

package com.ratta.bo;

import lombok.Data;

import java.io.Serializable;

/**
 * @author: bright
 * @date:Created in 2020/10/6 17:13
 * @describe :
 */
@Data
public class SetupFeeBO implements Serializable {
    /**
     * 辨別貨币的三字元ISO-4217貨币代碼。
     */
    private String currency_code;

    /**
     * 該值可能是:
     * 整數,例如: JPY此類通常不是小數。
     * TND此類貨币的小數部分可細分為千分之一。
     * 有關貨币代碼所需的小數位數
     */
    private String value;

}

           

SubscriptionsBO

package com.ratta.bo;

import lombok.Data;

import java.io.Serializable;

/**
 * @author: bright
 * @date:Created in 2020/10/6 18:42
 * @describe :
 */
@Data
public class SubscriptionsBO implements Serializable {
    /**
     * 計劃的ID。
     */
    private String plan_id;

    /**
     * 訂閱開始的日期和時間
     */
    private String start_time;

    /**
     * 應用程式上下文,可在使用PayPal進行訂閱準許過程中自定義付款人的體驗
     */
    private ApplicationContextBO application_context;

}

           

4.建立産品

4.1PayPalClient

package com.ratta.pay;

import com.paypal.base.rest.OAuthTokenCredential;
import com.paypal.base.rest.PayPalRESTException;
import org.springframework.http.HttpHeaders;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * @author: bright
 * @date:Created in 2020/10/6 15:40
 * @describe :
 */
public class PayPalClient {
    public static String getAccessToken() throws PayPalRESTException {
        Map<String, String> configurationMap = new HashMap<String, String>();
        configurationMap.put("service.EndPoint",
                "https://api.sandbox.paypal.com");
        OAuthTokenCredential merchantTokenCredential = new OAuthTokenCredential(
                "ARGZmv8TNRTjnyqnQe7xtJz04Ac15ul4V3HOtrWXezi9VhB_BQciFA5lUvqAC2nMvOC1IbAUGh34QYPb", "EPxpigopwLf5x3PuNZX5t2xWJB3BuGuxQe4EguvLiRDMKINO-amP29LATnep5uhX3YHIYR2YzCfUKKii", configurationMap);
        String accessToken = merchantTokenCredential.getAccessToken();
        return accessToken;
    }

    public static HttpHeaders setHttpHeaders() throws PayPalRESTException {
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.set("Content-Type", "application/json");
        httpHeaders.set("Authorization", getAccessToken());
        httpHeaders.set("PayPal-Request-Id", UUID.randomUUID().toString());
        return httpHeaders;
    }
}

           

4.2CreateProducts

package com.ratta.pay;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.paypal.base.rest.PayPalRESTException;
import com.ratta.bo.ProductsBO;
import com.ratta.util.RestTemplateUtils;
import org.springframework.http.ResponseEntity;

/**
 * @author: bright
 * @date:Created in 2020/10/6 16:32
 * @describe : 建立産品
 */
public class CreateProducts {
    public static String CreateProducts(ProductsBO products) throws PayPalRESTException {
        ResponseEntity<String> responseEntity = RestTemplateUtils.post("https://api.sandbox.paypal.com/v1/catalogs/products", PayPalClient.setHttpHeaders(), products, String.class);
        JSONObject jsonObject = JSONArray.parseObject(responseEntity.getBody());
        return jsonObject.get("id").toString();
    }

    public static void main(String[] args) throws PayPalRESTException {
        ProductsBO products = new ProductsBO();
        products.setName("超級會員一個月");
        products.setDescription("超級會員一個月");
        products.setCategory("SOFTWARE");
        products.setType("SERVICE");
        products.setImage_url("https://member.quicktvod.com/static/img/Mexico.jpg");
        products.setHome_url("https://member.quicktvod.com/static/img/Mexico.jpg");
        String id = CreateProducts.CreateProducts(products);
        System.out.println(id);
    }
}

           

4.3 CreatePlan

package com.ratta.pay;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.paypal.base.rest.PayPalRESTException;
import com.ratta.bo.*;
import com.ratta.util.RestTemplateUtils;
import org.springframework.http.ResponseEntity;

/**
 * @author: bright
 * @date:Created in 2020/10/6 17:16
 * @describe :  建立計費計劃
 */
public class CreatePlan {
    public static String createPlan(PlanBO plan) throws PayPalRESTException {
        ResponseEntity<String> responseEntity = RestTemplateUtils.post("https://api.sandbox.paypal.com/v1/billing/plans", PayPalClient.setHttpHeaders(), plan, String.class);
        JSONObject jsonObject = JSONArray.parseObject(responseEntity.getBody());
        return jsonObject.get("id").toString();
    }

    public static void main(String[] args) throws PayPalRESTException {
        PlanBO plan = new PlanBO();
        //CreateProducts擷取的産品id
        plan.setProduct_id("PROD-3C545082EG6201054");
        plan.setName("super服務一個月");
        plan.setDescription("自動續費");
        BillingCyclesBO billingCycles = new BillingCyclesBO();
        FrequencyBO frequency = new FrequencyBO();
        //設定付款頻率
        frequency.setInterval_unit("DAY");
        frequency.setInterval_count(1);
        billingCycles.setFrequency(frequency);

        PricingSchemeBO pricingScheme = new PricingSchemeBO();
        FixedPriceBO fixedPrice = new FixedPriceBO();
        fixedPrice.setCurrency_code("USD");
        fixedPrice.setValue("10");
        pricingScheme.setFixed_price(fixedPrice);
        billingCycles.setPricing_scheme(pricingScheme);

        billingCycles.setTotal_cycles(36);
        billingCycles.setSequence(1);
        billingCycles.setTenure_type("REGULAR");
        BillingCyclesBO[] billingCyclesArray = {billingCycles};
        plan.setBilling_cycles(billingCyclesArray);
        //設定初始金額
        PaymentPreferencesBO paymentPreferences = new PaymentPreferencesBO();
        SetupFeeBO setupFee = new SetupFeeBO();
        setupFee.setCurrency_code("USD");
        setupFee.setValue("10");
        paymentPreferences.setSetup_fee(setupFee);
        plan.setPayment_preferences(paymentPreferences);
        String id = createPlan(plan);
        System.out.println(id);
    }
}

           

4.4 CreateSubscriptions

package com.ratta.pay;

import com.paypal.base.rest.PayPalRESTException;
import com.ratta.bo.ApplicationContextBO;
import com.ratta.bo.PaymentMethodBO;
import com.ratta.bo.SubscriptionsBO;
import com.ratta.util.RestTemplateUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.http.ResponseEntity;

import java.util.HashMap;
import java.util.Map;

/**
 * @author: bright
 * @date:Created in 2020/10/6 18:37
 * @describe : 建立訂閱
 */
public class CreateSubscriptions {
    public static Map<String, String> createSubscriptions(SubscriptionsBO subscriptions) throws PayPalRESTException {
        Map<String, String> map = new HashMap<>();
        ResponseEntity<String> responseEntity = RestTemplateUtils.post("https://api.sandbox.paypal.com/v1/billing/subscriptions", PayPalClient.setHttpHeaders(), subscriptions, String.class);
        org.json.JSONObject jsonObject = new org.json.JSONObject(responseEntity.getBody());
        JSONArray object = (org.json.JSONArray) jsonObject.get("links");
        String url = "";
        for (Object o : object) {
            JSONObject jsonObj = (JSONObject) o;
            if (jsonObj.get("rel").toString().equals("approve")) {
                url = jsonObj.get("href").toString();
            }
        }
        map.put("id", jsonObject.get("id").toString());
        map.put("url", url);
        return map;
    }

    public static void main(String[] args) throws PayPalRESTException {
        SubscriptionsBO subscriptions = new SubscriptionsBO();
        subscriptions.setPlan_id("P-583780980U484121DL56REYY");
        subscriptions.setStart_time("2020-10-08T23:50:00Z");
        ApplicationContextBO applicationContext = new ApplicationContextBO();
        applicationContext.setBrand_name("yoostar");
        applicationContext.setCancel_url("https://www.example.com");
        applicationContext.setReturn_url("https://www.example.com");
        applicationContext.setLocale("en-US");
        applicationContext.setUser_action("SUBSCRIBE_NOW");
        applicationContext.setShipping_preference("GET_FROM_FILE");
        PaymentMethodBO paymentMethod = new PaymentMethodBO();
        paymentMethod.setPayee_preferred("UNRESTRICTED");
        paymentMethod.setPayer_selected("PAYPAL");
        applicationContext.setPayment_method(paymentMethod);
        subscriptions.setApplication_context(applicationContext);
        Map<String, String> map = createSubscriptions(subscriptions);
        System.out.println(map.get("id"));
        System.out.println(map.get("url"));

    }
}

           

4.5 CancelSubscriptions

package com.ratta.pay;

import com.paypal.base.rest.PayPalRESTException;
import com.ratta.util.RestTemplateUtils;
import org.springframework.http.ResponseEntity;

/**
 * @author: bright
 * @date:Created in 2020/10/7 8:32
 * @describe : 取消訂閱
 */
public class CancelSubscriptions {
    public static void cancelSubscriptions(String subscriptionsId) throws PayPalRESTException {
        RestTemplateUtils.post("https://api.sandbox.paypal.com/v1/billing/subscriptions/" + subscriptionsId + "/cancel", PayPalClient.setHttpHeaders(), "", String.class);
    }

    public static void main(String[] args) throws PayPalRESTException {
        cancelSubscriptions("I-GX16952AV2TL");
    }
}

           

5.官方文檔位址

1. https://developer.paypal.com/docs/subscriptions/integrate/#5-go-live
 2. https://developer.paypal.com/docs/api/subscriptions/v1/

           
java對接PayPal實作自動續費功能歡迎大家進群,一起探讨學習微信公衆号,每天給大家提供技術幹貨部落客技術平台位址部落客開源微服架構前後端分離技術部落格項目源碼位址,歡迎各位star
java對接PayPal實作自動續費功能歡迎大家進群,一起探讨學習微信公衆号,每天給大家提供技術幹貨部落客技術平台位址部落客開源微服架構前後端分離技術部落格項目源碼位址,歡迎各位star

git位址: https://gitee.com/bright-boy/paypal.git

QQ 694475668 歡迎各位打賞一下哦