SpringBoot集成支付宝沙箱支付

个人账号未申请上架的App/网站是无法接入支付宝支付的,但是可以使用支付宝沙箱版进行练手。沙箱版就相当于不不涉及现实金额交易的一个支付宝模拟环境,其中交易的金额都是虚假的内容。

准备步骤

  • 进入支付包开放平台找到沙箱应用管理平台-> 地址

  • 创建沙箱应用,之后界面如下

  • 在基本信息栏,开发信息中选择:自定义密钥

  • 公钥模式:设置并查看

  • 使用支付宝密钥生成工具或openssl工具生成公私钥,将公钥复制到加签内容配置内,结果如下

  • 以上开发平台配置部分就完成了

接入SpringBoot

SpringBoot版本

<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>2.4.12</version>
<relativePath/>
</parent>

依赖版本

 <!-- springboot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 支付宝模拟支付SDK -->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.16.2.ALL</version>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>

在resources目录编写alipay.properties配置文件

# 支付宝
# appId
alipay.appId=你的appid
# 应用私钥
alipay.appPrivateKey=你的应用私钥,在C:\Users\用户名\Documents\支付宝开放平台密钥工具\日期(前提是你用的支付宝工具生成的公私钥)
# 支付宝公钥
alipay.alipayPublicKey=你的支付宝公钥,在支付宝沙箱管理平台
# 异步回调一般用于数据持久化
# 异步回调地址(主要是用于支付完成后异步回调的地址,必须是公网(可以使用内网穿透))
alipay.notifyUrl=http://xxxx.xxx/xxx
# 同步回调一般用于页面跳转
# 同步回调地址(主要是用于支付完成后同步回调地址,可以是本地地址)
alipay.returnUrl=http://xxxx.xxx/xxx
# 支付宝网关地址(沙箱版,非沙箱版需要修改)
alipay.gatewayUrl=https://openapi.alipaydev.com/gateway.do
# 加密方式:默认
alipay.signType=RSA2
# 支付成功重定向地址(非支付宝配置,此处是支付完成后跳转的页面地址,根据需求添加删除)
alipay.redirectUrl=http://xxxx.xxx/xxx

编写AlipayConfig.java用于读取配置文件

@Configuration
@PropertySource("classpath:alipay.properties")
@ConfigurationProperties(prefix = "alipay")
@Data
public class AlipayConfig {
// appId
private String appId;
// 应用私钥
private String appPrivateKey;
// 支付宝公钥
private String alipayPublicKey;
// 异步回调地址(主要是用于支付完成后执行数据持久化(必须是公网ip))
private String notifyUrl;
// 同步回调地址(主要是用于支付完成后的页面跳转(可以是本地地址))
private String returnUrl;
// 支付宝网关地址
private String gatewayUrl;
// 加密方式
private String signType;
// 支付成功重定向地址
private String redirectUrl;

}

在需要支付的方法上调用如下方法


// 在使用这个方法前需要注入以下bean
// 支付宝配置文件
@Resource
private AlipayConfig alipayConfig;


/**
* 付款
*
* @param outTradeNo 订单ID(自定义生成,在调用方法前生成)
* @param totalAmount 订单金额
* @param subject 订单描述
* @return
*/
private String sendRequestToAlipay(String outTradeNo, String totalAmount, String subject) {
//获得初始化的AlipayClient
AlipayClient alipayClient = new DefaultAlipayClient(alipayConfig.getGatewayUrl(), alipayConfig.getAppId(), alipayConfig.getAppPrivateKey(),
"JSON", "UTF-8", alipayConfig.getAlipayPublicKey(), alipayConfig.getSignType());

//设置请求参数
AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
alipayRequest.setReturnUrl(alipayConfig.getReturnUrl());
alipayRequest.setNotifyUrl(alipayConfig.getNotifyUrl());
// 默认写法,不可更改
alipayRequest.setBizContent("{\"out_trade_no\":\"" + outTradeNo + "\","
+ "\"total_amount\":\"" + totalAmount + "\","
+ "\"subject\":\"" + subject + "\","
+ "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");

//请求
String result = null;
try {
result = alipayClient.pageExecute(alipayRequest).getBody();
} catch (AlipayApiException e) {
e.printStackTrace();
}
// 返回响应体
return result;
}

异步回调

// Controller
/**
* 付款成功异步回调,将数据持久化到数据库
*
* @param request
* @return
* @throws AlipayApiException
*/
@ApiOperation("付款成功异步回调")
@PostMapping("asyncNotify")
public String notifyUrl(HttpServletRequest request) throws AlipayApiException {
return orderService.notifyUrl(request);
}


// Service
/**
* 异步回调
*
* @param request
* @return
* @throws UnsupportedEncodingException
* @throws AlipayApiException
*/
public String notifyUrl(HttpServletRequest request) throws AlipayApiException {
logger.info("=================================异步回调=====================================");
// 获取支付宝GET过来反馈信息
Map<String, String> params = new HashMap<>();
Map<String, String[]> requestParams = request.getParameterMap();
for (String name : requestParams.keySet()) {
params.put(name, request.getParameter(name));
}
boolean signVerified = AlipaySignature.rsaCheckV1(params, alipayConfig.getAlipayPublicKey(), "UTF-8", alipayConfig.getSignType()); // 调用SDK验证签名
//验证签名通过
if (signVerified) {
logger.info("交易名称: " + params.get("subject"));
logger.info("交易状态: " + params.get("trade_status"));
logger.info("支付宝交易凭证号: " + params.get("trade_no"));
logger.info("商户订单号: " + params.get("out_trade_no"));
logger.info("交易金额: " + params.get("total_amount"));
logger.info("买家在支付宝唯一id: " + params.get("buyer_id"));
logger.info("买家付款时间: " + params.get("gmt_payment"));
logger.info("买家付款金额: " + params.get("buyer_pay_amount"));
logger.info("重定向URL: " + params.get("body"));

// TODO 支付成功,修改数据库等信息

Integer res = orderMapper.toBuy(order);
if (res >= 1) {
//跳转付款成功页面
return "ok";
}
// 支付宝失败退款
//跳转付款失败页面
return "no";
} else {
//跳转付款失败页面
return "no";
}
}

同步回调

// Controller
/**
* 付款成功同步回调,用户url重定向
*
* @param request
* @param response
* @throws IOException
*/
@ApiOperation("付款成功同步回调")
@GetMapping("syncNotify")
public void returnUrl(HttpServletRequest request, HttpServletResponse response) throws IOException {
orderService.returnUrl(request, response);
}

// Service
/**
* 同步回调
*
* @param request
* @param response
* @throws IOException
*/
public void returnUrl(HttpServletRequest request, HttpServletResponse response) throws IOException {
logger.info("=================================同步回调=====================================");
// TODO 进行相应的操作

}

以上配置完后,点击支付url,跳转到支付宝沙箱扫码支付页面,使用:支付宝沙箱软件支付

登录账号密码: