spring boot 集成paypal支付 rest api v2的实现

一、Java支付对接

 支付方式:

标准支付主要特点是只需要集成paypal按钮,所有的付款流程由paypal控制,接入方不需要关心支付细节。当用户完成支付后,paypal会通过同步PDT或者异步IPN机制来通知接入方,这种方式比较轻量级,对接难度最小,而且对借入方的入侵较小。

快速支付相对复杂,支付过程由接入方控制,通过调用3个接口来实现。从接入方网页跳转到paypal支付页面前,第一个接口触发,用于向paypal申请支付token。接着用户进入paypal支付页面,并进行支付授权,授权接口中会提交上一步获取的支付token,这个过程由paypal控制,并且没有进行实际支付,接着接入方调用第二个接口,用于获取用户的授权信息,包括支付金额,支付产品等信息,这些基础信息核对无误后,调用第三个接口,进行实际付费扣款,扣款成功后,paypal同样会进行同步PDT和异步IPN通知,这种方式很灵活,控制力强,但编码复杂度较高,入侵性较大。从实际情况考虑,我们选择了采标标准支付方式接入paypal支付。

通知方式:paypal支付的IPN和PDT两种通知方式,IPN异步通知,可能会有时延,但可靠性高,当接入方主机不可达时,有重试机制保证IPN通知尽量抵达接入方服务器。接入方收到IPN通知后,需要对其确认。确认方法为,把接收到的IPN通知原封不动的作为请求体,调用IPN确认接口。PDT通知是是实时的,但可靠性不高,因为只会通知一次,没有重试机制,一旦接入方出现主机不可达,这样的消息将会被丢失。官方推荐,IPN通知和PDT通知最好混合使用,以满足时效性和可靠性的保证。我们采用了IPN和PDT两种通知机制。

Demo 网址:https://demo.paypal.com/c2/demo/home

V1 版本已过期,我们使用V2对接支付
V2文档: https://developer.paypal.com/docs/api/payments/v2/

二、集成paypal的准备

登录开发者中心. https://developer.paypal.com

点击右上角的按钮 “Dashboard”、进入沙箱账号面板

在左边的导航栏中点击 Sandbox 下的 Accounts、创建测试用户

登录沙箱账户、沙箱登录地址: https://www.sandbox.paypal.com 创建应用(sandbox为测试环境/live为真实环境)注 这里登录商家账户进行设置

 

 获取创建应用的clientId 和 clientSecret 

 应用详情页下方创建PDT通知路径(代码不是使用的pdt通知)

 登录沙箱账户设置项目使用的IPN通知的url

 基本设置就这些 不多少

下面开始上干货(代码)

引入maven参数

<!--PayPal-->
<dependency>
   <groupId>com.paypal.sdk</groupId>
   <artifactId>rest-api-sdk</artifactId>
   <version>1.4.2</version>
</dependency>
<dependency>
   <groupId>com.paypal.sdk</groupId>
   <artifactId>checkout-sdk</artifactId>
   <version>1.0.2</version>
</dependency>
<!--PayPal-->

yml文件配置paypal信息(email为账户商家邮箱用于检测ipn的通知数据)

 编写PayPalClient环境请求配置

package com.szylt.kidsays.project.manager.config.paypal;

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 java.util.Iterator;

@Slf4j
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();
	}
}

编写paypal的支付配置

package com.szylt.kidsays.project.manager.config.paypal;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * paypal支付配置
 */
@Component
public class PaypalConfig implements InitializingBean {
    //统一在application.yml配置文件中
    @Value("${paypal.client.mode}")
    public String mode;

    @Value("${paypal.client.app}")
    public String clientId;

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

    @Value("${paypal.client.email}")
    public String email;

    public static String MODE ;

    public static String CLIENT_ID;

    public static String CLIENT_SECRET;

    public static String EMAIL;

    @Override
    public void afterPropertiesSet() throws Exception {
        MODE = mode;
        CLIENT_ID = clientId;
        CLIENT_SECRET = clientSecret;
        EMAIL = email;
    }

}
编写paypal路径工具类
package com.szylt.kidsays.project.manager.config.util.pal;

