使用沙箱环境实现支付宝支付功能
支付宝作为中国最大的第三方支付平台之一,为电商和各类应用提供了便捷的支付解决方案。在开发阶段,尤其是个人开发者通常无法直接申请支付宝商户号,因此需要使用支付宝提供的沙箱环境进行开发和测试。本教程将详细介绍如何在Spring Boot项目中整合支付宝支付功能,重点关注沙箱环境的配置和使用。
说明:沙箱环境是支付宝为开发者提供的模拟环境,可以在不涉及真实交易的情况下测试支付流程。在沙箱环境中,所有的交易都是模拟的,不会产生真实的资金流动。
在开始整合支付宝支付功能之前,我们需要做一些准备工作,包括注册支付宝开放平台账号、配置沙箱环境以及创建Spring Boot项目。
首先,我们需要在支付宝开放平台注册一个开发者账号。
提示:注册支付宝开放平台账号是免费的,但如果要上线真实环境,需要进行企业认证。对于个人开发者,可以长期使用沙箱环境进行开发和测试。
在支付宝开放平台的沙箱环境中,我们需要配置密钥和获取相关参数。
我们需要记录以下参数,稍后在Spring Boot项目中使用:
https://openapi.alipaydev.com/gateway.do
为了测试支付流程,我们需要下载沙箱环境专用的支付宝钱包APP:
接下来,我们需要创建一个Spring Boot项目。可以通过Spring Initializr或者IDE来创建。
说明:本教程使用的是Spring Boot 2.6.x版本,但原则上2.x系列的版本都应该适用。如果你使用Spring Boot 3.x,可能需要对部分代码进行调整。
在Spring Boot项目创建完成后,我们需要整合支付宝SDK,包括添加依赖、配置属性和初始化支付宝客户端。
首先,我们需要在pom.xml文件中添加支付宝SDK的依赖。打开pom.xml文件,在dependencies节点中添加以下依赖:
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.35.0.ALL</version>
</dependency>
<!-- 用于处理JSON的依赖 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
提示:建议使用最新版本的支付宝SDK,可以在Maven仓库中查找最新版本。
接下来,我们需要在application.yml文件中配置支付宝相关的属性。如果项目中没有application.yml文件,可以将application.properties重命名为application.yml,或者直接创建一个新的application.yml文件。
server:
port: 8080
spring:
thymeleaf:
cache: false
alipay:
app-id: 20210100000000000 # 你的沙箱环境APPID
merchant-private-key: MIIEvgIBADANB... # 你的商户私钥,完整的私钥内容
alipay-public-key: MIIBIjANBgkqhki... # 支付宝公钥
gateway-url: https://openapi.alipaydev.com/gateway.do # 沙箱环境网关
charset: UTF-8
format: json
sign-type: RSA2
notify-url: http://localhost:8080/alipay/notify # 异步通知地址
return-url: http://localhost:8080/alipay/return # 同步回调地址
警告:在实际项目中,不建议将敏感信息如私钥直接放在配置文件中,而应使用环境变量或配置中心来管理这些敏感信息。这里为了教程简单化而直接配置。
为了更方便地使用这些配置属性,我们创建一个属性绑定类:
package com.example.alipaydemo.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "alipay")
public class AlipayProperties {
private String appId;
private String merchantPrivateKey;
private String alipayPublicKey;
private String gatewayUrl;
private String charset;
private String format;
private String signType;
private String notifyUrl;
private String returnUrl;
}
现在,我们需要创建一个配置类,用于初始化支付宝客户端:
package com.example.alipaydemo.config;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AlipayConfig {
private final AlipayProperties alipayProperties;
public AlipayConfig(AlipayProperties alipayProperties) {
this.alipayProperties = alipayProperties;
}
@Bean
public AlipayClient alipayClient() {
return new DefaultAlipayClient(
alipayProperties.getGatewayUrl(),
alipayProperties.getAppId(),
alipayProperties.getMerchantPrivateKey(),
alipayProperties.getFormat(),
alipayProperties.getCharset(),
alipayProperties.getAlipayPublicKey(),
alipayProperties.getSignType()
);
}
}
通过上述配置,我们已经完成了支付宝SDK的基本整合,接下来我们将实现具体的支付接口。
在完成支付宝SDK的整合后,我们需要实现支付相关的功能,包括创建支付实体类、实现支付服务和控制器。
首先,我们创建一个支付订单实体类,用于封装支付信息:
package com.example.alipaydemo.model;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class PaymentOrder {
private String outTradeNo; // 商户订单号
private String subject; // 订单标题
private BigDecimal totalAmount; // 订单金额
private String body; // 订单描述
// 其他业务参数...
}
接下来,我们实现支付服务,用于处理支付相关的业务逻辑:
package com.example.alipaydemo.service;
import com.example.alipaydemo.model.PaymentOrder;
public interface AlipayService {
/**
* 创建电脑网站支付
*/
String createPagePay(PaymentOrder paymentOrder);
/**
* 验证支付宝异步通知
*/
boolean verifyNotify(String notifyId);
/**
* 查询订单状态
*/
String queryOrder(String outTradeNo);
}
package com.example.alipaydemo.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.example.alipaydemo.config.AlipayProperties;
import com.example.alipaydemo.model.PaymentOrder;
import com.example.alipaydemo.service.AlipayService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class AlipayServiceImpl implements AlipayService {
private final AlipayClient alipayClient;
private final AlipayProperties alipayProperties;
public AlipayServiceImpl(AlipayClient alipayClient, AlipayProperties alipayProperties) {
this.alipayClient = alipayClient;
this.alipayProperties = alipayProperties;
}
@Override
public String createPagePay(PaymentOrder paymentOrder) {
try {
// 创建API对应的request
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
// 设置回调地址
request.setReturnUrl(alipayProperties.getReturnUrl());
request.setNotifyUrl(alipayProperties.getNotifyUrl());
// 设置业务参数
JSONObject bizContent = new JSONObject();
bizContent.put("out_trade_no", paymentOrder.getOutTradeNo());
bizContent.put("total_amount", paymentOrder.getTotalAmount());
bizContent.put("subject", paymentOrder.getSubject());
bizContent.put("body", paymentOrder.getBody());
bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY"); // 电脑网站支付场景固定为FAST_INSTANT_TRADE_PAY
request.setBizContent(bizContent.toString());
// 调用SDK生成表单
String form = alipayClient.pageExecute(request).getBody();
return form;
} catch (AlipayApiException e) {
log.error("生成支付宝支付表单失败", e);
throw new RuntimeException("生成支付宝支付表单失败", e);
}
}
@Override
public boolean verifyNotify(String notifyId) {
// 实际项目中,应该调用支付宝提供的验证接口
// 这里简化处理,假设验证通过
return true;
}
@Override
public String queryOrder(String outTradeNo) {
try {
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
JSONObject bizContent = new JSONObject();
bizContent.put("out_trade_no", outTradeNo);
request.setBizContent(bizContent.toString());
AlipayTradeQueryResponse response = alipayClient.execute(request);
if (response.isSuccess()) {
return response.getTradeStatus();
} else {
log.error("查询订单失败: {}", response.getMsg());
return null;
}
} catch (AlipayApiException e) {
log.error("查询订单异常", e);
throw new RuntimeException("查询订单异常", e);
}
}
}
最后,我们实现支付相关的控制器,用于处理前端请求:
package com.example.alipaydemo.controller;
import com.example.alipaydemo.model.PaymentOrder;
import com.example.alipaydemo.service.AlipayService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.util.Map;
import java.util.UUID;
@Slf4j
@Controller
@RequestMapping("/alipay")
public class AlipayController {
private final AlipayService alipayService;
public AlipayController(AlipayService alipayService) {
this.alipayService = alipayService;
}
/**
* 跳转到支付页面
*/
@GetMapping("/pay")
public String pay(Model model) {
// 这里简单展示一个固定商品
model.addAttribute("productName", "测试商品");
model.addAttribute("productPrice", new BigDecimal("0.01"));
return "pay";
}
/**
* 发起支付
*/
@PostMapping("/create")
@ResponseBody
public String create(@RequestParam String subject, @RequestParam BigDecimal amount) {
// 创建支付订单
PaymentOrder paymentOrder = new PaymentOrder();
paymentOrder.setOutTradeNo(UUID.randomUUID().toString().replace("-", ""));
paymentOrder.setSubject(subject);
paymentOrder.setTotalAmount(amount);
paymentOrder.setBody("测试商品详情");
// 调用支付宝接口
String form = alipayService.createPagePay(paymentOrder);
return form;
}
/**
* 同步回调
*/
@GetMapping("/return")
public String returnUrl(@RequestParam Map params, Model model) {
log.info("支付宝同步回调参数: {}", params);
// 处理同步回调逻辑
String outTradeNo = params.get("out_trade_no");
String tradeNo = params.get("trade_no");
// 查询订单状态
String tradeStatus = alipayService.queryOrder(outTradeNo);
model.addAttribute("outTradeNo", outTradeNo);
model.addAttribute("tradeNo", tradeNo);
model.addAttribute("tradeStatus", tradeStatus);
return "success";
}
/**
* 异步通知
*/
@PostMapping("/notify")
@ResponseBody
public String notify(@RequestParam Map params) {
log.info("支付宝异步通知参数: {}", params);
// 验证通知的真实性
boolean verified = alipayService.verifyNotify(params.get("notify_id"));
if (verified) {
// 处理业务逻辑
String outTradeNo = params.get("out_trade_no");
String tradeStatus = params.get("trade_status");
// 根据交易状态更新订单
if ("TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus)) {
// 更新订单状态为已支付
log.info("订单 {} 支付成功", outTradeNo);
}
return "success"; // 成功处理的标识
} else {
return "fail"; // 失败处理的标识
}
}
}
支付回调是指当支付完成后,支付宝会向商户服务器发送通知,商户需要根据通知内容来更新订单状态。
同步回调是指用户在支付完成后,支付宝会自动跳转到商户指定的回调页面。
在上述支付控制器中,我们已经实现了同步回调的处理逻辑。
异步通知是指当支付完成后,支付宝会向商户服务器发送通知,商户需要根据通知内容来更新订单状态。
在上述支付控制器中,我们已经实现了异步通知的处理逻辑。
订单查询是指商户可以通过支付宝提供的接口查询订单状态。
在上述支付控制器中,我们已经实现了订单查询的处理逻辑。
在完成支付功能开发后,我们需要进行测试,以确保支付功能正常工作。
在进行测试之前,我们需要准备一些测试数据,包括测试账号、测试商品等。
测试流程包括以下几个步骤:
在测试过程中,可能会遇到一些常见问题,例如支付失败、订单状态更新不正确等。我们需要根据问题进行调试,确保支付功能正常工作。
在完成所有测试后,我们可以将项目部署到生产环境,供用户使用。
本教程详细介绍了如何在Spring Boot项目中整合支付宝支付功能,重点关注沙箱环境的配置和使用。通过本教程,您应该能够掌握以下技能: