准备工作
注册支付宝开发者账户,进入开发者控制台
获取支付账号
内网穿透,我们需要暴露我们的端口给支付宝,让他调用我们的接口返回参数给我们。免费内网穿透:i996 内网穿透/证书签发
成功映射
数据库订单表
项目整合
引入依赖
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.22.110.ALL</version>
</dependency>
application.yml 配置
alibabapay:
appId: 9021000134671891 # APPID
appPrivateKey: MIIEvgIBADANBgkqhkiG9w0BA # 应用私钥
alipayPublicKey: MIIBIjANBgkqhkiG9w0BAQEFAAO # 支付宝公钥
notifyUrl: https://tk4nf5.i996.me/order/notify # 提供给支付宝的回调接口
对应支付宝开发者页面的:
AliBaBaPayConfig .java
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "alibabapay")
public class AliBaBaPayConfig {
private String appId;
private String appPrivateKey;
private String alipayPublicKey;
private String notifyUrl;
// 支付宝沙盒地址
private String GATEWAY_URL="https://openapi-sanbox.dl.alipaydev.com/gateway/do";
private String FORMAT="JSON";
private String CHARSET="UTF-8";
// 签名方式
private String SIGN_TYPE="RSA2";
// 返回页面url
private String RETURN_URL="http://127.0.0.1:8080/myOrders";
}
支付接口
RestController
@RequestMapping("/order")
@Api(tags = "Order服务", description = "order服务接口api")
public class OrderInfoController {
@GetMapping("/payOrder")
@ApiOperation("支付订单")
public ResponseResult payOrder(String orderId , HttpServletResponse httpServletResponse) throws IOException {
return iOrderInfoService.payOrder(orderId, httpServletResponse);
}
@PostMapping("/notify")
@ApiOperation("支付宝支付成功回调")
public ResponseResult notify(HttpServletRequest request) throws IOException, AlipayApiException {
return iOrderInfoService.notify(request);
}
}
impl
@Resource
private AliBaBaPayConfig aliBaBaPayConfig;
@Resource
private OrderInfoMapper orderInfoMapper;
@Override
public ResponseResult payOrder(String orderId, HttpServletResponse httpServletResponse) throws IOException {
// 查询订单
OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
if (orderInfo== null) {
return ResponseResult.errorResult(HttpCodeEnum.SYSTEM_ERROR.getCode(),HttpCodeEnum.SYSTEM_ERROR.getMsg());
}
// 调用支付宝接口
DefaultAlipayClient defaultAlipayClient = new DefaultAlipayClient(aliBaBaPayConfig.getGATEWAY_URL(), aliBaBaPayConfig.getAppId(), aliBaBaPayConfig.getAppPrivateKey(), aliBaBaPayConfig.getFORMAT(), aliBaBaPayConfig.getCHARSET(), aliBaBaPayConfig.getAlipayPublicKey(), aliBaBaPayConfig.getSIGN_TYPE());
// 设置参数
AlipayTradePagePayRequest alipayTradePagePayRequest = new AlipayTradePagePayRequest(); //请求类
alipayTradePagePayRequest.setNotifyUrl(aliBaBaPayConfig.getNotifyUrl()); // 提供给支付宝的回调接口
JSONObject jsonObject = new JSONObject();
jsonObject.set("out_trade_no",orderInfo.getOrderUuid()); // 我们生成的订单编号需要唯一的
jsonObject.set("total_amount",orderInfo.getTotalAmount()); // 订单总金额
jsonObject.set("subject",orderInfo.getOrderName()); // 订单名称
jsonObject.set("product_code","FAST_INSTANT_TRADE_PAY"); // 固定配置
alipayTradePagePayRequest.setBizContent(jsonObject.toString());
alipayTradePagePayRequest.setReturnUrl(aliBaBaPayConfig.getRETURN_URL()); // 支付成功返回页面
// 调用支付宝接口返回结果,返回给游览器
String form="";
try {
form=defaultAlipayClient.pageExecute(alipayTradePagePayRequest).getBody(); // 调用SDK支付页面表单
} catch (AlipayApiException e) {
throw new RuntimeException(e);
}
httpServletResponse.setContentType("text/html;charset="+aliBaBaPayConfig.getCHARSET());
httpServletResponse.getWriter().write(form); // 直接将表单html输出页面
httpServletResponse.getWriter().flush();
httpServletResponse.getWriter().close();
return ResponseResult.okResult();
}
@Override
public ResponseResult notify(HttpServletRequest request) throws AlipayApiException {
if (request.getParameter("trade_status").equals("TRADE_SUCCESS")){
Map map = new HashMap<>();
Map<String, String[]> parameterMap = request.getParameterMap();
for (String name : parameterMap.keySet()) {
map.put(name,request.getParameter(name));
}
String sign = (String) map.get("sign");
String contentV1 = AlipaySignature.getSignCheckContentV1(map);
// 验证
boolean checkContent = AlipaySignature.rsa256CheckContent(contentV1, sign, aliBaBaPayConfig.getAlipayPublicKey(), aliBaBaPayConfig.getCHARSET());
// 验证通过
if (checkContent) {
System.out.println("交易名称 = " + map.get("subject"));
System.out.println("交易状态 = " + map.get("trade_status"));
System.out.println("支付宝交易凭证号 = " + map.get("trade_no"));
System.out.println("商户订单号 = " + map.get("out_trade_no"));
System.out.println("交易金额 = " + map.get("total_amount"));
System.out.println("买家在支付宝唯一ID = " + map.get("buyer_id"));
System.out.println("买家付款时间 = " + map.get("gmt_payment"));
System.out.println("买家付款金额 = " + map.get("buyer_pay_amount"));
String orderUuId = (String) map.get("out_trade_no");
String payTime = (String) map.get("gmt_payment");
String tradeNo = (String) map.get("trade_no");
// 更新订单状态
OrderInfo orderInfo= orderInfoMapper.selectByUuId(orderUuId);
orderInfo.setOrderStatus(OrderStatusType.PAY_ORDER.getStatus());
orderInfo.setTradeNo(tradeNo);
orderInfo.setPayDate(payTime);
return ResponseResult.okResult();
}
}
return ResponseResult.errorResult(HttpCodeEnum.SYSTEM_ERROR.getCode(),HttpCodeEnum.SYSTEM_ERROR.getMsg());
}
接口测试
然后我们访问URL进行测试。
然后使用沙箱账号登录,支付就可以
附加退款功能
接受参数
import lombok.Data;
import java.math.BigDecimal;
@Data
public class AliPay {
// 商品订单编号
private String orderUuid;
// 总金额
private BigDecimal totalAmount;
private String subject;
// 支付宝订单编号
private String tradeNo;
}
退款接口
@PostMapping("/returnOrder")
@ApiOperation("七天无理由退款")
public ResponseResult returnOrder(AliPay aliPay) throws AlipayApiException {
return iOrderInfoService.returnOrder(aliPay);
}
impl
public ResponseResult returnOrder(AliPay aliPay) throws AlipayApiException {
// 7天无理由退款
String now = DateUtil.now();
// 获取订单信息
OrderInfo orders = orderInfoMapper.selectByUuId(aliPay.getOrderUuid());
if (orders != null) {
// hutool工具类,判断时间间隔
long between = DateUtil.between(DateUtil.parseDateTime(orders.getPayDate()), DateUtil.parseDateTime(now), DateUnit.DAY);
if (between > 7) {
return new ResponseResult(HttpCodeEnum.SYSTEM_ERROR.getCode(), "该订单已超过7天,不支持退款");
}
}
// 1. 创建Client,通用SDK提供的Client,负责调用支付宝的API
AlipayClient alipayClient = new DefaultAlipayClient(aliBaBaPayConfig.getGATEWAY_URL(),
aliBaBaPayConfig.getAppId(), aliBaBaPayConfig.getAppPrivateKey(), aliBaBaPayConfig.getFORMAT(), aliBaBaPayConfig.getCHARSET(),
aliBaBaPayConfig.getAlipayPublicKey(), aliBaBaPayConfig.getSIGN_TYPE());
// 2. 创建 Request,设置参数
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
JSONObject bizContent = new JSONObject();
bizContent.set("trade_no", aliPay.getTradeNo()); // 支付宝回调的订单流水号
bizContent.set("refund_amount", aliPay.getTotalAmount()); // 订单的总金额
bizContent.set("out_request_no", aliPay.getOrderUuid()); // 我的订单编号
// 返回参数选项,按需传入
//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. 更新数据库状态
orderInfoMapper.updatePayState(aliPay.getOrderUuid(), OrderStatusType.RETURN_ORDER.getStatus(), now);
return ResponseResult.okResult();
} else { // 退款失败,isSuccess 为false
System.out.println(response.getBody());
return ResponseResult.errorResult(Integer.parseInt(response.getCode()), response.getBody());
}
}