import javax.servlet.http.HttpServletRequest;

/**
 * 路径工具
 */
public class URLUtils {

    public static String getBaseURl(HttpServletRequest request) {
        String scheme = request.getScheme();
        String serverName = request.getServerName();
        int serverPort = request.getServerPort();
        String contextPath = request.getContextPath();
        StringBuffer url =  new StringBuffer();
        url.append(scheme).append("://").append(serverName);
        if ((serverPort != 80) && (serverPort != 443)) {
            url.append(":").append(serverPort);
        }
        url.append(contextPath);
        if(url.toString().endsWith("/")){
            url.append("/");
        }
        return url.toString();
    }

}
编写请求支付所需要的PayPalCheckoutConstant常量类
package com.szylt.kidsays.project.manager.config.util.pal;

public class PayPalCheckoutConstant {

	public static final String CAPTURE = "CAPTURE";

	/**
	 * PayPal网站上PayPal帐户中的公司名称
	 */
	public static final String BRAND_NAME = "自定义名称";

	/**
	 * PayPal网站上商品名称
	 */
	public static final String DESCRIPTION = "自定义名称";

	/**
	 * 交易成功
	 */
	public static final String SUCCESS = "success";
	
	/**
	 * ipn回调,付款因退款或其他类型的冲销而被冲销。资金已从您的帐户余额中删除,并退还给买方
	 */
	public static final String PAYMENT_STATUS_REVERSED = "Reversed";
	
	/**
	 *  ipn回调, 撤销已被取消。例如,您赢得了与客户的纠纷,并且撤回的交易资金已退还给您
	 */
	public static final String PAYMENT_STATUS_CANCELED_REVERSAL = "Canceled_Reversal";
	
	/**
	 *  ipn回调,付款被拒绝
	 */
	public static final String PAYMENT_STATUS_DENIED = "Denied";
	
	/**
	 *  ipn回调, 此授权已过期,无法捕获
	 */
	public static final String PAYMENT_STATUS_EXPIRED = "Expired";
	
	/**
	 *  ipn回调,  德国的ELV付款是通过Express Checkout进行的
	 */
	public static final String PAYMENT_STATUS_CREATED = "Created";
	
	/**
	 * ipn回调, 付款失败。仅当付款是通过您客户的银行帐户进行的。
	 */
	public static final String PAYMENT_STATUS_FAILED = "Failed";
	
	/**
	 *   ipn回调,付款已被接受
	 */
	public static final String PAYMENT_STATUS_PROCESSED = "Processed";
	
	/**
	 *   ipn回调,此授权已失效
	 */
	public static final String PAYMENT_STATUS_VOIDED = "Voided";
	

}

编写paypal订单创建类CreateOrder(生成paypal订单 不是本地订单)

package com.szylt.kidsays.project.manager.config.util.pal.operation;

import com.paypal.http.HttpResponse;
import com.paypal.orders.*;
import com.szylt.kidsays.project.manager.config.paypal.PayPalClient;
import com.szylt.kidsays.project.manager.config.paypal.PaypalConfig;
import com.szylt.kidsays.project.manager.config.util.pal.PayPalCheckoutConstant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;


@Slf4j
@Component
public class CreateOrder {

	/**
	 * 生成订单主体信息
	 */
	private OrderRequest buildRequestBody(String cancelUrl,String returnUrl,String customId,String invoiceId,
										  String currencyCode,String value) {
		OrderRequest orderRequest = new OrderRequest();
		orderRequest.checkoutPaymentIntent(PayPalCheckoutConstant.CAPTURE);
		ApplicationContext applicationContext = new ApplicationContext()
				.brandName(PayPalCheckoutConstant.BRAND_NAME)
				.cancelUrl(cancelUrl).returnUrl(returnUrl);
		orderRequest.applicationContext(applicationContext);
		List<PurchaseUnitRequest> purchaseUnits = new ArrayList<>();
		purchaseUnits
				.add(new PurchaseUnitRequest()
						.description(PayPalCheckoutConstant.DESCRIPTION)
						.customId(customId) // 自定义编号 这里我放入的也是 本地订单号
						.invoiceId(invoiceId) // 本地订单号
						.amountWithBreakdown(new AmountWithBreakdown()
								.currencyCode(currencyCode)
								.value(String.valueOf(value))
						));
		orderRequest.purchaseUnits(purchaseUnits);
		return orderRequest;
	}

