Java整合PayPal支付结账和支出

本文介绍如何使用Java整合PayPal支付功能,包括创建订单、支付捕获、退款操作及支出功能的实现。

转载请表明出处 https://blog.csdn.net/Amor_Leo/article/details/117959323 谢谢

准备

一、环境准备

  1. 注册paypal账号

  2. 注册paypal开发者账号

  3. 创建两个测试用户

  4. 创建应用,生成用于测试的clientID 和 密钥

代码

PayPal官方GitHub

pom

     <properties>
        <paypal-rest.version>1.14.0</paypal-rest.version>
        <paypal-checkout.version>1.0.4</paypal-checkout.version>
        <paypal-out.version>1.1.0</paypal-out.version>
        <paypal-core.version>1.7.2</paypal-core.version>
    </properties>
    
		<!-- PayPal-->
        <dependency>
            <groupId>com.paypal.sdk</groupId>
            <artifactId>rest-api-sdk</artifactId>
            <version>${
   
   paypal-rest.version}</version>
        </dependency>
        <dependency>
            <groupId>com.paypal.sdk</groupId>
            <artifactId>checkout-sdk</artifactId>
            <version>${
   
   paypal-checkout.version}</version>
        </dependency>
        <dependency>
            <groupId>com.paypal.sdk</groupId>
            <artifactId>payouts-sdk</artifactId>
            <version>${
   
   paypal-out.version}</version>
        </dependency>
        <dependency>
            <groupId>com.paypal.sdk</groupId>
            <artifactId>paypal-core</artifactId>
            <version>${
   
   paypal-core.version}</version>
        </dependency>

yml

paypal:
  client:
    id: xxxx
    secret: xxxx
    mode: sandbox
#    mode: live

配置

import com.paypal.core.PayPalEnvironment;
import com.paypal.core.PayPalHttpClient;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.stereotype.Component;
import java.util.Iterator;

/**
 * @author LHL
 * @since 2021/6/3
 */
@Slf4j
@Component
public class PayPalClient {
   
   

    public PayPalHttpClient client(String mode, String clientId, String clientSecret) {
   
   
        log.info("mode={}, clientId={}, clientSecret={}", mode, clientId, clientSecret);
        PayPalEnvironment environment = mode.equals("live") ? new PayPalEnvironment.Live(clientId, clientSecret) : new PayPalEnvironment.Sandbox(clientId, clientSecret);
        return new PayPalHttpClient(environment);
    }

    /**
     * @param jo
     * @param pre
     * @return
     */
    public String prettyPrint(JSONObject jo, String pre) {
   
   
        Iterator<?> keys = jo.keys();
        StringBuilder pretty = new StringBuilder();
        while (keys.hasNext()) {
   
   
            String key = (String) keys.next();
            pretty.append(String.format("%s%s: ", pre, StringUtils.capitalize(key)));
            if (jo.get(key) instanceof JSONObject) {
   
   
                pretty.append(prettyPrint(jo.getJSONObject(key), pre + "\t"));
            } else if (jo.get(key) instanceof JSONArray) {
   
   
                int sno = 1;
                for (Object jsonObject : jo.getJSONArray(key)) {
   
   
                    pretty.append(String.format("\n%s\t%d:\n", pre, sno++));
                    pretty.append(prettyPrint((JSONObject) jsonObject, pre + "\t\t"));
                }
            } else {
   
   
                pretty.append(String.format("%s\n", jo.getString(key)));
            }
        }
        return pretty.toString();
    }

}

支付结账

官网

import com.paypal.http.HttpResponse;
import com.paypal.http.exceptions.SerializeException;
import com.paypal.http.serializer.Json;
import com.paypal.orders.AmountBreakdown;
import com.paypal.orders.AmountWithBreakdown;
import com.paypal.orders.ApplicationContext;
import com.paypal.orders.Capture;
import com.paypal.orders.LinkDescription;
import com.paypal.orders.Money;
import com.paypal.orders.Order;
import com.paypal.orders.OrderRequest;
import com.paypal.orders.OrdersCreateRequest;
import com.paypal.orders.OrdersGetRequest;
import com.paypal.orders.PurchaseUnitRequest;
import com.paypal.orders.Refund;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
* 创建订单
* @author LHL
**/
@Slf4j
@Component
public class CreateOrder extends PayPalClient {
   
   

