一、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;@Overridepublic 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();}// 支付成功,状态为=PENDINGlog.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*/@Overridepublic 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*/@Overridepublic 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*/@Overridepublic 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) {// 参数MapMap properties = request.getParameterMap();// 返回值MapMap 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的支付就这样完成了

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

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

spring boot 集成paypal支付 rest api v2的实现相关推荐

  1. Spring Boot 集成 Swagger 生成 RESTful API 文档

    原文链接: Spring Boot 集成 Swagger 生成 RESTful API 文档 简介 Swagger 官网是这么描述它的:The Best APIs are Built with Swa ...

  2. Spring Boot 集成Swagger2生成RESTful API文档

    Swagger2可以在写代码的同时生成对应的RESTful API文档,方便开发人员参考,另外Swagger2也提供了强大的页面测试功能来调试每个RESTful API. 使用Spring Boot可 ...

  3. Spring Boot集成支付宝电脑网站支付功能

    Spring Boot集成支付宝电脑网站支付功能 接入准备 登录 创建应用 添加能力 生成私钥与公钥 开发设置 沙箱环境 示例Demo的使用与学习 下载Demo 启动项目 参数配置 执行测试 Spri ...

  4. Java集成PayPal支付

    Java集成PayPal支付 1.申请账号 浏览器中输入:https://www.paypal.com,点击 "注册" 选择 "企业账号" ,信息可以随意填写 ...

  5. 使用Spring Boot自动发布和监视API

    如果您正在沿着微服务风格的架构前进,那么您将需要接受的一个租户就是自动化. 这种架构风格介绍了许多活动部件. 如果成功,您的环境将具有大量服务API,企业可以将其用于应用程序开发和集成. 这意味着必须 ...

  6. Linux 安装Redis-6.2.5,配置及使用(RDB与AOF持久化、sentinel机制、主从复制、Spring Boot 集成 Redis)

    CentOS 7 安装Redis-6.2.5版本 Redis采用的是基于内存的单进程 单线程模型 的KV数据库,由C语言编写.官方提供的数据是可以达到100000+的qps 应用场景: 令牌(Toke ...

  7. Spring Boot集成支付宝(最新版SDK)—— 手机支付

    前言 前些日子写了一篇关于H5网页集成支付宝的文章: Spring Boot集成支付宝(最新版SDK)-- H5/网页支付 当时写了好久,往那一坐就是俩小时,写完直接就发布了,发布之后才感觉少点啥-- ...

  8. 有手就行的 Spring Boot 集成 Shiro

    前言   Apache Shiro 是 Java 的一个安全框架.目前,使用 Apache Shiro 的人越来越多,因为它相当简单,对比 Spring Security,可能没有 Spring Se ...

  9. Spring Boot 集成SnakerFlow流程引擎,简介、功能列表、详细解读、扩展点分析

    文章目录 简介 功能列表 流程定义 任务参与者 参与者设置 动态添加.删除参与者 组支持 详细解读 Spring Boot集成 表定义 表详细说明: 字段详细说明: 常见操作 常规API 综合查询 模 ...

  10. Spring Boot集成Swagger导入YApi@无界编程

    接口APi开发现状 现在开发接口都要在类似YApi上写文档,这样方便不同的团队之间协作,同步更新接口,提高效率. 但是如果接口很多,你一个个手工在YApi去录入无疑效率很低. 如果是使用Spring ...

最新文章

  1. 点云数据向图像数据转换(附源码)
  2. 2019测试指南-测试测试原理
  3. 后缀为frm是什么文件_Shell 点文件可以为你做点什么
  4. Java 面试题全梳理
  5. php 安装mysql扩展注意事项
  6. iphone微信 h5页音乐自动播放
  7. Linux中vi/vim编辑器的常用命令
  8. mysql 在线语法检查工具_「mysql 管理工具」五大开源MySQL管理工具! - seo实验室
  9. 中值滤波器和双边滤波器(python实现)
  10. HTML+CSS+JS制作炫酷特效代码
  11. Filebeat日志收集
  12. 在计算机检索中 有哪些方法能缩小,使用“或OR”运算将同义词连接起来可以缩小检索。()...
  13. 基于随机森林实现特征选择降维及回归预测(Matlab代码实现)
  14. CVPR 2018值得一看的25篇论文,都在这里了 | 源码 解读
  15. tipask mysql调取dedecms_帝国CMS如何在首页调用tipask最新问题-DEDE
  16. 孙溟㠭篆刻《天地宽》
  17. Android OTA releasekey 替换
  18. 搭建高可用oVirt(hosted engine)
  19. 2种前端实现图片加水印的方式
  20. MES系统——工艺管理篇

热门文章

  1. [About Design] 各类素材网站
  2. Word2010为图片批量插入题注
  3. (dfs)[USACO3.4]“破锣摇滚”乐队 Raucous Rockers
  4. 史上最全的点线面距离公式与推导过程(图文介绍)
  5. 正负数据如何归一化_数据标准化period;归一化处理
  6. python因数_Python实现将一个正整数分解质因数的方法分析
  7. 调用支付宝第三方支付接口详解(沙箱环境)
  8. UVA - 10066 The Twin Towers
  9. 幸运大转盘抽奖逻辑实现
  10. 代码调用SPSS功能执行分析