	/**
	 * 创建订单的方法
	 * @throws //收银台地址
	 */
	public String createOrder(String cancelUrl,String returnUrl,String customId,String invoiceId,
							  String currencyCode,String value) throws IOException {
		OrdersCreateRequest request = new OrdersCreateRequest();
		request.header("prefer","return=representation");
		request.requestBody(buildRequestBody( cancelUrl, returnUrl, customId, invoiceId,
				currencyCode, value));
		PayPalClient payPalClient = new PayPalClient();

		HttpResponse<Order> response = null;
		try {
			response = payPalClient.client(PaypalConfig.MODE, PaypalConfig.CLIENT_ID,PaypalConfig.CLIENT_SECRET).execute(request);
		} catch (IOException e1) {
			try {
				log.error("第1次调用paypal订单创建失败");
				response = payPalClient.client(PaypalConfig.MODE, PaypalConfig.CLIENT_ID,PaypalConfig.CLIENT_SECRET).execute(request);
			} catch (Exception e) {
				try {
					log.error("第2次调用paypal订单创建失败");
					response = payPalClient.client(PaypalConfig.MODE, PaypalConfig.CLIENT_ID,PaypalConfig.CLIENT_SECRET).execute(request);
				} catch (Exception e2) {
					log.error("第3次调用paypal订单创建失败,失败原因:{}", e2.getMessage());
				}
			}
		}
		String approve = "";
		if (response.statusCode() == 201) {
			log.info("Status Code = {}, Status = {}, OrderID = {}, Intent = {}", response.statusCode(), response.result().status(), response.result().id(), response.result().checkoutPaymentIntent());
			Order order = response.result();
			order.links().forEach(link -> log.info(link.rel() + " => " + link.method() + ":" + link.href()));
			//交易成功后,跳转反馈地址
			for(LinkDescription links : order.links()){
				if(links.rel().equals("approve")){
					approve = links.href();
				}
			}

		}
		return approve;
	}

}

编写paypal订单捕获类用于从用户账户扣款操作CaptureOrder

package com.szylt.kidsays.project.manager.config.util.pal.operation;

import com.paypal.http.HttpResponse;
import com.paypal.orders.*;
import com.paypal.payments.CapturesGetRequest;
import com.szylt.kidsays.project.manager.config.paypal.PayPalClient;
import com.szylt.kidsays.project.manager.config.paypal.PaypalConfig;
import com.szylt.kidsays.project.vo.paypal.PaypalVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.IOException;

@Slf4j
@Component
public class CaptureOrder extends PayPalClient {

	public OrderRequest buildRequestBody() {
		return new OrderRequest();
	}

	/**
	 * 用户授权支付成功,进行扣款操作
	 */
	public PaypalVo captureOrder(String orderId) throws IOException {
		PaypalVo paypalVo = new PaypalVo();
		OrdersCaptureRequest request = new OrdersCaptureRequest(orderId);
		request.requestBody(new OrderRequest());
		PayPalClient payPalClient = new PayPalClient();
		HttpResponse<Order> response = null;
		try {
			response = payPalClient.client(PaypalConfig.MODE, PaypalConfig.CLIENT_ID, PaypalConfig.CLIENT_SECRET).execute(request);
		} catch (IOException e1) {
			try {
				log.error("第1次调用paypal扣款失败");
				response = payPalClient.client(PaypalConfig.MODE, PaypalConfig.CLIENT_ID, PaypalConfig.CLIENT_SECRET).execute(request);
			} catch (Exception e) {
				try {
					log.error("第2次调用paypal扣款失败");
					response = payPalClient.client(PaypalConfig.MODE, PaypalConfig.CLIENT_ID, PaypalConfig.CLIENT_SECRET).execute(request);
				} catch (Exception e2) {
					log.error("第3次调用paypal扣款失败,失败原因 {}", e2.getMessage() );
				}
			}
		}
		for (PurchaseUnit purchaseUnit : response.result().purchaseUnits()) {
			for (Capture capture : purchaseUnit.payments().captures()) {
				log.info("Capture id: {}", capture.id());
				log.info("status: {}", capture.status());
				log.info("invoice_id: {}", capture.invoiceId());
				//paypal交易号
				log.info("paypal交易号" + capture.id());
				//商户订单号,之前生成的带用户ID的订单号
				log.info(capture.invoiceId());
				paypalVo.setOId(capture.invoiceId());
				paypalVo.setCaptureId(capture.id());
				if("COMPLETED".equals(capture.status())) {
					paypalVo.setIsPaySuccess("SUCCESS");
				} else if("PENDING".equals(capture.status())) {
					log.info("status_details: {}", capture.captureStatusDetails().reason());
					String reason = "PENDING";
					if(capture.captureStatusDetails() != null && capture.captureStatusDetails().reason() != null) {
						reason = capture.captureStatusDetails().reason();
					}
					// 支付成功,状态为=PENDING
					log.info("支付成功,状态为=PENDING : {}", reason);
					paypalVo.setIsPaySuccess("PENDING");
				}else {
					paypalVo.setIsPaySuccess("FAILURE");
				}
			}
		}
		return paypalVo;
	}

	/**
	 * 支付后查询扣款信息
	 */
	public Boolean getCapture(String captureId) {
		// 扣款查询
		CapturesGetRequest restRequest = new CapturesGetRequest(captureId);
		PayPalClient payPalClient = new PayPalClient();
		HttpResponse<com.paypal.payments.Capture> response = null;
		try {
			response = payPalClient.client(PaypalConfig.MODE, PaypalConfig.CLIENT_ID, PaypalConfig.CLIENT_SECRET).execute(restRequest);
		} catch (IOException e) {
			log.info("查询支付扣款失败:{}",e.getMessage());
			return false;
		}
		log.info("Capture ids: " + response.result().id());
		return true;
	}

}

PaypalVo自定义的支付返回类

package com.szylt.kidsays.project.vo.paypal;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

@Data
@ApiModel("paypal支付结果返回模型")
public class PaypalVo {
    /**
     * 捕获id 第三方id
     */
    @ApiModelProperty("捕获id 第三方id")
    private String captureId;

    /**
     * 是否支付成功(SUCCESS/PENDING/FAILURE)
     */
    @ApiModelProperty("是否支付成功(SUCCESS/PENDING/FAILURE)")
    private String isPaySuccess;

    /**
     * 本地订单号
     */
    @ApiModelProperty("本地订单号")
    private String oId;

}

现在开始编写 service吧

package com.szylt.kidsays.project.manager.paypal;

import com.paypal.base.rest.PayPalRESTException;
import com.szylt.kidsays.project.vo.paypal.PaypalVo;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * paypal支付接口
 */
public interface PaypalService {

    /**
     * 创建支付
     * @param request
     * @param oId 本地订单单号
     * @return
     */
    String createPayment(HttpServletRequest request,String oId);

    /**
     * 执行支付
     * @param token paypal支付编号id 唯一
     * @param payerID
     * @return
     * @throws
     */
    PaypalVo successPay(String token, String payerID) throws PayPalRESTException;


    /**
     * 回调
     * @param map
     */
    String callback(@SuppressWarnings("rawtypes") Map map);

}

回调数据的转换放在还后面

实现server定义的接口

package com.szylt.kidsays.project.manager.paypal.impl;

import com.paypal.base.rest.PayPalRESTException;
import com.szylt.kidsays.project.entity.HOrder;
import com.szylt.kidsays.project.manager.config.paypal.PaypalConfig;
import com.szylt.kidsays.project.manager.config.util.pal.PayPalCheckoutConstant;
import com.szylt.kidsays.project.manager.config.util.pal.URLUtils;
import com.szylt.kidsays.project.manager.config.util.pal.operation.CaptureOrder;
import com.szylt.kidsays.project.manager.config.util.pal.operation.CreateOrder;
import com.szylt.kidsays.project.mapper.HOrderMapper;
import com.szylt.kidsays.project.manager.paypal.PaypalService;
import com.szylt.kidsays.project.service.IHOrderService;
import com.szylt.kidsays.project.vo.paypal.PaypalVo;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Map;

