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;@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的实现相关推荐
- Spring Boot 集成 Swagger 生成 RESTful API 文档
原文链接: Spring Boot 集成 Swagger 生成 RESTful API 文档 简介 Swagger 官网是这么描述它的:The Best APIs are Built with Swa ...
- Spring Boot 集成Swagger2生成RESTful API文档
Swagger2可以在写代码的同时生成对应的RESTful API文档,方便开发人员参考,另外Swagger2也提供了强大的页面测试功能来调试每个RESTful API. 使用Spring Boot可 ...
- Spring Boot集成支付宝电脑网站支付功能
Spring Boot集成支付宝电脑网站支付功能 接入准备 登录 创建应用 添加能力 生成私钥与公钥 开发设置 沙箱环境 示例Demo的使用与学习 下载Demo 启动项目 参数配置 执行测试 Spri ...
- Java集成PayPal支付
Java集成PayPal支付 1.申请账号 浏览器中输入:https://www.paypal.com,点击 "注册" 选择 "企业账号" ,信息可以随意填写 ...
- 使用Spring Boot自动发布和监视API
如果您正在沿着微服务风格的架构前进,那么您将需要接受的一个租户就是自动化. 这种架构风格介绍了许多活动部件. 如果成功,您的环境将具有大量服务API,企业可以将其用于应用程序开发和集成. 这意味着必须 ...
- Linux 安装Redis-6.2.5,配置及使用(RDB与AOF持久化、sentinel机制、主从复制、Spring Boot 集成 Redis)
CentOS 7 安装Redis-6.2.5版本 Redis采用的是基于内存的单进程 单线程模型 的KV数据库,由C语言编写.官方提供的数据是可以达到100000+的qps 应用场景: 令牌(Toke ...
- Spring Boot集成支付宝(最新版SDK)—— 手机支付
前言 前些日子写了一篇关于H5网页集成支付宝的文章: Spring Boot集成支付宝(最新版SDK)-- H5/网页支付 当时写了好久,往那一坐就是俩小时,写完直接就发布了,发布之后才感觉少点啥-- ...
- 有手就行的 Spring Boot 集成 Shiro
前言 Apache Shiro 是 Java 的一个安全框架.目前,使用 Apache Shiro 的人越来越多,因为它相当简单,对比 Spring Security,可能没有 Spring Se ...
- Spring Boot 集成SnakerFlow流程引擎,简介、功能列表、详细解读、扩展点分析
文章目录 简介 功能列表 流程定义 任务参与者 参与者设置 动态添加.删除参与者 组支持 详细解读 Spring Boot集成 表定义 表详细说明: 字段详细说明: 常见操作 常规API 综合查询 模 ...
- Spring Boot集成Swagger导入YApi@无界编程
接口APi开发现状 现在开发接口都要在类似YApi上写文档,这样方便不同的团队之间协作,同步更新接口,提高效率. 但是如果接口很多,你一个个手工在YApi去录入无疑效率很低. 如果是使用Spring ...
最新文章
- 点云数据向图像数据转换(附源码)
- 2019测试指南-测试测试原理
- 后缀为frm是什么文件_Shell 点文件可以为你做点什么
- Java 面试题全梳理
- php 安装mysql扩展注意事项
- iphone微信 h5页音乐自动播放
- Linux中vi/vim编辑器的常用命令
- mysql 在线语法检查工具_「mysql 管理工具」五大开源MySQL管理工具! - seo实验室
- 中值滤波器和双边滤波器(python实现)
- HTML+CSS+JS制作炫酷特效代码
- Filebeat日志收集
- 在计算机检索中 有哪些方法能缩小,使用“或OR”运算将同义词连接起来可以缩小检索。()...
- 基于随机森林实现特征选择降维及回归预测(Matlab代码实现)
- CVPR 2018值得一看的25篇论文,都在这里了 | 源码 解读
- tipask mysql调取dedecms_帝国CMS如何在首页调用tipask最新问题-DEDE
- 孙溟㠭篆刻《天地宽》
- Android OTA releasekey 替换
- 搭建高可用oVirt(hosted engine)
- 2种前端实现图片加水印的方式
- MES系统——工艺管理篇
热门文章
- [About Design] 各类素材网站
- Word2010为图片批量插入题注
- (dfs)[USACO3.4]“破锣摇滚”乐队 Raucous Rockers
- 史上最全的点线面距离公式与推导过程(图文介绍)
- 正负数据如何归一化_数据标准化period;归一化处理
- python因数_Python实现将一个正整数分解质因数的方法分析
- 调用支付宝第三方支付接口详解(沙箱环境)
- UVA - 10066 The Twin Towers
- 幸运大转盘抽奖逻辑实现
- 代码调用SPSS功能执行分析