	@Value("${paypal.client.id}")
	private String clientId;

	@Value("${paypal.client.secret}")
	private String clientSecret;

	/**
	 * sandbox 沙箱/ live 正式环境
	 **/
	@Value("${paypal.client.mode}")
	private String mode;

	public static final String CAPTURE = "CAPTURE";

	/**
	 * 该标签将覆盖PayPal网站上PayPal帐户中的公司名称
	 */
	public static final String BRANDNAME = "Supernote";
	/**
	 * LOGIN。当客户单击PayPal Checkout时,客户将被重定向到页面以登录PayPal并批准付款。
	 * BILLING。当客户单击PayPal Checkout时,客户将被重定向到一个页面,以输入信用卡或借记卡以及完成购买所需的其他相关账单信息
	 * NO_PREFERENCE。当客户单击“ PayPal Checkout”时,将根据其先前的交互方式将其重定向到页面以登录PayPal并批准付款,或重定向至页面以输入信用卡或借记卡以及完成购买所需的其他相关账单信息使用PayPal。
	 * 默认值:NO_PREFERENCE
	 */
	public static final String LANDINGPAGE = "NO_PREFERENCE";
	/**
	 * CONTINUE。将客户重定向到PayPal付款页面后,将出现“ 继续”按钮。当结帐流程启动时最终金额未知时,请使用此选项,并且您想将客户重定向到商家页面而不处理付款。
	 * PAY_NOW。将客户重定向到PayPal付款页面后,出现“ 立即付款”按钮。当启动结帐时知道最终金额并且您要在客户单击“ 立即付款”时立即处理付款时,请使用此选项。
	 */
	public static final String USERACTION = "PAY_NOW";

	/**
	 * 当前货币币种简称, 默认为人名币的币种 EUR CNY USD
	 */
	public static final String CURRENT_CY = "USD";

	/**
	 * GET_FROM_FILE。使用贝宝网站上客户提供的送货地址。
	 * NO_SHIPPING。从PayPal网站编辑送货地址。推荐用于数字商品
	 * SET_PROVIDED_ADDRESS。使用商家提供的地址。客户无法在PayPal网站上更改此地址
	 */
	public static final String SHIPPINGPREFERENCE = "NO_SHIPPING";

	/**
	 * 生成订单主体信息
	 * @author LHL
	 */
	private OrderRequest buildOrderRequestBody(String description, String serialNumber, String price, String cancelUrl, String successUrl) {
   
   
		OrderRequest orderRequest = new OrderRequest();
		orderRequest.checkoutPaymentIntent(CAPTURE);
		ApplicationContext applicationContext = new ApplicationContext()
				//可不要
				//.brandName(BRANDNAME)
				//.landingPage(LANDINGPAGE)
				//.cancelUrl(cancelUrl)
				//.returnUrl(successUrl)
				.userAction(USERACTION)
				.shippingPreference(SHIPPINGPREFERENCE);
		orderRequest.applicationContext(applicationContext);
		List<PurchaseUnitRequest> purchaseUnitRequests = new ArrayList<PurchaseUnitRequest>();
		PurchaseUnitRequest purchaseUnitRequest = new PurchaseUnitRequest()
				//支付描述
				.description(description)
				//(唯一)订单号
				.customId(serialNumber)
				.invoiceId(serialNumber)
				.amountWithBreakdown(new AmountWithBreakdown()
						.currencyCode(CURRENT_CY)
						//支付金额 value = itemTotal + shipping + handling + taxTotal + shippingDiscount; "220.00"
						.value(price)
						//可不要
						//.amountBreakdown(new AmountBreakdown()
						//		// itemTotal = Item[Supernote A6](value × quantity) + Item[帆布封套](value × quantity)
						//		.itemTotal(new Money().currencyCode(CURRENT_CY).value(price))
						//		.shipping(new Money().currencyCode(CURRENT_CY).value("0.00"))
						//		.handling(new Money().currencyCode(CURRENT_CY).value("0.00"))
						//		.taxTotal(new Money().currencyCode(CURRENT_CY).value("0.00"))
						//		.shippingDiscount(new Money().currencyCode(CURRENT_CY).value("0.00")))
								)
				;
		//可不要
		//.items(new ArrayList<Item>() {
   
   
		//    {
   
   
		//        add(new Item().name("Supernote A6").description("丝滑般流畅的书写体验")
		//                .unitAmount(new Money()
		//                        .currencyCode(CURRENT_CY)
		//                        .value("200.00"))
		//                .quantity("1"));
		//        add(new Item().name("帆布封套").description("黑色帆布保护封套")
		//                .unitAmount(new Money()
		//                        .currencyCode(CURRENT_CY)
		//                        .value("20.00"))
		//                .quantity("1"));
		//    }
		//})
		//.shippingDetail(new ShippingDetail()
		//        .name(new Name().fullName("RATTA"))
		//        .addressPortable(new AddressPortable()
		//                .addressLine1("梅陇镇")
		//                .addressLine2("集心路168号")
		//                .adminArea2("闵行区")
		//                .adminArea1("上海市")
		//                .postalCode("20000")
		//                .countryCode("CN")));
		purchaseUnitRequests.add(purchaseUnitRequest);
		orderRequest.purchaseUnits(purchaseUnitRequests);
		return orderRequest;
	}

