本文目录导读:

我来为你提供一个完整的支付宝支付Java集成案例,包含当面付(扫码支付)和手机网站支付两种常见场景。
环境准备
1 Maven依赖
<dependencies>
<!-- 支付宝SDK -->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.38.72.ALL</version>
</dependency>
<!-- JSON处理 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.40</version>
</dependency>
<!-- 日志 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.9</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.11</version>
</dependency>
</dependencies>
2 配置文件 (application.yml)
alipay: # 应用ID app-id: your_app_id # 商户私钥 app-private-key: your_app_private_key # 支付宝公钥 alipay-public-key: your_alipay_public_key # 网关地址 gateway-url: https://openapi.alipay.com/gateway.do # 签名类型 sign-type: RSA2 # 编码格式 charset: UTF-8 # 格式 format: json # 异步通知地址 notify-url: http://your-domain.com/alipay/notify # 同步返回地址 return-url: http://your-domain.com/alipay/return
核心配置类
package com.example.alipay.config;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "alipay")
public class AlipayConfig {
private String appId;
private String appPrivateKey;
private String alipayPublicKey;
private String gatewayUrl;
private String signType = "RSA2";
private String charset = "UTF-8";
private String format = "json";
private String notifyUrl;
private String returnUrl;
// getters and setters...
@Bean
public AlipayClient alipayClient() {
return new DefaultAlipayClient(
gatewayUrl,
appId,
appPrivateKey,
format,
charset,
alipayPublicKey,
signType
);
}
}
支付服务实现
1 支付服务接口
package com.example.alipay.service;
import com.example.alipay.dto.AlipayOrderDTO;
import com.example.alipay.dto.AlipayQueryDTO;
import com.example.alipay.dto.AlipayRefundDTO;
import java.util.Map;
public interface AlipayService {
/**
* 当面付(扫码支付)
*/
String qrcodePay(AlipayOrderDTO orderDTO) throws Exception;
/**
* 手机网站支付
*/
String webPay(AlipayOrderDTO orderDTO) throws Exception;
/**
* 查询订单
*/
AlipayQueryDTO queryOrder(String outTradeNo) throws Exception;
/**
* 退款
*/
boolean refund(AlipayRefundDTO refundDTO) throws Exception;
/**
* 处理异步通知
*/
String handleNotify(Map<String, String> params) throws Exception;
}
2 支付服务实现类
package com.example.alipay.service.impl;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayConstants;
import com.alipay.api.domain.AlipayTradePrecreateModel;
import com.alipay.api.domain.AlipayTradeWapPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.example.alipay.dto.AlipayOrderDTO;
import com.example.alipay.dto.AlipayQueryDTO;
import com.example.alipay.dto.AlipayRefundDTO;
import com.example.alipay.service.AlipayService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.Map;
import java.util.UUID;
@Slf4j
@Service
public class AlipayServiceImpl implements AlipayService {
@Autowired
private AlipayClient alipayClient;
@Autowired
private AlipayConfig alipayConfig;
@Override
public String qrcodePay(AlipayOrderDTO orderDTO) throws Exception {
// 构建请求
AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
request.setNotifyUrl(alipayConfig.getNotifyUrl());
// 构建业务参数
AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
model.setOutTradeNo(orderDTO.getOutTradeNo());
model.setTotalAmount(orderDTO.getTotalAmount().toString());
model.setSubject(orderDTO.getSubject());
model.setBody(orderDTO.getBody());
request.setBizModel(model);
// 发起请求
AlipayTradePrecreateResponse response = alipayClient.execute(request);
if (response.isSuccess()) {
log.info("支付宝当面付成功,订单号:{},二维码链接:{}",
orderDTO.getOutTradeNo(), response.getQrCode());
return response.getQrCode();
} else {
log.error("支付宝当面付失败,错误码:{},错误信息:{}",
response.getCode(), response.getMsg());
throw new RuntimeException("支付失败:" + response.getMsg());
}
}
@Override
public String webPay(AlipayOrderDTO orderDTO) throws Exception {
// 构建请求
AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
request.setNotifyUrl(alipayConfig.getNotifyUrl());
request.setReturnUrl(alipayConfig.getReturnUrl());
// 构建业务参数
AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
model.setOutTradeNo(orderDTO.getOutTradeNo());
model.setTotalAmount(orderDTO.getTotalAmount().toString());
model.setSubject(orderDTO.getSubject());
model.setBody(orderDTO.getBody());
model.setProductCode("QUICK_WAP_WAY");
request.setBizModel(model);
// 生成支付表单
return alipayClient.pageExecute(request).getBody();
}
@Override
public AlipayQueryDTO queryOrder(String outTradeNo) throws Exception {
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
model.setOutTradeNo(outTradeNo);
request.setBizModel(model);
AlipayTradeQueryResponse response = alipayClient.execute(request);
AlipayQueryDTO queryDTO = new AlipayQueryDTO();
if (response.isSuccess()) {
queryDTO.setTradeNo(response.getTradeNo());
queryDTO.setOutTradeNo(response.getOutTradeNo());
queryDTO.setTradeStatus(response.getTradeStatus());
queryDTO.setTotalAmount(new BigDecimal(response.getTotalAmount()));
queryDTO.setReceiptAmount(new BigDecimal(response.getReceiptAmount()));
queryDTO.setBuyerLogonId(response.getBuyerLogonId());
queryDTO.setGmtPayment(response.getGmtPayment());
}
return queryDTO;
}
@Override
public boolean refund(AlipayRefundDTO refundDTO) throws Exception {
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
model.setOutTradeNo(refundDTO.getOutTradeNo());
model.setRefundAmount(refundDTO.getRefundAmount().toString());
model.setRefundReason(refundDTO.getRefundReason());
request.setBizModel(model);
AlipayTradeRefundResponse response = alipayClient.execute(request);
if (response.isSuccess()) {
log.info("退款成功,订单号:{},退款金额:{}",
refundDTO.getOutTradeNo(), refundDTO.getRefundAmount());
return true;
} else {
log.error("退款失败,错误码:{},错误信息:{}",
response.getCode(), response.getMsg());
return false;
}
}
@Override
public String handleNotify(Map<String, String> params) throws Exception {
// 验证签名
boolean signVerified = AlipaySignature.rsaCheckV1(
params,
alipayConfig.getAlipayPublicKey(),
alipayConfig.getCharset(),
alipayConfig.getSignType()
);
if (!signVerified) {
log.error("支付宝异步通知签名验证失败");
return "failure";
}
// 获取通知参数
String outTradeNo = params.get("out_trade_no");
String tradeNo = params.get("trade_no");
String tradeStatus = params.get("trade_status");
String totalAmount = params.get("total_amount");
String gmtPayment = params.get("gmt_payment");
log.info("支付宝异步通知,订单号:{},交易状态:{}", outTradeNo, tradeStatus);
// 处理业务逻辑(更新订单状态等)
if ("TRADE_SUCCESS".equals(tradeStatus)) {
// 支付成功,更新订单状态
// 注意:需要判断处理过的通知不做重复处理
boolean success = processPaymentSuccess(outTradeNo, tradeNo, totalAmount, gmtPayment);
return success ? "success" : "failure";
}
return "success";
}
private boolean processPaymentSuccess(String outTradeNo, String tradeNo,
String totalAmount, String gmtPayment) {
// 实现具体的业务逻辑,如更新数据库订单状态
log.info("处理支付成功回调,订单号:{},支付宝交易号:{}", outTradeNo, tradeNo);
return true;
}
}
DTO对象
1 订单DTO
package com.example.alipay.dto;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class AlipayOrderDTO {
private String outTradeNo; // 商户订单号
private BigDecimal totalAmount; // 支付金额
private String subject; // 订单标题
private String body; // 订单描述
private Integer timeoutExpress = 30; // 超时时间(分钟)
}
2 查询DTO
package com.example.alipay.dto;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class AlipayQueryDTO {
private String tradeNo; // 支付宝交易号
private String outTradeNo; // 商户订单号
private String tradeStatus; // 交易状态
private BigDecimal totalAmount; // 交易金额
private BigDecimal receiptAmount; // 实收金额
private String buyerLogonId; // 买家支付宝账号
private String gmtPayment; // 支付时间
}
3 退款DTO
package com.example.alipay.dto;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class AlipayRefundDTO {
private String outTradeNo; // 商户订单号
private BigDecimal refundAmount; // 退款金额
private String refundReason; // 退款原因
}
控制层
package com.example.alipay.controller;
import com.example.alipay.dto.AlipayOrderDTO;
import com.example.alipay.dto.AlipayQueryDTO;
import com.example.alipay.dto.AlipayRefundDTO;
import com.example.alipay.service.AlipayService;
import com.example.alipay.util.OrderNumberGenerator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
@Slf4j
@RestController
@RequestMapping("/alipay")
public class AlipayController {
@Autowired
private AlipayService alipayService;
/**
* 发起当面付(扫码支付)
*/
@PostMapping("/qrcodePay")
public Map<String, Object> qrcodePay(@RequestBody AlipayOrderDTO orderDTO) {
Map<String, Object> result = new HashMap<>();
try {
// 生成订单号
orderDTO.setOutTradeNo(OrderNumberGenerator.generate());
String qrCode = alipayService.qrcodePay(orderDTO);
result.put("code", 200);
result.put("message", "success");
result.put("data", qrCode);
result.put("outTradeNo", orderDTO.getOutTradeNo());
} catch (Exception e) {
log.error("发起支付宝支付失败", e);
result.put("code", 500);
result.put("message", "支付失败:" + e.getMessage());
}
return result;
}
/**
* 发起手机网站支付
*/
@PostMapping("/webPay")
public Map<String, Object> webPay(@RequestBody AlipayOrderDTO orderDTO) {
Map<String, Object> result = new HashMap<>();
try {
orderDTO.setOutTradeNo(OrderNumberGenerator.generate());
String form = alipayService.webPay(orderDTO);
result.put("code", 200);
result.put("message", "success");
result.put("data", form);
} catch (Exception e) {
log.error("发起手机网站支付失败", e);
result.put("code", 500);
result.put("message", "支付失败:" + e.getMessage());
}
return result;
}
/**
* 查询订单
*/
@GetMapping("/query/{outTradeNo}")
public Map<String, Object> queryOrder(@PathVariable String outTradeNo) {
Map<String, Object> result = new HashMap<>();
try {
AlipayQueryDTO queryDTO = alipayService.queryOrder(outTradeNo);
result.put("code", 200);
result.put("message", "success");
result.put("data", queryDTO);
} catch (Exception e) {
log.error("查询订单失败", e);
result.put("code", 500);
result.put("message", "查询失败:" + e.getMessage());
}
return result;
}
/**
* 退款
*/
@PostMapping("/refund")
public Map<String, Object> refund(@RequestBody AlipayRefundDTO refundDTO) {
Map<String, Object> result = new HashMap<>();
try {
boolean success = alipayService.refund(refundDTO);
result.put("code", success ? 200 : 500);
result.put("message", success ? "退款成功" : "退款失败");
} catch (Exception e) {
log.error("退款失败", e);
result.put("code", 500);
result.put("message", "退款失败:" + e.getMessage());
}
return result;
}
/**
* 异步通知处理
*/
@PostMapping("/notify")
public String handleNotify(HttpServletRequest request) {
try {
// 获取支付宝POST过来的参数
Map<String, String> params = new HashMap<>();
Map<String, String[]> requestParams = request.getParameterMap();
for (String name : requestParams.keySet()) {
String[] values = requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
}
params.put(name, valueStr);
}
return alipayService.handleNotify(params);
} catch (Exception e) {
log.error("处理支付宝异步通知失败", e);
return "failure";
}
}
/**
* 同步返回处理
*/
@GetMapping("/return")
public String handleReturn(HttpServletRequest request) {
// 处理同步返回,通常只是展示成功页面
// 真正的业务逻辑应在异步通知中处理
return "支付成功,正在返回...";
}
}
工具类
1 订单号生成器
package com.example.alipay.util;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
public class OrderNumberGenerator {
private static int sequence = 0;
private static final Object lock = new Object();
/**
* 生成唯一订单号
*/
public static String generate() {
synchronized (lock) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
String dateStr = sdf.format(new Date());
// 序列号,确保同一毫秒内不会重复
if (sequence >= 1000) {
sequence = 0;
}
sequence++;
return dateStr + String.format("%03d", sequence) + getRandomChar(3);
}
}
/**
* 生成随机字符
*/
private static String getRandomChar(int length) {
String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++) {
int index = (int) (Math.random() * chars.length());
sb.append(chars.charAt(index));
}
return sb.toString();
}
}
2 金额工具类
package com.example.alipay.util;
import java.math.BigDecimal;
import java.math.RoundingMode;
public class AmountUtil {
/**
* 元转分
*/
public static long yuanToFen(BigDecimal yuan) {
return yuan.multiply(new BigDecimal(100))
.setScale(0, RoundingMode.HALF_UP)
.longValue();
}
/**
* 分转元
*/
public static BigDecimal fenToYuan(long fen) {
return new BigDecimal(fen)
.divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
}
/**
* 格式化金额
*/
public static String format(BigDecimal amount) {
return amount.setScale(2, RoundingMode.HALF_UP).toString();
}
}
集成测试示例
package com.example.alipay;
import com.example.alipay.dto.AlipayOrderDTO;
import com.example.alipay.service.AlipayService;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.math.BigDecimal;
@Slf4j
@SpringBootTest
public class AlipayPaymentTest {
@Autowired
private AlipayService alipayService;
@Test
public void testQrcodePay() throws Exception {
// 准备订单数据
AlipayOrderDTO orderDTO = new AlipayOrderDTO();
orderDTO.setOutTradeNo("ORDER" + System.currentTimeMillis());
orderDTO.setTotalAmount(new BigDecimal("0.01"));
orderDTO.setSubject("测试商品");
orderDTO.setBody("测试商品描述");
// 发起支付
String qrCode = alipayService.qrcodePay(orderDTO);
log.info("生成的二维码链接:{}", qrCode);
System.out.println("请使用支付宝扫描以下二维码进行支付:");
System.out.println(qrCode);
}
@Test
public void testQueryOrder() throws Exception {
String outTradeNo = "ORDER1234567890";
com.example.alipay.dto.AlipayQueryDTO queryDTO = alipayService.queryOrder(outTradeNo);
log.info("订单信息:{}", queryDTO);
}
}
注意事项
1 配置文件示例
# 支付宝配置 alipay.app-id=2021000118600001 alipay.app-private-key=MIIEvQIBADANB... (完整RSA私钥) alipay.alipay-public-key=MIIBIjANBg... (完整RSA公钥) alipay.gateway-url=https://openapi.alipay.com/gateway.do alipay.sign-type=RSA2 alipay.charset=UTF-8 alipay.format=json alipay.notify-url=http://your-domain.com/alipay/notify alipay.return-url=http://your-domain.com/alipay/return
2 重要提示
- 密钥安全:私钥不要在代码中硬编码,建议使用配置中心或环境变量
- 异步通知:一定要验证签名,并确保回调幂等性
- 订单号唯一性:确保生成的订单号全局唯一
- 金额精度:使用BigDecimal处理金额,避免浮点数精度问题
- 日志记录:记录所有关键操作的日志,便于排查问题
3 常见问题处理
// 签名失败处理
public static boolean verifySign(Map<String, String> params, String alipayPublicKey) {
try {
return AlipaySignature.rsaCheckV1(params, alipayPublicKey, "UTF-8", "RSA2");
} catch (Exception e) {
log.error("签名验证异常", e);
return false;
}
}
这个案例涵盖了支付宝支付的主要功能,可根据实际需求进行调整和扩展,建议在沙箱环境中测试通过后再切换到生产环境。