/**
 * paypal支付接口实现
 */
@Service
@Slf4j
@AllArgsConstructor
public class PaypalServiceImpl implements PaypalService {


    private CreateOrder createOrder;
    private HOrderMapper orderMapper;
    private CaptureOrder captureOrder;
    private IHOrderService orderService;

    public static final String RETURN_URL = "paypal/return_url";
    public static final String CANCEL_URL = "paypal/cancel_url";

    /**
     * 创建支付
     * @param request
     * @param oId 本地订单单号
     * @return
     */
    @Override
    public String createPayment(HttpServletRequest request,String oId) {
        HOrder sOrder = orderMapper.findOrder(oId); // 本地订单数据
        String cancelUrl = URLUtils.getBaseURl(request) + "/" + CANCEL_URL; // 支付取消返回链接
        String returnUrl = URLUtils.getBaseURl(request) + "/" + RETURN_URL; // 支付成功返回链接
        String approve = "";
        try {
            approve = createOrder.createOrder(cancelUrl,returnUrl,sOrder.getOId(),sOrder.getOId(),"USD",String.valueOf(sOrder.getOrderPriceUsd()));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "redirect:" + approve;
    }

    /**
     * 执行支付 捕获订单进行扣款操作
     * @param token paypal支付编号id 唯一
     * @param payerID
     * @return
     * @throws
     */
    @Override
    public PaypalVo successPay(String token, String payerID) throws PayPalRESTException {
        PaypalVo result = null;
        try {
            result = captureOrder.captureOrder(token);
            captureOrder.getCapture(result.getCaptureId());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }


    /**
     * 回调
     * @param map
     */
    @Override
    public String callback(@SuppressWarnings("rawtypes") Map map) {

        log.info(map.toString());
        String outTradeNo = (String)map.get("invoice");
        String paymentStatus = (String)map.get("payment_status");
        String amount = (String)map.get("mc_gross");
        String currency = (String)map.get("mc_currency");
        String paymentId = (String)map.get("txn_id");
        String parentPaymentId = (String)map.get("parent_txn_id");
        log.info("商家订单号 = {}", outTradeNo);
        log.info("订单状态 = {}", paymentStatus);
        log.info("金额 = {}", amount);
        log.info("币种 = {}", currency);
        log.info("流水号 = {}", paymentId);
        log.info("父流水号 = {}", parentPaymentId);

        if (!PaypalConfig.EMAIL.equals((String) map.get("receiver_email"))) {
            log.info("FAIL = 商户id错误, outTradeNo = {}", outTradeNo);
            return "failure";
        }
        if("Completed".equals(paymentStatus)) {
            //进行数据库操作
            boolean result = orderService.updateOrder(outTradeNo,paymentId,"paypal支付",1);
            //
            log.info("支付成功,状态为=COMPLETED");
            return PayPalCheckoutConstant.SUCCESS;
        }
//        //退款操作不开放
//        if("Refunded".equals(paymentStatus)) {
//            //进行数据库操作
//            log.info("退款成功");
//            return PayPalCheckoutConstant.SUCCESS;
//        }
        if("Pending".equals(paymentStatus) && StringUtils.isEmpty(parentPaymentId)) {
            String pendingReason = String.valueOf(map.get("pending_reason"));
            //进行数据库操作
            log.info("订单支付成功,状态为=PENDING,产生此状态的原因是 {}", pendingReason );
            return PayPalCheckoutConstant.SUCCESS;
        }
        if(StringUtils.isEmpty(parentPaymentId)) {
            if(PayPalCheckoutConstant.PAYMENT_STATUS_REVERSED.equals(paymentStatus)
                    || PayPalCheckoutConstant.PAYMENT_STATUS_CANCELED_REVERSAL.equals(paymentStatus)
                    || PayPalCheckoutConstant.PAYMENT_STATUS_DENIED.equals(paymentStatus)) {
                String reasonCode = String.valueOf(map.get("reason_code"));
                //进行数据库操作(状态修改)
                log.info("订单异常,请尽快查看处理,状态为={},产生此状态的原因是 {} ", paymentStatus, reasonCode);
                return PayPalCheckoutConstant.SUCCESS;
            }
            if(PayPalCheckoutConstant.PAYMENT_STATUS_EXPIRED.equals(paymentStatus)
                    || PayPalCheckoutConstant.PAYMENT_STATUS_CREATED.equals(paymentStatus)
                    || PayPalCheckoutConstant.PAYMENT_STATUS_FAILED.equals(paymentStatus)
                    || PayPalCheckoutConstant.PAYMENT_STATUS_PROCESSED.equals(paymentStatus)
                    || PayPalCheckoutConstant.PAYMENT_STATUS_VOIDED.equals(paymentStatus)) {
                //进行数据库操作(状态修改)
                log.info("其他订单状态,订单异常,请尽快查看处理, 状态={}", paymentStatus);
                return PayPalCheckoutConstant.SUCCESS;
            }
        }
        return "failure";
    }
}

编写PaypalController

package com.szylt.kidsays.project.manager.controller;

import com.paypal.base.rest.PayPalRESTException;
import com.szylt.kidsays.project.manager.config.util.pal.RequestToMapUtil;
import com.szylt.kidsays.project.manager.paypal.PaypalService;
import com.szylt.kidsays.project.vo.paypal.PaypalVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * paypal支付前端控制器
 */
@Slf4j
@Api(tags = "paypal支付")
@Controller
@AllArgsConstructor
@RequestMapping("/paypal")
public class PaypalController  {

    private PaypalService paypalService;

    /**
     * 创建支付
     * @param request
     * @return
     */
    @ApiOperation("创建支付")
    @GetMapping( value = "/create_payment")
    public String payment(HttpServletRequest request,String oId) {
        return paypalService.createPayment(request,oId);
    }

    /**
     * 执行支付
     * @param token
     * @param PayerID
     * @return
     * @throws PayPalRESTException
     */
    @ApiOperation("执行支付")
    @GetMapping(value ="/return_url" )
    public String successPay(@RequestParam("token") String token, @RequestParam("PayerID") String PayerID){
        try {
            PaypalVo result = paypalService.successPay(token,PayerID);
            if("SUCCESS".equals(result.getIsPaySuccess())){
                return "redirect:/pay/list";
            }
        } catch (PayPalRESTException e) {
            e.printStackTrace();
        }
        return "redirect:/";
    }

    /**
     * ipn异步回调
     * @param request
     * @param response
     * @return
     */
    @ApiOperation(value = "ipn异步回调") //https://e4726dc5b647.ngrok.io/api/paypal/call/back
    @ResponseBody
    @PostMapping(value = "/call/back")
    public String callback(HttpServletRequest request, HttpServletResponse response) {
        return paypalService.callback(RequestToMapUtil.getParameterMap(request));
    }

}
处理ipn异步回调的Request转换为map
数据
package com.szylt.kidsays.project.manager.config.util.pal;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RequestToMapUtil {
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static Map getParameterMap(HttpServletRequest request) {
		// 参数Map
		Map properties = request.getParameterMap();
		// 返回值Map
		Map returnMap = new HashMap();
		Iterator entries = properties.entrySet().iterator();
		Map.Entry entry;
		String name = "";
		String value = "";
		while (entries.hasNext()) {
			entry = (Map.Entry) entries.next();
			name = (String) entry.getKey();
			Object valueObj = entry.getValue();
			if (null == valueObj) {
				value = "";
			} else if (valueObj instanceof String[]) {
				String[] values = (String[]) valueObj;
				for (int i = 0; i < values.length; i++) {
					value = values[i] + ",";
				}
				value = value.substring(0, value.length() - 1);
			} else {
				value = valueObj.toString();
			}
			returnMap.put(name, value);
		}
		return returnMap;
	}
	
	public static Map<String, Object> getPrepayMapInfo(String Str) {
		String notityXml = Str.replaceAll("</?xml>", "");
		Pattern pattern = Pattern.compile("<.*?/.*?>");
		Matcher matcher = pattern.matcher(notityXml);
		Pattern pattern2 = Pattern.compile("!.*]");
		Map<String, Object> mapInfo = new HashMap<>();
		while (matcher.find()) {
			String key = matcher.group().replaceAll(".*/", "");
			key = key.substring(0, key.length() - 1);
			Matcher matcher2 = pattern2.matcher(matcher.group());
			String value = matcher.group().replaceAll("</?.*?>", "");
			if (matcher2.find() && !value.equals("DATA")) {
				value = matcher2.group().replaceAll("!.*\\[", "");
				value = value.substring(0, value.length() - 2);
			}
			mapInfo.put(key, value);
		}
		return mapInfo;
	}
}

一个paypal的支付就这样完成了 

具体操作请集合公司业务情况操作

如果是是有按钮支付的请交给前端处理 后端结束通知修改数据库就可以了

  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
要在 Spring Boot 项目中集成 PayPal 支付,你可以使用 PayPal Java SDK。以下是集成 PayPal 的步骤: 1. 添加依赖:在 pom.xml 文件中添加以下依赖: ```xml <dependency> <groupId>com.paypal.sdk</groupId> <artifactId>rest-api-sdk</artifactId> <version>1.14.0</version> </dependency> ``` 2. 创建 PayPal 配置类:在你的项目中创建一个 PayPal 配置类,用于配置 PayPal 的访问凭证和其他设置。 ```java import com.paypal.base.rest.APIContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class PayPalConfig { // PayPal 配置参数 private String clientId = "YOUR_CLIENT_ID"; private String clientSecret = "YOUR_CLIENT_SECRET"; private String mode = "sandbox"; // 这里使用 sandbox 模式,可以改为 "live" 用于生产环境 @Bean public APIContext apiContext() { APIContext apiContext = new APIContext(clientId, clientSecret, mode); return apiContext; } } ``` 在上述示例中,你需要替换 YOUR_CLIENT_ID 和 YOUR_CLIENT_SECRET 为你的 PayPal 客户端 ID 和密钥。注意,这里使用了 sandbox 模式,你可以根据需要将其改为 "live" 用于生产环境。 3. 使用 PayPal API:在你的代码中,可以使用 PayPal SDK 提供的 API 来执行支付相关操作。以下是一个简单的示例: ```java import com.paypal.api.payments.*; import com.paypal.base.rest.APIContext; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class PayPalService { @Autowired private APIContext apiContext; public Payment createPayment(Double total, String currency, String cancelUrl, String successUrl) throws PayPalRESTException { Amount amount = new Amount(); amount.setCurrency(currency); amount.setTotal(String.format("%.2f", total)); Transaction transaction = new Transaction(); transaction.setAmount(amount); List<Transaction> transactions = new ArrayList<>(); transactions.add(transaction); Payer payer = new Payer(); payer.setPaymentMethod("paypal"); Payment payment = new Payment(); payment.setIntent("sale"); payment.setPayer(payer); payment.setTransactions(transactions); RedirectUrls redirectUrls = new RedirectUrls(); redirectUrls.setCancelUrl(cancelUrl); redirectUrls.setReturnUrl(successUrl); payment.setRedirectUrls(redirectUrls); return payment.create(apiContext); } public Payment executePayment(String paymentId, String payerId) throws PayPalRESTException { Payment payment = new Payment(); payment.setId(paymentId); PaymentExecution paymentExecute = new PaymentExecution(); paymentExecute.setPayerId(payerId); return payment.execute(apiContext, paymentExecute); } } ``` 在上述示例中,我们创建了一个 PayPalService 类,用于处理 PayPal 相关的操作。createPayment 方法用于创建支付请求,executePayment 方法用于执行支付。 注意,在 PayPalService 类中我们注入了之前创建的 APIContext 对象,它包含了 PayPal 的访问凭证和配置参数。 这只是一个简单的示例,你可以根据实际需求使用 PayPal SDK 提供的其他 API 来处理更复杂的支付操作。 这样,在你的 Spring Boot 项目中,你就可以集成 PayPal 支付了。使用 PayPalService 类的相应方法来创建支付请求、执行支付等操作。记得根据实际情况替换示例代码中的参数和逻辑。
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值