	/**
	 * 创建订单的方法,返回orderId 给移动端; 再由移动端支付 付费后 ipn监听支付成功处理逻辑; 如果ipn监听失败 移动端主动调用服务端捕获captureOrder再处理逻辑
	 * @author LHL
	 */
	public String createOrder(String description, String serialNumber, String price, String cancelUrl, String successUrl) {
   
   
		OrdersCreateRequest request = new OrdersCreateRequest();
		request.header("prefer","return=representation");
		request.requestBody(buildOrderRequestBody(description, serialNumber, price, cancelUrl, successUrl));
		HttpResponse<Order> response = null;
		try {
   
   
			response = client(mode, clientId, clientSecret).execute(request);
		} catch (IOException e1) {
   
   
			try {
   
   
				log.error("第1次调用paypal订单创建失败: {}", e1.getMessage());
				response = client(mode, clientId, clientSecret).execute(request);
			} catch (Exception e) {
   
   
				try {
   
   
					log.error("第2次调用paypal订单创建失败: {}", e.getMessage());
					response = client(mode, clientId, clientSecret).execute(request);
				} catch (Exception e2) {
   
   
					log.error("第3次调用paypal订单创建失败,失败原因:{}", e2.getMessage());
				}
			}
		}
		//String approve = cancelUrl;
		String orderId = null;
		if (response.statusCode() == 201) {
   
   
			log.info("Status Code = {}, Status = {}, OrderID = {}, Intent = {}", response.statusCode(), response.result().status(), response.result().id(), response.result().checkoutPaymentIntent());
			orderId = response.result().id();
			//for (LinkDescription link : response.result().links()) {
   
   
			//log.info("Links-{}: {}    \tCall Type: {}", link.rel(), link.href(), link.method());
			//	if(link.rel().equals("approve")) {
   
   
			//		approve = link.href();
			//	}
			//}
			// 打印 需要删除
			//String totalAmount = response.result().purchaseUnits().get(0).amountWithBreakdown().currencyCode() + ":" + response.result().purchaseUnits().get(0).amountWithBreakdown().value();
			//log.info("Total Amount: {}", totalAmount);
			String json= null;
			try {
   
   
				json = new JSONObject(new Json().serialize(response.result())).toString(4);
			} catch (SerializeException e) {
   
   
				log.error("json serialize error: {}", e.getMessage());
			}
			log.info("createOrder response body: {}", json);
			return orderId;
		}
		//return approve;
		return orderId;
	}

	/**
	 * 查询订单详情
	 *
	 * @param orderId 订单id,CreateOrder 生成
	 * @author LHL
	 * */
	public Map<String, Object> testOrdersGetRequest(String orderId) {
   
   
		Map<String, Object> map = new HashMap<>(5);
		OrdersGetRequest request = new OrdersGetRequest(orderId);
		HttpResponse<Order> response = null;
		try {
   
   
			response = client(mode, clientId, clientSecret).execute(request);
		} catch (Exception e) {
   
   
			try {
   
   
				log.
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值