![](https://i-blog.csdnimg.cn/blog_migrate/f1c1043461d7a78e2093a6b611df272b.png)
common文件夹
package com.stop.think.shiro.common;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class PayPalConfig {
public static String CLIENT_ID;
@Value("${paypal.client.id}")
public void setClientId(String clientId) {
PayPalConfig.CLIENT_ID = clientId;
}
public static String CLIENT_SECRET;
@Value("${paypal.client.secret}")
public void setClientSecret(String clientSecret) {
PayPalConfig.CLIENT_SECRET = clientSecret;
}
public static String BRAND_NAME;
@Value("${paypal.brand.name}")
public void setBrandName(String brandName) {
PayPalConfig.BRAND_NAME = brandName;
}
public final static String LANDING_PAGE = "NO_PREFERENCE";
public final static String SHIPPING_PREFERENCE = "NO_SHIPPING";
public final static String USER_ACTION = "PAY_NOW";
public final static String INTENT = "CAPTURE";
}
package com.stop.think.shiro.common;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class ProjectConfig {
public static boolean IS_TEST = true;
@Value("${is.test}")
public void setIsTest(boolean isTest) {
IS_TEST = isTest;
}
}
DAO OrderRecord
package com.stop.think.shiro.dao.entity;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Entity
@Table
@Getter
@Setter
public class OrderRecord {
public final static String STATUS_ING = "01";
public final static String STATUS_SUC = "02";
public final static String STATUS_FAIL = "03";
@Id
private String id;
private String name;
private BigDecimal money;
/***
* 币种
*/
private String currencyCode;
private String mark;
/**
* 支付订单号
*/
@Column(nullable = false, length = 200, unique = true)
private String payOrdNo;
private LocalDateTime payDate;
private LocalDateTime createDate;
private String status;
}
package com.stop.think.shiro.dao;
import com.stop.think.shiro.dao.entity.OrderRecord;
import org.springframework.data.repository.PagingAndSortingRepository;
import java.util.Optional;
public interface OrderRecordDao extends PagingAndSortingRepository<OrderRecord, Long> {
Optional<OrderRecord> findByPayOrdNo(String payOrdNo);
}
service
package com.stop.think.shiro.service.paypal;
import com.paypal.core.PayPalEnvironment;
import com.paypal.core.PayPalHttpClient;
import com.stop.think.shiro.common.PayPalConfig;
import com.stop.think.shiro.common.ProjectConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class PayPalClient {
private static PayPalHttpClient client;
private PayPalClient() {}
public static PayPalHttpClient client() {
if (client != null) {
return client;
}
PayPalEnvironment environment = !ProjectConfig.IS_TEST ? new PayPalEnvironment.Live(PayPalConfig.CLIENT_ID, PayPalConfig.CLIENT_SECRET)
: new PayPalEnvironment.Sandbox(PayPalConfig.CLIENT_ID, PayPalConfig.CLIENT_SECRET);
client = new PayPalHttpClient(environment);
return client;
}
}
package com.stop.think.shiro.service.paypal;
import com.paypal.http.HttpResponse;
import com.paypal.orders.*;
import org.springframework.stereotype.Service;
import java.io.IOException;
@Service
public class PayPalService {
public HttpResponse<Order> captureOrder(String orderId) throws IOException {
OrdersCaptureRequest request = new OrdersCaptureRequest(orderId);
request.requestBody(buildRequestBody());
//3. Call PayPal to capture an order
HttpResponse<Order> response = PayPalClient.client().execute(request);
//4. Save the capture ID to your database. Implement logic to save capture to your database for future reference.
System.out.println("Status Code: " + response.statusCode());
System.out.println("Status: " + response.result().status());
System.out.println("Order ID: " + response.result().id());
System.out.println("Links: ");
for (LinkDescription link : response.result().links()) {
System.out.println("\t" + link.rel() + ": " + link.href());
}
System.out.println("Capture ids:");
for (PurchaseUnit purchaseUnit : response.result().purchaseUnits()) {
for (Capture capture : purchaseUnit.payments().captures()) {
System.out.println("\t" + capture.id());
}
}
System.out.println("Buyer: ");
Payer buyer = response.result().payer();
System.out.println("\tEmail Address: " + buyer.email());
System.out.println("\tName: " + buyer.name().fullName());
return response;
}
/**
*Creating empty body for capture request.
*You can set the payment source if required.
*
*@return OrderRequest request with empty body
*/
public OrderRequest buildRequestBody() {
return new OrderRequest();
}
}
package com.stop.think.shiro.service;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.paypal.http.HttpResponse;
import com.paypal.orders.*;
import com.stop.think.shiro.common.PayPalConfig;
import com.stop.think.shiro.dao.OrderRecordDao;
import com.stop.think.shiro.dao.entity.OrderRecord;
import com.stop.think.shiro.service.paypal.PayPalClient;
import com.stop.think.shiro.service.paypal.PayPalService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@Slf4j
@Service
public class OrderRecordService {
@Resource private OrderRecordDao orderRecordDao;
@Resource private PayPalService payPalService;
@Value("${domain.url}")
private String domainUrl;
public JSONObject createPayOrder() {
OrderRecord record = new OrderRecord();
record.setId(IdUtil.getSnowflake().nextIdStr());
record.setCreateDate(LocalDateTime.now());
record.setName("测试商铺");
record.setMoney(BigDecimal.ONE);
record.setCurrencyCode("USD"); // 币种
record.setStatus(OrderRecord.STATUS_ING);
JSONObject retJson = new JSONObject();
try {
retJson.set("approveUrl", this.createPayPalOrder(record));
} catch (IOException e) {
log.error("创建订单错误", e);
// 这个地方也可以进行重试
}
orderRecordDao.save(record);
return retJson;
}
private String createPayPalOrder(OrderRecord orderRecord) throws IOException {
OrdersCreateRequest request = new OrdersCreateRequest();
request.prefer("return=representation");
request.requestBody(buildRequestBody(orderRecord));
//3. Call PayPal to set up a transaction
HttpResponse<Order> response = PayPalClient.client().execute(request);
String approveUrl = "";
if (response.statusCode() == 201) {
System.out.println("Status Code: " + response.statusCode());
System.out.println("Status: " + response.result().status());
System.out.println("Order ID: " + response.result().id());
System.out.println("Links: ");
// 保存支付订单号
orderRecord.setPayOrdNo(response.result().id());
for (LinkDescription link : response.result().links()) {
System.out.println("\t" + link.rel() + ": " + link.href() + "\tCall Type: " + link.method());
if (link.rel().equals("approve")) {
approveUrl = link.href();
}
}
System.out.println("Total Amount: " + response.result().purchaseUnits().get(0).amountWithBreakdown().currencyCode()
+ " " + response.result().purchaseUnits().get(0).amountWithBreakdown().value());
}
return approveUrl;
}
private OrderRequest buildRequestBody(OrderRecord orderRecord) {
OrderRequest orderRequest = new OrderRequest();
orderRequest.checkoutPaymentIntent(PayPalConfig.INTENT);
ApplicationContext context = new ApplicationContext()
// 商家名称,展示在支付界面
.brandName(PayPalConfig.BRAND_NAME)
.landingPage(PayPalConfig.LANDING_PAGE)
.cancelUrl(domainUrl + "/pay/result") // 取消返回地址
.returnUrl(domainUrl + "/pay/result") // 支付成功返回地址
.userAction(PayPalConfig.USER_ACTION)
.shippingPreference(PayPalConfig.SHIPPING_PREFERENCE);
orderRequest.applicationContext(context);
List<PurchaseUnitRequest> purchaseUnitRequests = new ArrayList<PurchaseUnitRequest>();
PurchaseUnitRequest unitRequest = new PurchaseUnitRequest()
.customId(orderRecord.getId() + "")
// 发票标识
.invoiceId(orderRecord.getId() + "")
.amountWithBreakdown(
new AmountWithBreakdown()
.currencyCode("USD")
.value(NumberUtil.decimalFormat("###.00", orderRecord.getMoney()))
);
purchaseUnitRequests.add(unitRequest);
orderRequest.purchaseUnits(purchaseUnitRequests);
return orderRequest;
}
@Transactional(rollbackFor = Exception.class)
public boolean payNotify(String payOrdNo, boolean cancelFlag) {
if (StrUtil.isBlank(payOrdNo)) {
return false;
}
Optional<OrderRecord> orderRecordOptional = orderRecordDao.findByPayOrdNo(payOrdNo);
if (!orderRecordOptional.isPresent()) {
log.warn("单号错误:" + payOrdNo);
return false;
}
OrderRecord record = orderRecordOptional.get();
if (!record.getStatus().equals(OrderRecord.STATUS_ING)) {
return true;
}
if (cancelFlag) {
record.setPayDate(LocalDateTime.now());
record.setMark("取消支付");
orderRecordDao.save(record);
return false;
}
try {
// 核销资金
payPalService.captureOrder(payOrdNo);
} catch (IOException e) {
log.error("支付核销失败:" + payOrdNo, e);
return false;
}
record.setPayDate(LocalDateTime.now());
record.setMark("");
record.setStatus(OrderRecord.STATUS_SUC);
orderRecordDao.save(record);
return true;
}
}
web.controller
package com.stop.think.shiro.web.controller;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.stop.think.shiro.service.OrderRecordService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@RequestMapping("/pay")
public class PayPalController {
@Resource private OrderRecordService orderRecordService;
@GetMapping("/auth_url")
public JSONObject createAuthUrl() {
return orderRecordService.createPayOrder();
}
@GetMapping("/result")
public JSONObject frontReturn(String token, String PayerID) {
// 同步返回时
boolean paySuccess = orderRecordService.payNotify(token, StrUtil.isBlank(PayerID));
JSONObject retJson = new JSONObject();
retJson.set("payResult", paySuccess);
return retJson;
}
}
package com.stop.think.shiro;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
application.yml
server:
context-path: ''
port: 8093
spring:
datasource:
driver-class-name: org.h2.Driver
url: jdbc:h2:mem:myDb;DB_CLOSE_DELAY=-1
username: sa
password: sa
validationQuery: SELECT 1 FROM DUAL
http:
encoding:
force: true
jackson:
defaultPropertyInclusion: NON_NULL
jpa:
hibernate:
ddl-auto: update
properties:
hibernate:
connection:
CharSet: utf8mb4
characterEncoding: utf8mb4
useUnicode: true
format_sql: true
show-sql: true
# paypal 支付配置
paypal:
client:
id:
secret:
brand:
name: 测试商家
# domain
domain:
url: http://localhost:8093
# 环境配置
is:
test: true