支付宝支付业务
1. Maven依赖配置
<!-- pom.xml -->
<dependencies><!-- 支付宝SDK --><dependency><groupId>com.alipay.sdk</groupId><artifactId>alipay-sdk-java</artifactId><version>4.35.79.ALL</version></dependency><!-- Spring Boot Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- 数据校验 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency><!-- 配置处理 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency>
</dependencies>2. 支付宝配置类
package com.example.alipay.config;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;@Data
@Configuration
@ConfigurationProperties(prefix = "alipay")
public class AlipayConfig {/*** 应用ID*/private String appId;/*** 商户私钥*/private String privateKey;/*** 支付宝公钥*/private String publicKey;/*** 签名算法类型 RSA2*/private String signType = "RSA2";/*** 字符编码格式*/private String charset = "UTF-8";/*** 支付宝网关*/private String gatewayUrl = "https://openapi.alipay.com/gateway.do";/*** 格式*/private String format = "json";/*** 异步通知地址*/private String notifyUrl;/*** 同步通知地址(支付完成后跳转的页面)*/private String returnUrl;
}3. 支付宝服务配置
package com.example.alipay.config;import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class AlipayClientConfig {@Autowiredprivate AlipayConfig alipayConfig;@Beanpublic AlipayClient alipayClient() {return new DefaultAlipayClient(alipayConfig.getGatewayUrl(),alipayConfig.getAppId(),alipayConfig.getPrivateKey(),alipayConfig.getFormat(),alipayConfig.getCharset(),alipayConfig.getPublicKey(),alipayConfig.getSignType());}
}4. 请求和响应DTO
package com.example.alipay.dto;import lombok.Data;
import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;/*** 支付请求参数*/
@Data
public class PayRequestDTO {@NotBlank(message = "订单号不能为空")private String orderNo;@NotBlank(message = "订单标题不能为空")private String subject;@NotNull(message = "订单金额不能为空")@DecimalMin(value = "0.01", message = "订单金额不能小于0.01")private BigDecimal amount;private String body;private String timeoutExpress = "30m";
}/*** 支付响应*/
@Data
public class PayResponseDTO {private boolean success;private String message;private String payForm; // 支付表单HTMLprivate String tradeNo; // 支付宝交易号private String orderNo; // 商户订单号
}/*** 退款请求参数*/
@Data
public class RefundRequestDTO {@NotBlank(message = "订单号不能为空")private String orderNo;@NotBlank(message = "退款请求号不能为空")private String refundNo;@NotNull(message = "退款金额不能为空")@DecimalMin(value = "0.01", message = "退款金额不能小于0.01")private BigDecimal refundAmount;private String refundReason;
}/*** 退款响应*/
@Data
public class RefundResponseDTO {private boolean success;private String message;private String refundNo;private String tradeNo;
}/*** 查询订单响应*/
@Data
public class QueryResponseDTO {private boolean success;private String message;private String tradeStatus;private String tradeNo;private String orderNo;private BigDecimal totalAmount;private String buyerLogonId;private Date gmtPayment;
}5. 支付宝支付服务
package com.example.alipay.service;import com.alipay.api.AlipayClient;
import com.alipay.api.domain.*;
import com.alipay.api.request.*;
import com.alipay.api.response.*;
import com.example.alipay.config.AlipayConfig;
import com.example.alipay.dto.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;@Slf4j
@Service
public class AlipayService {@Autowiredprivate AlipayClient alipayClient;@Autowiredprivate AlipayConfig alipayConfig;/*** 电脑网站支付*/public PayResponseDTO pagePay(PayRequestDTO payRequest) {try {AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();// 设置异步通知地址request.setNotifyUrl(alipayConfig.getNotifyUrl());// 设置同步通知地址request.setReturnUrl(alipayConfig.getReturnUrl());AlipayTradePagePayModel model = new AlipayTradePagePayModel();model.setOutTradeNo(payRequest.getOrderNo());model.setTotalAmount(payRequest.getAmount().toString());model.setSubject(payRequest.getSubject());model.setBody(payRequest.getBody());model.setProductCode("FAST_INSTANT_TRADE_PAY");model.setTimeoutExpress(payRequest.getTimeoutExpress());request.setBizModel(model);AlipayTradePagePayResponse response = alipayClient.pageExecute(request);PayResponseDTO result = new PayResponseDTO();if (response.isSuccess()) {result.setSuccess(true);result.setPayForm(response.getBody());result.setOrderNo(payRequest.getOrderNo());log.info("支付宝网页支付下单成功,订单号:{}", payRequest.getOrderNo());} else {result.setSuccess(false);result.setMessage(response.getSubMsg());log.error("支付宝网页支付下单失败,订单号:{},错误信息:{}", payRequest.getOrderNo(), response.getSubMsg());}return result;} catch (Exception e) {log.error("支付宝网页支付异常,订单号:{}", payRequest.getOrderNo(), e);PayResponseDTO result = new PayResponseDTO();result.setSuccess(false);result.setMessage("支付系统异常:" + e.getMessage());return result;}}/*** 手机网站支付*/public PayResponseDTO wapPay(PayRequestDTO payRequest) {try {AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();request.setNotifyUrl(alipayConfig.getNotifyUrl());request.setReturnUrl(alipayConfig.getReturnUrl());AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();model.setOutTradeNo(payRequest.getOrderNo());model.setTotalAmount(payRequest.getAmount().toString());model.setSubject(payRequest.getSubject());model.setBody(payRequest.getBody());model.setProductCode("QUICK_WAP_WAY");model.setTimeoutExpress(payRequest.getTimeoutExpress());request.setBizModel(model);AlipayTradeWapPayResponse response = alipayClient.pageExecute(request);PayResponseDTO result = new PayResponseDTO();if (response.isSuccess()) {result.setSuccess(true);result.setPayForm(response.getBody());result.setOrderNo(payRequest.getOrderNo());log.info("支付宝手机网站支付下单成功,订单号:{}", payRequest.getOrderNo());} else {result.setSuccess(false);result.setMessage(response.getSubMsg());log.error("支付宝手机网站支付下单失败,订单号:{},错误信息:{}", payRequest.getOrderNo(), response.getSubMsg());}return result;} catch (Exception e) {log.error("支付宝手机网站支付异常,订单号:{}", payRequest.getOrderNo(), e);PayResponseDTO result = new PayResponseDTO();result.setSuccess(false);result.setMessage("支付系统异常:" + e.getMessage());return result;}}/*** APP支付*/public PayResponseDTO appPay(PayRequestDTO payRequest) {try {AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();request.setNotifyUrl(alipayConfig.getNotifyUrl());AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();model.setOutTradeNo(payRequest.getOrderNo());model.setTotalAmount(payRequest.getAmount().toString());model.setSubject(payRequest.getSubject());model.setBody(payRequest.getBody());model.setProductCode("QUICK_MSECURITY_PAY");model.setTimeoutExpress(payRequest.getTimeoutExpress());request.setBizModel(model);AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);PayResponseDTO result = new PayResponseDTO();if (response.isSuccess()) {result.setSuccess(true);result.setPayForm(response.getBody()); // 这里返回的是订单字符串result.setOrderNo(payRequest.getOrderNo());log.info("支付宝APP支付下单成功,订单号:{}", payRequest.getOrderNo());} else {result.setSuccess(false);result.setMessage(response.getSubMsg());log.error("支付宝APP支付下单失败,订单号:{},错误信息:{}", payRequest.getOrderNo(), response.getSubMsg());}return result;} catch (Exception e) {log.error("支付宝APP支付异常,订单号:{}", payRequest.getOrderNo(), e);PayResponseDTO result = new PayResponseDTO();result.setSuccess(false);result.setMessage("支付系统异常:" + e.getMessage());return result;}}/*** 查询订单状态*/public QueryResponseDTO queryOrder(String orderNo) {try {AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();AlipayTradeQueryModel model = new AlipayTradeQueryModel();model.setOutTradeNo(orderNo);request.setBizModel(model);AlipayTradeQueryResponse response = alipayClient.execute(request);QueryResponseDTO result = new QueryResponseDTO();if (response.isSuccess()) {result.setSuccess(true);result.setTradeStatus(response.getTradeStatus());result.setTradeNo(response.getTradeNo());result.setOrderNo(response.getOutTradeNo());result.setTotalAmount(new BigDecimal(response.getTotalAmount()));result.setBuyerLogonId(response.getBuyerLogonId());if (response.getGmtPayment() != null) {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");result.setGmtPayment(sdf.parse(response.getGmtPayment()));}log.info("支付宝订单查询成功,订单号:{},状态:{}", orderNo, response.getTradeStatus());} else {result.setSuccess(false);result.setMessage(response.getSubMsg());log.error("支付宝订单查询失败,订单号:{},错误信息:{}", orderNo, response.getSubMsg());}return result;} catch (Exception e) {log.error("支付宝订单查询异常,订单号:{}", orderNo, e);QueryResponseDTO result = new QueryResponseDTO();result.setSuccess(false);result.setMessage("查询系统异常:" + e.getMessage());return result;}}/*** 退款*/public RefundResponseDTO refund(RefundRequestDTO refundRequest) {try {AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();AlipayTradeRefundModel model = new AlipayTradeRefundModel();model.setOutTradeNo(refundRequest.getOrderNo());model.setOutRequestNo(refundRequest.getRefundNo());model.setRefundAmount(refundRequest.getRefundAmount().toString());model.setRefundReason(refundRequest.getRefundReason());request.setBizModel(model);AlipayTradeRefundResponse response = alipayClient.execute(request);RefundResponseDTO result = new RefundResponseDTO();if (response.isSuccess()) {result.setSuccess(true);result.setRefundNo(refundRequest.getRefundNo());result.setTradeNo(response.getTradeNo());log.info("支付宝退款成功,订单号:{},退款单号:{}", refundRequest.getOrderNo(), refundRequest.getRefundNo());} else {result.setSuccess(false);result.setMessage(response.getSubMsg());log.error("支付宝退款失败,订单号:{},退款单号:{},错误信息:{}", refundRequest.getOrderNo(), refundRequest.getRefundNo(), response.getSubMsg());}return result;} catch (Exception e) {log.error("支付宝退款异常,订单号:{},退款单号:{}", refundRequest.getOrderNo(), refundRequest.getRefundNo(), e);RefundResponseDTO result = new RefundResponseDTO();result.setSuccess(false);result.setMessage("退款系统异常:" + e.getMessage());return result;}}/*** 关闭订单*/public boolean closeOrder(String orderNo) {try {AlipayTradeCloseRequest request = new AlipayTradeCloseRequest();AlipayTradeCloseModel model = new AlipayTradeCloseModel();model.setOutTradeNo(orderNo);request.setBizModel(model);AlipayTradeCloseResponse response = alipayClient.execute(request);if (response.isSuccess()) {log.info("支付宝订单关闭成功,订单号:{}", orderNo);return true;} else {log.error("支付宝订单关闭失败,订单号:{},错误信息:{}", orderNo, response.getSubMsg());return false;}} catch (Exception e) {log.error("支付宝订单关闭异常,订单号:{}", orderNo, e);return false;}}
}6. 支付回调处理
package com.example.alipay.service;import com.alipay.api.internal.util.AlipaySignature;
import com.example.alipay.config.AlipayConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;@Slf4j
@Service
public class AlipayCallbackService {@Autowiredprivate AlipayConfig alipayConfig;@Autowiredprivate OrderService orderService; // 假设有订单服务/*** 处理支付宝异步通知*/public String handleAsyncNotify(HttpServletRequest request) {try {// 将异步通知中收到的所有参数都存放到map中Map<String, String> params = convertRequestParamsToMap(request);log.info("收到支付宝异步通知,参数:{}", params);// 验证签名boolean signVerified = AlipaySignature.rsaCheckV1(params, alipayConfig.getPublicKey(), alipayConfig.getCharset(), alipayConfig.getSignType());if (!signVerified) {log.error("支付宝异步通知签名验证失败");return "failure";}// 验证通知数据的正确性String appId = params.get("app_id");String sellerId = params.get("seller_id");if (!alipayConfig.getAppId().equals(appId)) {log.error("支付宝异步通知app_id不匹配");return "failure";}// 处理业务逻辑String tradeStatus = params.get("trade_status");String orderNo = params.get("out_trade_no");String tradeNo = params.get("trade_no");String totalAmount = params.get("total_amount");if ("TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus)) {// 支付成功,更新订单状态boolean success = orderService.updateOrderStatus(orderNo, tradeNo, totalAmount);if (success) {log.info("订单支付成功处理完成,订单号:{}", orderNo);return "success";} else {log.error("订单支付成功但业务处理失败,订单号:{}", orderNo);return "failure";}} else if ("WAIT_BUYER_PAY".equals(tradeStatus)) {// 交易创建,等待买家付款log.info("订单等待支付,订单号:{}", orderNo);return "success";} else if ("TRADE_CLOSED".equals(tradeStatus)) {// 未付款交易超时关闭,或支付完成后全额退款log.info("订单已关闭,订单号:{}", orderNo);return "success";}return "success";} catch (Exception e) {log.error("处理支付宝异步通知异常", e);return "failure";}}/*** 处理同步返回*/public boolean handleSyncReturn(HttpServletRequest request) {try {Map<String, String> params = convertRequestParamsToMap(request);log.info("收到支付宝同步返回,参数:{}", params);// 验证签名boolean signVerified = AlipaySignature.rsaCheckV1(params, alipayConfig.getPublicKey(), alipayConfig.getCharset(), alipayConfig.getSignType());if (!signVerified) {log.error("支付宝同步返回签名验证失败");return false;}// 业务处理...return true;} catch (Exception e) {log.error("处理支付宝同步返回异常", e);return false;}}/*** 将request中的参数转换成Map*/private Map<String, String> convertRequestParamsToMap(HttpServletRequest request) {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 params;}
}7. 控制器
package com.example.alipay.controller;import com.example.alipay.dto.*;
import com.example.alipay.service.AlipayCallbackService;
import com.example.alipay.service.AlipayService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@Slf4j
@RestController
@RequestMapping("/api/alipay")
public class AlipayController {@Autowiredprivate AlipayService alipayService;@Autowiredprivate AlipayCallbackService alipayCallbackService;/*** 电脑网站支付*/@PostMapping("/page-pay")public PayResponseDTO pagePay(@Validated @RequestBody PayRequestDTO payRequest) {return alipayService.pagePay(payRequest);}/*** 手机网站支付*/@PostMapping("/wap-pay")public PayResponseDTO wapPay(@Validated @RequestBody PayRequestDTO payRequest) {return alipayService.wapPay(payRequest);}/*** APP支付*/@PostMapping("/app-pay")public PayResponseDTO appPay(@Validated @RequestBody PayRequestDTO payRequest) {return alipayService.appPay(payRequest);}/*** 查询订单状态*/@GetMapping("/query/{orderNo}")public QueryResponseDTO queryOrder(@PathVariable String orderNo) {return alipayService.queryOrder(orderNo);}/*** 退款*/@PostMapping("/refund")public RefundResponseDTO refund(@Validated @RequestBody RefundRequestDTO refundRequest) {return alipayService.refund(refundRequest);}/*** 关闭订单*/@PostMapping("/close/{orderNo}")public ApiResponse closeOrder(@PathVariable String orderNo) {boolean success = alipayService.closeOrder(orderNo);ApiResponse response = new ApiResponse();response.setSuccess(success);response.setMessage(success ? "订单关闭成功" : "订单关闭失败");return response;}/*** 支付宝异步通知回调*/@PostMapping("/notify")public String asyncNotify(HttpServletRequest request, HttpServletResponse httpResponse) {return alipayCallbackService.handleAsyncNotify(request);}/*** 支付宝同步返回*/@GetMapping("/return")public String syncReturn(HttpServletRequest request) {boolean success = alipayCallbackService.handleSyncReturn(request);if (success) {return "支付成功!";} else {return "支付验证失败!";}}
}/*** 通用API响应*/
@Data
class ApiResponse {private boolean success;private String message;private Object data;
}8. 配置文件
# application.yml
alipay:app-id: your_app_idprivate-key: your_private_keypublic-key: your_alipay_public_keysign-type: RSA2charset: UTF-8gateway-url: https://openapi.alipay.com/gateway.donotify-url: https://your-domain.com/api/alipay/notifyreturn-url: https://your-domain.com/api/alipay/return# 日志配置
logging:level:com.example.alipay: DEBUG9. 异常处理
package com.example.alipay.handler;import com.example.alipay.dto.ApiResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {/*** 参数校验异常处理*/@ExceptionHandler(BindException.class)public ApiResponse handleBindException(BindException e) {String message = e.getBindingResult().getAllErrors().get(0).getDefaultMessage();ApiResponse response = new ApiResponse();response.setSuccess(false);response.setMessage(message);return response;}/*** 通用异常处理*/@ExceptionHandler(Exception.class)public ApiResponse handleException(Exception e) {log.error("系统异常", e);ApiResponse response = new ApiResponse();response.setSuccess(false);response.setMessage("系统繁忙,请稍后重试");return response;}
}使用说明:
配置支付宝参数:在支付宝开放平台获取AppID、商户私钥、支付宝公钥
选择支付方式:
电脑网站支付:
pagePay手机网站支付:
wapPayAPP支付:
appPay
处理回调:配置异步通知地址和同步返回地址
订单状态管理:通过查询接口获取订单状态
退款功能:支持全额或部分退款
