环境:支付宝沙箱sdk
pom依赖:
//支付宝sdk依赖包
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.22.110.ALL</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.20</version>
</dependency>
config:这里读区nacos中aliyun配置文件
配置文件如下
spring:
aliyun:
pay:
serverUrl: https://openapi-sandbox.dl.alipaydev.com/gateway.do//沙箱网关
appId: 9021000123611850 //支付宝appid
privateKey: //应用私钥
alipayPublicKey://应用公钥
notifyUrl: ip/alipay/notify //回调地址
gatewayUrl: https://openapi-sandbox.dl.alipaydev.com/gateway.do //网关
@Data
@Component
@ConfigurationProperties(prefix = "spring.aliyun.pay")
public class AliPayConfig {
private String appId;
private String privateKey;
private String alipayPublicKey;
private String notifyUrl;
}
controller:业务层
package com.ruoyi.alipay.controller;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.ruoyi.alipay.config.AliPayConfig;
import com.ruoyi.alipay.domain.AliPayOrder;
import com.ruoyi.common.core.constant.SecurityConstants;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.system.api.RemoteOrderService;
import com.ruoyi.system.api.domain.kernel.KernelOrderDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
//支付宝支付接口
@Component
@Controller
@RequestMapping("/alipay")
public class AlipayController {
@Autowired
private RemoteOrderService remoteOrderService;
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";
@Resource
private AliPayConfig aliPayConfig;
@GetMapping("/pay") // &subject=xxx&traceNo=xxx&totalAmount=xxx
public void pay(AliPayOrder aliPayOrder, HttpServletResponse httpResponse) throws Exception {
// 1. 创建Client,通用SDK提供的Client,负责调用支付宝的API
AlipayClient alipayClient = new DefaultAlipayClient(GATEWAY_URL, aliPayConfig.getAppId(),
aliPayConfig.getPrivateKey(), FORMAT, CHARSET, aliPayConfig.getAlipayPublicKey(), SIGN_TYPE);
// 2. 创建 Request并设置Request参数
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest(); // 发送请求的 Request类
request.setNotifyUrl(aliPayConfig.getNotifyUrl());
JSONObject bizContent = new JSONObject();
bizContent.set("out_trade_no", aliPayOrder.getOrderNumber()); // 我们自己生成的订单编号
bizContent.set("total_amount", aliPayOrder.getActualAmount()); // 订单的总金额
bizContent.set("subject", aliPayOrder.getOrderName()); // 支付的名称
bizContent.set("product_code", "FAST_INSTANT_TRADE_PAY"); // 固定配置
request.setBizContent(bizContent.toString());
// 执行请求,拿到响应的结果,返回给浏览器
String form = "";
try {
form = alipayClient.pageExecute(request).getBody(); // 调用SDK生成表单
} catch (AlipayApiException e) {
e.printStackTrace();
}
httpResponse.setContentType("text/html;charset=" + CHARSET);
httpResponse.getWriter().write(form);// 直接将完整的表单html输出到页面
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));
// System.out.println(name + " = " + request.getParameter(name));
}
String tradeNo = params.get("out_trade_no");
String gmtPayment = params.get("gmt_payment");
String alipayTradeNo = params.get("trade_no");
String sign = params.get("sign");
String content = AlipaySignature.getSignCheckContentV1(params);
boolean checkSignature = AlipaySignature.rsa256CheckContent(content, sign, aliPayConfig.getAlipayPublicKey(), "UTF-8"); // 验证签名
// 支付宝验签
if (checkSignature) {
// 验签通过
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"));
// 查询订单
KernelOrderDTO kernelOrder = new KernelOrderDTO();
kernelOrder.setOrderNumber(tradeNo);
List<KernelOrderDTO> list = remoteOrderService.select(kernelOrder, SecurityConstants.INNER);
if (list != null && !list.isEmpty()) {
KernelOrderDTO kernelOrder1 = new KernelOrderDTO();
//支付时间
kernelOrder1.setOrderBegin(new Date());
//支付宝付款编号
kernelOrder1.setDealNumber(alipayTradeNo);
//订单状态
kernelOrder1.setOrderState("0");
//支付金额
kernelOrder1.setActualAmount(new BigDecimal(params.get("total_amount")));
//支付方式
kernelOrder1.setPayMode("支付宝");
for (int i = 0; i < list.size(); i++) {
kernelOrder1.setId(list.get(i).getId());
}
System.out.println("金额"+gmtPayment);
System.out.println(params.get("total_amount")+"金额2");
AjaxResult ajaxResult = remoteOrderService.editOrder(kernelOrder1, SecurityConstants.INNER);
System.out.println(
ajaxResult + "测试"
);
System.out.println("走完");
}
}
}
return "success";
}
@GetMapping("/return")
public AjaxResult returnPay (AliPayOrder aliPayOrder) throws Exception {
// 7天无理由退款
String now = DateUtil.now();
// 查询订单
KernelOrderDTO kernelOrder = new KernelOrderDTO();
kernelOrder.setOrderNumber(aliPayOrder.getOrderNumber());
List<KernelOrderDTO> list = remoteOrderService.select(kernelOrder, SecurityConstants.INNER);
if (list != null && !list.isEmpty()) {
for (int i = 0; i < list.size(); i++) {
// hutool工具类,判断时间间隔
// long between = DateUtil.between(DateUtil.parseDateTime((CharSequence) list.get(i).getOrderBegin()), DateUtil.parseDateTime(now), DateUnit.DAY);
// if (between > 7) {
// // return Result.error("-1", "该订单已超过7天,不支持退款");
// System.out.println("超时");
if (list.get(i).getOrderState().equals("8")){
return AjaxResult.error("已退款");
}
}
}
// 1. 创建Client,通用SDK提供的Client,负责调用支付宝的API
AlipayClient alipayClient = new DefaultAlipayClient(GATEWAY_URL,
aliPayConfig.getAppId(), aliPayConfig.getPrivateKey(), FORMAT, CHARSET,
aliPayConfig.getAlipayPublicKey(), SIGN_TYPE);
// 2. 创建 Request,设置参数
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
JSONObject bizContent = new JSONObject();
bizContent.set("trade_no", aliPayOrder.getDealNumber()); // 支付宝回调的订单流水号
bizContent.set("refund_amount", aliPayOrder.getActualAmount()); // 订单的总金额
bizContent.set("out_request_no", aliPayOrder.getOrderNumber()); // 我的订单编号
// 返回参数选项,按需传入
//JSONArray queryOptions = new JSONArray();
//queryOptions.add("refund_detail_item_list");
//bizContent.put("query_options", queryOptions);
request.setBizContent(bizContent.toString());
// 3. 执行请求
AlipayTradeRefundResponse response = alipayClient.execute(request);
if (response.isSuccess()) { // 退款成功,isSuccess 为true
System.out.println("调用成功");
// 4. 更新数据库状态
KernelOrderDTO kernelOrder1 = new KernelOrderDTO();
kernelOrder1.setOrderState("8");
for (int i = 0; i < list.size(); i++) {
kernelOrder1.setId(list.get(i).getId());
}
AjaxResult ajaxResult = remoteOrderService.editOrder(kernelOrder1, SecurityConstants.INNER);
System.out.println("成功");
return AjaxResult.success("成功");
} else { // 退款失败,isSuccess 为false
System.out.println(response.getBody());
System.out.println("失败");
return AjaxResult.error("失败");
}
}
}
domin :实体
package com.ruoyi.alipay.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.math.BigDecimal;
import java.util.Date;
/**
* 订单对象 kernel_order
*
* @author ruoyi
* @date 2023-07-31
*/
public class AliPayOrder
{
//以自己业务实体为基准
}
测试方法:
本地测试需要配合natapp穿透测试。
下载地址https://natapp.cn
接口测试url:
穿ip
+/alipay/pay?orderNumber=7777&actualAmount=23&orderName=ty
orderNumber:订单号
actualAmount:支付金额
orderName:订单名称
温馨提示,如果集成项目为springcloud,支付与订单不在同一模块,figin接口调用查询使用post
被调用方要使用
@RequestBody接收参数