支付宝离线支付的设计需要考虑多种场景,例如用户网络异常、商家网络异常、支付数据一致性等问题。以下提供一个简单的案例。
场景案例
场景描述: 某线下商家支持支付宝离线支付,用户在手机无网络的情况下,通过生成离线支付二维码完成支付。商家设备会保存支付请求,待商家设备恢复网络后,将离线支付请求批量上传到支付宝进行处理。此设计需要保证支付数据的一致性、离线支付信息的安全性以及系统的高可用性。
功能设计
核心功能:
- 用户生成离线支付二维码,包含必要支付信息(金额、订单号等)。
- 商家扫描二维码,离线保存支付信息。
- 商家设备恢复网络后,将支付信息上传支付宝进行验证。
- 支付结果同步至用户。
系统架构
- 支付二维码生成模块:负责用户端生成支付二维码。
- 商家离线保存模块:负责商家端保存离线支付数据。
- 离线支付同步模块:负责商家恢复网络后,批量同步离线支付数据。
技术实现
以下基于Spring Boot实现。
依赖配置(pom.xml)
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.4.1</version>
</dependency>
</dependencies>
数据库模型
@Entity
@Table(name = "offline_payment")
public class OfflinePayment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String orderId;
@Column(nullable = false)
private Double amount;
@Column(nullable = false)
private String qrCode;
@Column(nullable = false)
private boolean synced = false;
// Getters and Setters
}
支付二维码生成服务
@Service
public class QRCodeService {
public String generateQRCode(String data) throws Exception {
int width = 300;
int height = 300;
Map<EncodeHintType, Object> hints = new HashMap<>();
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
BitMatrix bitMatrix = new MultiFormatWriter().encode(data, BarcodeFormat.QR_CODE, width, height, hints);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
MatrixToImageWriter.writeToStream(bitMatrix, "PNG", outputStream);
byte[] qrCodeBytes = outputStream.toByteArray();
return Base64.getEncoder().encodeToString(qrCodeBytes);
}
}
离线支付保存接口
@RestController
@RequestMapping("/api/payments")
public class OfflinePaymentController {
@Autowired
private OfflinePaymentRepository offlinePaymentRepository;
@PostMapping("/save")
public ResponseEntity<String> savePayment(@RequestBody OfflinePayment payment) {
payment.setSynced(false);
offlinePaymentRepository.save(payment);
return ResponseEntity.ok("Payment saved successfully");
}
@GetMapping("/unsynced")
public List<OfflinePayment> getUnsyncedPayments() {
return offlinePaymentRepository.findBySyncedFalse();
}
}
离线支付同步任务
@Component
public class OfflinePaymentSyncTask {
@Autowired
private OfflinePaymentRepository offlinePaymentRepository;
@Scheduled(fixedRate = 60000) // 每分钟执行一次
public void syncPayments() {
List<OfflinePayment> unsyncedPayments = offlinePaymentRepository.findBySyncedFalse();
for (OfflinePayment payment : unsyncedPayments) {
// 模拟向支付宝同步支付信息
boolean success = syncWithAlipay(payment);
if (success) {
payment.setSynced(true);
offlinePaymentRepository.save(payment);
}
}
}
private boolean syncWithAlipay(OfflinePayment payment) {
// 模拟调用支付宝API
System.out.println("Syncing payment: " + payment.getOrderId());
return true;
}
}
数据访问层
public interface OfflinePaymentRepository extends JpaRepository<OfflinePayment, Long> {
List<OfflinePayment> findBySyncedFalse();
}
应用配置(application.properties)
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.hibernate.ddl-auto=update
spring.h2.console.enabled=true
测试流程
-
生成支付二维码:
- 调用
QRCodeService
的generateQRCode
方法生成支付二维码。 - 示例数据:
{ "orderId": "123456", "amount": 100.0 }
。
- 调用
-
保存离线支付数据:
- 调用
/api/payments/save
接口保存支付信息。
- 调用
-
模拟离线状态后同步:
- 定时任务
OfflinePaymentSyncTask
会在设备网络恢复时同步未同步的支付信息。
- 定时任务
该设计实现了支付宝离线支付的核心功能,考虑了离线场景的数据存储和同步问题。系统可以进一步扩展,例如增加支付验证、用户通知等功能。