一、在SpringBoot项目中的pom.xml文件中加入
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-easysdk</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.22.113.ALL</version>
</dependency>
二、到支付宝开发平台去申请一个网页移动应用创建
三,申请成功之后,通过获得的appId、appPrivateKey、 alipayPublicKey来配置application.yml里面的,notifyUrl,涉及到内网渗透,需要到NATAPP-内网穿透 基于ngrok的国内高速内网映射工具natapp是基于ngrok的国内高速内网穿透专业服务商,独家彻底解决ngrok1.7内存泄漏问题.稳定拒绝掉线,适用于微信开发调试,本地架设演示服务器,外网可以访问,远程服务器,远程桌面,远程办公,游戏联机等https://natapp.cn/里面去创建一个账号,并购买一个免费隧道。
之后就是下载natapp,下载之后,解压打开natapp.exe。
打开之后,回到NATAPP-内网穿透 基于ngrok的国内高速内网映射工具修改本地端口号(也就是你的SpringBoot项目的端口号),并复制authtoken
复制好之后在已经打开的natapp里面输入natapp -authtoken=复制的token,就会得到notifyUrl。最后returnUrl就是你完成支付后所要跳转的页面,填的是你前端的一个地址。
alipay:
appId:
appPrivateKey:
alipayPublicKey:
notifyUrl:
returnUrl:
四、创建AliPayConfig.java
package com.test.comment;
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.Config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Data
@Component
//读取yml文件中alipay 开头的配置
@ConfigurationProperties(prefix = "alipay")
public class AliPayConfig {
private String appId;
private String appPrivateKey;
private String alipayPublicKey;
//异步通知回调地址(可选)
private String notifyUrl;
//支付成功后的回调地址
private String returnUrl;
@PostConstruct
public void init() {
// 设置参数(全局只需设置一次)
Config config = new Config();
config.protocol = "https";
config.gatewayHost = "openapi.alipaydev.com";
config.signType = "RSA2";
config.appId = this.appId;
config.merchantPrivateKey = this.appPrivateKey;
config.alipayPublicKey = this.alipayPublicKey;
config.notifyUrl = this.notifyUrl;
Factory.setOptions(config);
System.out.println("=======支付宝SDK初始化成功=======");
}
}
五、创建实体类AliPay.java
package com.test.vo;
import lombok.Data;
@Data
public class AliPay {
private String traceNo;
private double totalAmount;
private String subject;
private String alipayTraceNo;
}
六、创建AliPayController.java
package com.test.controller;
import com.alipay.easysdk.factory.Factory;
import com.test.comment.AliPayConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.test.vo.AliPay;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("alipay")
@Transactional(rollbackFor = Exception.class)
public class AliPayController {
@Resource
AliPayConfig aliPayConfig;
private static final String GATEWAY_URL ="https://openapi-sandbox.dl.alipaydev.com/gateway.do";
private static final String FORMAT ="JSON";
private static final String CHARSET ="utf-8";
private static final String SIGN_TYPE ="RSA2";
@GetMapping("/pay") // 前端路径参数格式?subject=xxx&traceNo=xxx&totalAmount=xxx
public void pay(AliPay aliPay, HttpServletResponse httpResponse) throws Exception {
AlipayClient alipayClient = new DefaultAlipayClient(GATEWAY_URL, aliPayConfig.getAppId(),
aliPayConfig.getAppPrivateKey(), FORMAT, CHARSET, aliPayConfig.getAlipayPublicKey(), SIGN_TYPE);
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
request.setNotifyUrl(aliPayConfig.getNotifyUrl());
request.setReturnUrl(aliPayConfig.getReturnUrl());
request.setBizContent("{\"out_trade_no\":\"" + aliPay.getTraceNo() + "\","
+ "\"total_amount\":\"" + aliPay.getTotalAmount() + "\","
+ "\"subject\":\"" + aliPay.getSubject() + "\","
+ "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
String form = "";
try {
// 调用SDK生成表单
form = alipayClient.pageExecute(request).getBody();
} catch (AlipayApiException e) {
e.printStackTrace();
}
httpResponse.setContentType("text/html;charset=" + CHARSET);
// 直接将完整的表单html输出到页面
httpResponse.getWriter().write(form);
httpResponse.getWriter().flush();
httpResponse.getWriter().close();
}
@PostMapping("/notify") // 注意这里必须是POST接口
public String payNotify(HttpServletRequest request) throws Exception {
if (request.getParameter("trade_status").equals("TRADE_SUCCESS")) {
System.out.println("=========支付宝异步回调========");
Map<String, String> params = new HashMap<>();
Map<String, String[]> requestParams = request.getParameterMap();
for (String name : requestParams.keySet()) {
params.put(name, request.getParameter(name));
}
String tradeNo = params.get("out_trade_no");
String gmtPayment = params.get("gmt_payment");
String alipayTradeNo = params.get("trade_no");
// 支付宝验签
if (Factory.Payment.Common().verifyNotify(params)) {
// 验签通过
System.out.println("交易名称: " + params.get("subject"));
System.out.println("交易状态: " + params.get("trade_status"));
System.out.println("支付宝交易凭证号: " + params.get("trade_no"));
System.out.println("商户订单号: " + params.get("out_trade_no"));
System.out.println("交易金额: " + params.get("total_amount"));
System.out.println("买家在支付宝唯一id: " + params.get("buyer_id"));
System.out.println("买家付款时间: " + params.get("gmt_payment"));
System.out.println("买家付款金额: " + params.get("buyer_pay_amount"));
// 更新订单已支付的逻辑代码
}
}
return "success";
}
}
七、如果项目存在拦截器,需要添加
excludePathPatterns("/alipay/pay");
八、前端使用的Vue
window.open("http://127.0.0.1:9090/alipay/pay?subject="+order.value.orderFlowersName+"&traceNo="+res.data.orderNumber+"&totalAmount="+order.value.orderMoney,'_self')
九、启动项目,测试