From 91c52a1281791e59570342b264b1066477aa23cc Mon Sep 17 00:00:00 2001 From: zhangli <123879394@qq.com> Date: Tue, 2 Sep 2025 00:11:37 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=94=AF=E4=BB=98=E5=AE=9D?= =?UTF-8?q?=E6=94=AF=E4=BB=98=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 11 + .../java/com/sczx/pay/config/AlipayConf.java | 113 +++++ .../pay/controller/AliPaymentController.java | 182 +++++++ .../com/sczx/pay/dto/AlipayCloseRequest.java | 14 + .../com/sczx/pay/dto/AlipayCreateRequest.java | 14 + .../sczx/pay/dto/AlipayCreateResponse.java | 14 + .../com/sczx/pay/dto/AlipayQueryRequest.java | 11 + .../com/sczx/pay/dto/AlipayQueryResponse.java | 14 + .../com/sczx/pay/dto/AlipayRefundRequest.java | 14 + .../java/com/sczx/pay/dto/AlipayResponse.java | 10 + .../sczx/pay/entity/CompanyAlipayConfig.java | 44 ++ .../pay/mapper/CompanyAlipayConfigMapper.java | 22 + .../com/sczx/pay/service/AlipayService.java | 47 ++ .../pay/service/impl/AlipayServiceImpl.java | 479 ++++++++++++++++++ src/main/resources/application.yml | 11 + 15 files changed, 1000 insertions(+) create mode 100644 src/main/java/com/sczx/pay/config/AlipayConf.java create mode 100644 src/main/java/com/sczx/pay/controller/AliPaymentController.java create mode 100644 src/main/java/com/sczx/pay/dto/AlipayCloseRequest.java create mode 100644 src/main/java/com/sczx/pay/dto/AlipayCreateRequest.java create mode 100644 src/main/java/com/sczx/pay/dto/AlipayCreateResponse.java create mode 100644 src/main/java/com/sczx/pay/dto/AlipayQueryRequest.java create mode 100644 src/main/java/com/sczx/pay/dto/AlipayQueryResponse.java create mode 100644 src/main/java/com/sczx/pay/dto/AlipayRefundRequest.java create mode 100644 src/main/java/com/sczx/pay/dto/AlipayResponse.java create mode 100644 src/main/java/com/sczx/pay/entity/CompanyAlipayConfig.java create mode 100644 src/main/java/com/sczx/pay/mapper/CompanyAlipayConfigMapper.java create mode 100644 src/main/java/com/sczx/pay/service/AlipayService.java create mode 100644 src/main/java/com/sczx/pay/service/impl/AlipayServiceImpl.java diff --git a/pom.xml b/pom.xml index d430497..861e86c 100644 --- a/pom.xml +++ b/pom.xml @@ -216,6 +216,17 @@ 4.5.13 + + + + + + + com.alipay.sdk + alipay-sdk-java + 4.40.427.ALL + + diff --git a/src/main/java/com/sczx/pay/config/AlipayConf.java b/src/main/java/com/sczx/pay/config/AlipayConf.java new file mode 100644 index 0000000..15c95ec --- /dev/null +++ b/src/main/java/com/sczx/pay/config/AlipayConf.java @@ -0,0 +1,113 @@ +package com.sczx.pay.config; + + +import com.alipay.api.AlipayApiException; +import com.alipay.api.AlipayClient; +import com.alipay.api.AlipayConfig; +import com.alipay.api.DefaultAlipayClient; +import com.sczx.pay.entity.CompanyAlipayConfig; +import com.sczx.pay.mapper.CompanyAlipayConfigMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +@Component +public class AlipayConf { + + @Value("${ali.pay.app-id}") + private String appId; + + @Value("${alipay.gateway-url}") + private String gatewayUrl; + + @Value("${ali.pay.privateKey}") + private String privateKey; + +// @Value("${alipay.miniapp.publicKey}") +// private String publicKey; + + @Value("${ali.pay.appCertPath}") + private String appCertPath; + + @Value("${ali.pay.alipayCertPath}") + private String alipayCertPath; + + @Value("${ali.pay.alipayRootCertPath}") + private String alipayRootCertPath; + + + @Autowired + private CompanyAlipayConfigMapper companyAlipayConfigMapper; + + private static final Map apiClientMap = new HashMap<>(); + + private static AlipayClient alipayClient; + + public AlipayClient alipayClient() throws AlipayApiException { + + if(Objects.nonNull(alipayClient)){ + AlipayConfig alipayConfig = new AlipayConfig(); + //设置网关地址 + alipayConfig.setServerUrl(gatewayUrl); + //设置应用ID + alipayConfig.setAppId(appId); + //设置应用私钥 + alipayConfig.setPrivateKey(privateKey); + //设置请求格式,固定值json + alipayConfig.setFormat("JSON"); + //设置字符集 + alipayConfig.setCharset("UTF-8"); + //设置签名类型 + alipayConfig.setSignType("RSA2"); + //设置应用公钥证书路径 + alipayConfig.setAppCertPath(appCertPath); + //设置支付宝公钥证书路径 + alipayConfig.setAlipayPublicCertPath(alipayCertPath); + //设置支付宝根证书路径 + alipayConfig.setRootCertPath(alipayRootCertPath); + + alipayClient = new DefaultAlipayClient(alipayConfig); + } + return alipayClient; + } + + public String getCompanyAppid(Long companyId) throws AlipayApiException { + CompanyAlipayConfig companyAlipayConfig = companyAlipayConfigMapper.getConfigByCompanyId(companyId); + if(Objects.nonNull(companyAlipayConfig)){ + return companyAlipayConfig.getMchId(); + }else { + throw new AlipayApiException("未找到公司对应的支付宝支付配置"); + } + } + + + /** + * 获取支付宝客户端 + * @param companyId + * @param privateKey + * @param alipayPublicKey + * @return + * @throws AlipayApiException + */ + public AlipayClient alipayClient(Long companyId, String privateKey, String alipayPublicKey) throws AlipayApiException { + AlipayClient alipayClient = apiClientMap.get(companyId.toString()); + if(Objects.isNull(alipayClient)){ + AlipayConfig alipayConfig = new AlipayConfig(); + alipayConfig.setServerUrl(gatewayUrl); + alipayConfig.setAppId(appId); + alipayConfig.setPrivateKey(privateKey); + alipayConfig.setFormat("json"); + alipayConfig.setAlipayPublicKey(alipayPublicKey); + alipayConfig.setCharset("UTF-8"); + alipayConfig.setSignType("RSA2"); + alipayClient = new DefaultAlipayClient(alipayConfig); + apiClientMap.put(companyId.toString(),alipayClient); + } + + return alipayClient; + } +} diff --git a/src/main/java/com/sczx/pay/controller/AliPaymentController.java b/src/main/java/com/sczx/pay/controller/AliPaymentController.java new file mode 100644 index 0000000..fec0f92 --- /dev/null +++ b/src/main/java/com/sczx/pay/controller/AliPaymentController.java @@ -0,0 +1,182 @@ +package com.sczx.pay.controller; + +import com.sczx.pay.dto.*; +import com.sczx.pay.service.AlipayService; +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.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +@Slf4j +@RestController +@RequestMapping("/api/alipay") +public class AliPaymentController { + + @Autowired + private AlipayService alipayService; + + /** + * 支付宝统一下单接口 + */ + @PostMapping("/unifiedOrder") + public AlipayCreateResponse unifiedOrder(@RequestBody AlipayCreateRequest request) { + log.info("收到支付宝支付请求: {}", request); + return alipayService.unifiedOrder(request); + } + + /** + * 查询订单接口 + */ + @GetMapping("/query/{companyId}/{outTradeNo}") + public AlipayQueryResponse orderQuery(@PathVariable Long companyId, @PathVariable String outTradeNo) { + log.info("收到支付宝订单查询请求,公司ID: {}, 订单号: {}", companyId, outTradeNo); + return alipayService.orderQuery(companyId, outTradeNo); + } + + /** + * 关闭订单接口 + */ + @PostMapping("/close") + public AlipayResponse closeOrder(@RequestBody AlipayCloseRequest request) { + log.info("收到支付宝关闭订单请求: {}", request); + return alipayService.closeOrder(request); + } + + /** + * 申请退款接口 + */ + @PostMapping("/refund") + public AlipayResponse refund(@RequestBody AlipayRefundRequest request) { + log.info("收到支付宝退款请求: {}", request); + return alipayService.refund(request); + } + + /** + * 查询退款接口 + */ + @PostMapping("/refundQuery") + public AlipayResponse refundQuery(@RequestBody AlipayRefundRequest request) { + log.info("收到支付宝退款查询请求: {}", request); + return alipayService.refundQuery(request); + } + + /** + * 支付宝支付结果通知 + */ + @PostMapping("/notify") + public String notify(HttpServletRequest request) { + try { + // 读取支付宝回调数据 + Map params = new HashMap<>(); + Map requestParams = request.getParameterMap(); + for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) { + String name = iter.next(); + 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); + } + + String outTradeNo = params.get("out_trade_no"); + String companyIdStr = params.get("passback_params"); // 通过回传参数获取公司ID + Long companyId = companyIdStr != null ? Long.parseLong(companyIdStr) : null; + + log.info("收到支付宝支付通知,数据: {}, 公司ID: {}, 订单号: {}", params, companyId, outTradeNo); + + // 验证签名 + if (!alipayService.verifyNotifySign(companyId, params)) { + log.warn("支付宝支付通知签名验证失败,公司ID: {}", companyId); + return buildResponse("failure"); + } + + String tradeStatus = params.get("trade_status"); + if (!"TRADE_SUCCESS".equals(tradeStatus) && !"TRADE_FINISHED".equals(tradeStatus)) { + log.warn("支付宝支付通知状态失败,公司ID: {}: {}", companyId, tradeStatus); + return buildResponse("success"); // 状态不是成功时也返回success,避免重复通知 + } + + // 处理支付成功的业务逻辑 + String tradeNo = params.get("trade_no"); + String totalAmount = params.get("total_amount"); + + // 更新数据库中的订单状态 + boolean success = alipayService.processPaySuccessNotify(companyId, params); + if (success) { + log.info("支付宝支付成功,公司ID: {}, 订单号: {}, 支付宝交易号: {}, 金额: {}", + companyId, outTradeNo, tradeNo, totalAmount); + return buildResponse("success"); + } else { + log.error("更新支付宝支付状态失败,公司ID: {}, 订单号: {}", companyId, outTradeNo); + return buildResponse("failure"); + } + + } catch (Exception e) { + log.error("处理支付宝支付通知异常", e); + return buildResponse("failure"); + } + } + + /** + * 支付宝退款结果通知 + */ + @PostMapping("/refundNotify") + public String refundNotify(HttpServletRequest request) { + try { + // 读取支付宝退款回调数据 + Map params = new HashMap<>(); + Map requestParams = request.getParameterMap(); + for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) { + String name = iter.next(); + 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); + } + + log.info("收到支付宝退款通知, 数据: {}", params); + + // 验证签名 + // 注意:支付宝退款通知的签名验证方式可能与支付通知不同 + // 这里简化处理,实际应根据支付宝文档实现 + + String outTradeNo = params.get("out_trade_no"); + String refundStatus = params.get("refund_status"); + + if (!"REFUND_SUCCESS".equals(refundStatus)) { + log.warn("支付宝退款通知状态失败: {}", refundStatus); + return buildResponse("success"); + } + + // 处理退款通知的业务逻辑 + String outRequestNo = params.get("out_request_no"); + String refundAmount = params.get("refund_amount"); + + // 更新数据库中的退款状态 + boolean success = alipayService.processRefundNotify(params); + if (success) { + log.info("支付宝退款处理完成,订单号: {}, 退款请求号: {}, 退款金额: {}, 状态: {}", + outTradeNo, outRequestNo, refundAmount, refundStatus); + return buildResponse("success"); + } else { + log.error("更新支付宝退款状态失败,订单号: {}, 退款请求号: {}", outTradeNo, outRequestNo); + return buildResponse("failure"); + } + + } catch (Exception e) { + log.error("处理支付宝退款通知异常", e); + return buildResponse("failure"); + } + } + + private String buildResponse(String result) { + return result; + } +} diff --git a/src/main/java/com/sczx/pay/dto/AlipayCloseRequest.java b/src/main/java/com/sczx/pay/dto/AlipayCloseRequest.java new file mode 100644 index 0000000..d6ad1d0 --- /dev/null +++ b/src/main/java/com/sczx/pay/dto/AlipayCloseRequest.java @@ -0,0 +1,14 @@ +package com.sczx.pay.dto; + +import lombok.Data; + +// 支付宝查询请求 +@Data +public class AlipayCloseRequest { + private Long companyId; + private String outTradeNo; // 商户订单号 + private String reasonCode; //原因编码 + private String reasonDesc; + private String openId; //买家支付宝用户唯一标识 + +} diff --git a/src/main/java/com/sczx/pay/dto/AlipayCreateRequest.java b/src/main/java/com/sczx/pay/dto/AlipayCreateRequest.java new file mode 100644 index 0000000..a8a0fc0 --- /dev/null +++ b/src/main/java/com/sczx/pay/dto/AlipayCreateRequest.java @@ -0,0 +1,14 @@ +package com.sczx.pay.dto; + +import lombok.Data; + +// 支付宝支付请求 +@Data +public class AlipayCreateRequest { + private Long companyId; // 公司ID + private String outTradeNo; // 商户订单号 + private String subject; // 订单标题 + private String totalAmount; // 订单总金额 + private String body; // 订单描述 + private String openId; // 用户ID +} diff --git a/src/main/java/com/sczx/pay/dto/AlipayCreateResponse.java b/src/main/java/com/sczx/pay/dto/AlipayCreateResponse.java new file mode 100644 index 0000000..a5388f3 --- /dev/null +++ b/src/main/java/com/sczx/pay/dto/AlipayCreateResponse.java @@ -0,0 +1,14 @@ +package com.sczx.pay.dto; + +import lombok.Data; + +// 支付宝支付响应 +@Data +public class AlipayCreateResponse { + private boolean success; + private String message; + private String tradeNo; // 支付宝交易号 + private String outTradeNo; // 商户订单号 + private String orderStr; // 支付串(用于前端调起支付) + private String code; // 状态码 +} diff --git a/src/main/java/com/sczx/pay/dto/AlipayQueryRequest.java b/src/main/java/com/sczx/pay/dto/AlipayQueryRequest.java new file mode 100644 index 0000000..a0d63b2 --- /dev/null +++ b/src/main/java/com/sczx/pay/dto/AlipayQueryRequest.java @@ -0,0 +1,11 @@ +package com.sczx.pay.dto; + +import lombok.Data; + +// 支付宝查询请求 +@Data +public class AlipayQueryRequest { + private Long companyId; + private String outTradeNo; // 商户订单号 + private String tradeNo; // 支付宝交易号(可选,与outTradeNo二选一) +} diff --git a/src/main/java/com/sczx/pay/dto/AlipayQueryResponse.java b/src/main/java/com/sczx/pay/dto/AlipayQueryResponse.java new file mode 100644 index 0000000..5f53535 --- /dev/null +++ b/src/main/java/com/sczx/pay/dto/AlipayQueryResponse.java @@ -0,0 +1,14 @@ +package com.sczx.pay.dto; + +import lombok.Data; + +// 支付宝订单查询响应 +@Data +public class AlipayQueryResponse { + private boolean success; + private String message; + private String tradeNo; // 支付宝交易号 + private String outTradeNo; // 商户订单号 + private String tradeStatus; // 交易状态 + private String code; // 状态码 +} diff --git a/src/main/java/com/sczx/pay/dto/AlipayRefundRequest.java b/src/main/java/com/sczx/pay/dto/AlipayRefundRequest.java new file mode 100644 index 0000000..0d1d75f --- /dev/null +++ b/src/main/java/com/sczx/pay/dto/AlipayRefundRequest.java @@ -0,0 +1,14 @@ +package com.sczx.pay.dto; + +import lombok.Data; + +// 支付宝退款请求 +@Data +public class AlipayRefundRequest { + private Long companyId; + private String outTradeNo; // 商户订单号 + private String refundAmount; // 退款金额 + private String refundReason; // 退款原因 + private String outRequestNo; // 退款请求号 + private String tradeNo; // 支付宝交易号(可选,与outTradeNo二选一) +} diff --git a/src/main/java/com/sczx/pay/dto/AlipayResponse.java b/src/main/java/com/sczx/pay/dto/AlipayResponse.java new file mode 100644 index 0000000..5767619 --- /dev/null +++ b/src/main/java/com/sczx/pay/dto/AlipayResponse.java @@ -0,0 +1,10 @@ +package com.sczx.pay.dto; + +import lombok.Data; + +@Data +public class AlipayResponse { + private boolean success; + private String message; + private String code; // 状态码 +} diff --git a/src/main/java/com/sczx/pay/entity/CompanyAlipayConfig.java b/src/main/java/com/sczx/pay/entity/CompanyAlipayConfig.java new file mode 100644 index 0000000..66d9c34 --- /dev/null +++ b/src/main/java/com/sczx/pay/entity/CompanyAlipayConfig.java @@ -0,0 +1,44 @@ +package com.sczx.pay.entity; + +/** + * 公司支付宝支付配置实体类 + */ +public class CompanyAlipayConfig { + private Long id; + private String mchId; + private String apikey; + + // 构造函数 + public CompanyAlipayConfig() {} + + public CompanyAlipayConfig(Long id, String mchId, String apikey) { + this.id = id; + this.mchId = mchId; + this.apikey = apikey; + } + + // Getter和Setter方法 + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getMchId() { + return mchId; + } + + public void setMchId(String mchId) { + this.mchId = mchId; + } + + public String getApikey() { + return apikey; + } + + public void setApikey(String apikey) { + this.apikey = apikey; + } +} diff --git a/src/main/java/com/sczx/pay/mapper/CompanyAlipayConfigMapper.java b/src/main/java/com/sczx/pay/mapper/CompanyAlipayConfigMapper.java new file mode 100644 index 0000000..2885413 --- /dev/null +++ b/src/main/java/com/sczx/pay/mapper/CompanyAlipayConfigMapper.java @@ -0,0 +1,22 @@ +package com.sczx.pay.mapper; + +import com.sczx.pay.entity.CompanyAlipayConfig; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +@Mapper +public interface CompanyAlipayConfigMapper { + + /** + * 根据公司ID获取支付宝支付配置 + * @param companyId 公司ID + * @return 微信支付配置信息 + */ + @Select("SELECT id, ali_receiving_account AS mchId, ali_key AS apikey FROM zc_company WHERE id = #{companyId}") + CompanyAlipayConfig getConfigByCompanyId(@Param("companyId") Long companyId); + + + @Select("SELECT id,ali_receiving_account AS mchId, ali_key AS apikey FROM zc_company WHERE ali_receiving_account = #{mchId} limit 1") + CompanyAlipayConfig getCompanyIdByMchId(@Param("mchId") String mchId); +} diff --git a/src/main/java/com/sczx/pay/service/AlipayService.java b/src/main/java/com/sczx/pay/service/AlipayService.java new file mode 100644 index 0000000..2391c45 --- /dev/null +++ b/src/main/java/com/sczx/pay/service/AlipayService.java @@ -0,0 +1,47 @@ +package com.sczx.pay.service; + +import com.sczx.pay.dto.*; + +import java.util.Map; + +public interface AlipayService { + /** + * 支付宝统一下单 + */ + AlipayCreateResponse unifiedOrder(AlipayCreateRequest request); + + /** + * 查询订单 + */ + AlipayQueryResponse orderQuery(Long companyId, String outTradeNo); + + /** + * 关闭订单 + */ + AlipayResponse closeOrder(AlipayCloseRequest alipayCloseRequest); + + /** + * 申请退款 + */ + AlipayResponse refund(AlipayRefundRequest request); + + /** + * 查询退款 + */ + AlipayResponse refundQuery(AlipayRefundRequest refundQueryRequest); + + /** + * 验证通知签名 + */ + boolean verifyNotifySign(Long companyId, Map params); + + /** + * 处理支付成功通知 + */ + boolean processPaySuccessNotify(Long companyId, Map notifyMap); + + /** + * 处理退款通知 + */ + boolean processRefundNotify(Map notifyMap); +} diff --git a/src/main/java/com/sczx/pay/service/impl/AlipayServiceImpl.java b/src/main/java/com/sczx/pay/service/impl/AlipayServiceImpl.java new file mode 100644 index 0000000..2e43e00 --- /dev/null +++ b/src/main/java/com/sczx/pay/service/impl/AlipayServiceImpl.java @@ -0,0 +1,479 @@ +package com.sczx.pay.service.impl; + + +import com.alipay.api.AlipayApiException; +import com.alipay.api.AlipayClient; +import com.alipay.api.domain.*; +import com.alipay.api.internal.util.AlipaySignature; +import com.alipay.api.request.*; +import com.alipay.api.response.*; +import com.sczx.pay.config.AlipayConf; +import com.sczx.pay.dto.*; +import com.sczx.pay.entity.OrderMain; +import com.sczx.pay.entity.PayStatus; +import com.sczx.pay.entity.PaymentRecord; +import com.sczx.pay.entity.RefundRecord; +import com.sczx.pay.mapper.OrderPayMapper; +import com.sczx.pay.mapper.PaymentRecordMapper; +import com.sczx.pay.mapper.RefundRecordMapper; +import com.sczx.pay.service.AlipayService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.Map; + +@Slf4j +@Service +public class AlipayServiceImpl implements AlipayService { + + @Autowired + private AlipayConf alipayConf; + + @Value("${ali.pay.app-id}") + private String appId; + + @Value("${ali.pay.notify-url}") + private String notifyUrl; + + @Value("${ali.pay.refund-notify-url}") + private String refundNotifyUrl; + + @Value("${ali.pay.privateKey}") + private String privateKey; + +// @Value("${alipay.miniapp.publicKey}") +// private String publicKey; + + @Value("${ali.pay.appCertPath}") + private String appCertPath; + + @Value("${ali.pay.alipayCertPath}") + private String alipayCertPath; + + @Value("${ali.pay.alipayRootCertPath}") + private String alipayRootCertPath; + + + @Autowired + private PaymentRecordMapper paymentRecordMapper; + + @Autowired + private RefundRecordMapper refundRecordMapper; + + @Autowired + private OrderPayMapper orderPayMapper; + + @Override + public AlipayCreateResponse unifiedOrder(AlipayCreateRequest alipayCreateRequest) { + AlipayCreateResponse response = new AlipayCreateResponse(); + try { + AlipayClient alipayClient = alipayConf.alipayClient(); + + // 构造请求参数以调用接口 + AlipayTradeCreateRequest request = new AlipayTradeCreateRequest(); + AlipayTradeCreateModel model = new AlipayTradeCreateModel(); + + // 设置商户订单号 + model.setOutTradeNo(alipayCreateRequest.getOutTradeNo()); + + // 设置订单总金额 + model.setTotalAmount(alipayCreateRequest.getTotalAmount()); + + // 设置订单标题 + model.setSubject(alipayCreateRequest.getSubject()); + + // 设置订单相对超时时间 +// model.setTimeoutExpress("90m"); + + // uid参数未来计划废弃,存量商户可继续使用,新商户请使用openid。请根据应用-开发配置-openid配置选择支持的字段。 + // model.setBuyerId("2088102146225135"); + + // 设置买家支付宝用户唯一标识 + model.setBuyerOpenId(alipayCreateRequest.getOpenId()); + + model.setOpAppId(alipayConf.getCompanyAppid(alipayCreateRequest.getCompanyId())); + + // 设置产品码 + model.setProductCode("JSAPI_PAY"); + + + request.setBizModel(model); + //设置回调地址 + request.setNotifyUrl(notifyUrl); + + // 第三方代调用模式下请设置app_auth_token + // request.putOtherTextParam("app_auth_token", "<-- 请填写应用授权令牌 -->"); + + AlipayTradeCreateResponse alipayResponse = alipayClient.certificateExecute(request); + + if (alipayResponse.isSuccess()) { + response.setSuccess(true); + response.setOrderStr(alipayResponse.getBody()); + response.setOutTradeNo(alipayCreateRequest.getOutTradeNo()); + response.setTradeNo(alipayResponse.getTradeNo()); + response.setCode("SUCCESS"); + response.setMessage("下单成功"); + //保存支付单 + recordPaymentInfo(alipayCreateRequest); + + } else { + response.setSuccess(false); + response.setCode("FAIL"); + response.setMessage("下单失败: " + alipayResponse.getMsg() + ":" + alipayResponse.getSubMsg()); + } + } catch (Exception e) { + log.error("支付宝下单异常,公司ID: {}, 订单号: {}", alipayCreateRequest.getCompanyId(), alipayCreateRequest.getOutTradeNo(), e); + response.setSuccess(false); + response.setCode("FAIL"); + response.setMessage("下单异常: " + e.getMessage()); + } + + return response; + } + + @Override + public AlipayQueryResponse orderQuery(Long companyId, String outTradeNo) { + AlipayQueryResponse response = new AlipayQueryResponse(); + try { + AlipayClient alipayClient = alipayConf.alipayClient(); + + // 构造请求参数以调用接口 + // 构造请求参数以调用接口 + AlipayTradeQueryRequest request = new AlipayTradeQueryRequest(); + AlipayTradeQueryModel model = new AlipayTradeQueryModel(); + + // 设置订单支付时传入的商户订单号 + model.setOutTradeNo(outTradeNo); + + request.setBizModel(model); + + // 第三方代调用模式下请设置app_auth_token + // request.putOtherTextParam("app_auth_token", "<-- 请填写应用授权令牌 -->"); + + AlipayTradeQueryResponse alipayResponse = alipayClient.certificateExecute(request); + + if (alipayResponse.isSuccess()) { + response.setSuccess(true); + response.setOutTradeNo(alipayResponse.getOutTradeNo()); + response.setTradeNo(alipayResponse.getTradeNo()); + response.setTradeStatus(alipayResponse.getTradeStatus()); + response.setCode("SUCCESS"); + response.setMessage("查询支付单成功"); + } else { + response.setSuccess(false); + response.setCode("FAIL"); + response.setMessage("查询支付单失败: " + alipayResponse.getMsg() + ":" + alipayResponse.getSubMsg()); + } + } catch (Exception e) { + log.error("支付宝订单查询异常,公司ID: {}, 订单号: {}", companyId, outTradeNo, e); + response.setSuccess(false); + response.setCode("FAIL"); + response.setMessage("支付宝订单查询败异常: " + e.getMessage()); + } + return response; + } + + @Override + public AlipayResponse closeOrder(AlipayCloseRequest alipayCloseRequest) { + AlipayResponse response = new AlipayResponse(); + try { + AlipayClient alipayClient = alipayConf.alipayClient(); + // 构造请求参数以调用接口 + AlipayTradeCloseRequest request = new AlipayTradeCloseRequest(); + AlipayTradeCloseModel model = new AlipayTradeCloseModel(); + + + // 设置订单支付时传入的商户订单号 + model.setOutTradeNo(alipayCloseRequest.getOutTradeNo()); + + request.setBizModel(model); + // 第三方代调用模式下请设置app_auth_token + // request.putOtherTextParam("app_auth_token", "<-- 请填写应用授权令牌 -->"); + + AlipayTradeCloseResponse closeResponse = alipayClient.certificateExecute(request); + log.info("关闭订单响应 : {}",closeResponse.getBody()); + + if (closeResponse.isSuccess()) { + response.setSuccess(true); + response.setCode("SUCCESS"); + response.setMessage("关闭支付单成功"); + } else { + response.setSuccess(false); + response.setCode("FAIL"); + response.setMessage("关闭支付单失败: " + closeResponse.getMsg() + ":" + closeResponse.getSubMsg()); + } + } catch (Exception e) { + log.error("支付宝关闭异常,公司ID: {}, 订单号: {}", alipayCloseRequest.getCompanyId(), alipayCloseRequest.getOutTradeNo(), e); + response.setSuccess(false); + response.setCode("FAIL"); + response.setMessage("关闭支付单失败异常: " + e.getMessage()); + } + return response; + } + + @Override + public AlipayResponse refund(AlipayRefundRequest request) { + AlipayResponse response = new AlipayResponse(); + try { + AlipayClient alipayClient = alipayConf.alipayClient(); + // 构造请求参数以调用接口 + AlipayTradeRefundRequest refundRequest = new AlipayTradeRefundRequest(); + AlipayTradeRefundModel model = new AlipayTradeRefundModel(); + + // 设置商户订单号 + model.setOutTradeNo(request.getOutTradeNo()); +// +// // 设置支付宝交易号 +// model.setTradeNo("2014112611001004680073956707"); + + // 设置退款金额 + model.setRefundAmount(request.getRefundAmount()); + + // 设置退款原因说明 + model.setRefundReason(request.getRefundReason()); + + // 设置退款请求号 + model.setOutRequestNo(request.getOutRequestNo()); + refundRequest.setBizModel(model); + + AlipayTradeRefundResponse refundResponse = alipayClient.certificateExecute(refundRequest); + log.info("退款响应 : {}",refundResponse.getBody()); + + if (refundResponse.isSuccess()) { + response.setSuccess(true); + response.setCode("SUCCESS"); + response.setMessage("发起退款成功"); + //保存退款信息 + recordRefundInfo(request); + } else { + response.setSuccess(false); + response.setCode("FAIL"); + response.setMessage("退款失败: " + refundResponse.getMsg() + ":" + refundResponse.getSubMsg()); + } + } catch (Exception e) { + log.error("支付宝退款异常,公司ID: {}, 订单号: {}", request.getCompanyId(), request.getOutTradeNo(), e); + response.setSuccess(false); + response.setCode("FAIL"); + response.setMessage("退款失败异常: " + e.getMessage()); + } + return response; + } + + @Override + public AlipayResponse refundQuery(AlipayRefundRequest refundQueryRequest) { + AlipayResponse response = new AlipayResponse(); + try { + AlipayClient alipayClient = alipayConf.alipayClient(); + // 构造请求参数以调用接口 + AlipayTradeFastpayRefundQueryRequest request = new AlipayTradeFastpayRefundQueryRequest(); + AlipayTradeFastpayRefundQueryModel model = new AlipayTradeFastpayRefundQueryModel(); + + // 设置商户订单号 + model.setOutTradeNo(refundQueryRequest.getOutTradeNo()); + + // 设置退款请求号 + model.setOutRequestNo(refundQueryRequest.getOutRequestNo()); + + + request.setBizModel(model); + // 第三方代调用模式下请设置app_auth_token + // request.putOtherTextParam("app_auth_token", "<-- 请填写应用授权令牌 -->"); + + AlipayTradeFastpayRefundQueryResponse refundQueryResponse = alipayClient.certificateExecute(request); + log.info("退款查询响应 : {}",refundQueryResponse.getBody()); + + if (refundQueryResponse.isSuccess() && "REFUND_SUCCESS".equals(refundQueryResponse.getRefundStatus())) { + response.setSuccess(true); + response.setCode("SUCCESS"); + response.setMessage("退款成功"); + } else { + response.setSuccess(false); + response.setCode("FAIL"); + response.setMessage("退款查询失败: " + refundQueryResponse.getMsg() + ":" + refundQueryResponse.getSubMsg()); + } + } catch (Exception e) { + log.error("支付宝退款异常,公司ID: {}, 订单号: {}", refundQueryRequest.getCompanyId(), refundQueryRequest.getOutTradeNo(), e); + response.setSuccess(false); + response.setCode("FAIL"); + response.setMessage("支付宝退款失败异常: " + e.getMessage()); + } + return response; + } + + @Override + public boolean verifyNotifySign(Long companyId, Map params) { + try { + return AlipaySignature.rsaCertCheckV1(params, alipayCertPath, "UTF-8", "RSA2"); + } catch (AlipayApiException e) { + log.error("支付宝通知签名验证异常,公司ID: {}", companyId, e); + return false; + } + } + + @Override + public boolean processPaySuccessNotify(Long companyId, Map notifyMap) { + try { + // 这里实现您的业务逻辑 + // 例如:更新订单状态、发送通知等 + + String outTradeNo = notifyMap.get("out_trade_no"); + String tradeNo = notifyMap.get("trade_no"); + String totalAmount = notifyMap.get("total_amount"); + + log.info("处理支付宝支付成功通知,公司ID: {}, 订单号: {}, 交易号: {}, 金额: {}", + companyId, outTradeNo, tradeNo, totalAmount); + + // 更新支付记录状态 + int updated = paymentRecordMapper.updateToSuccess( + outTradeNo, + tradeNo, + new Date(), // 支付时间 + new Date() // 更新时间 + ); + if (updated > 0) { + log.info("支付宝支付记录状态已更新,订单号: {}, 支付宝交易号: {}", outTradeNo, tradeNo); + //更新主订单状态 + OrderMain orderMain = orderPayMapper.getOrderStatusByOrderNo(outTradeNo); + String OrderStatus = orderMain.getOrderStatus(); + + if(OrderStatus.equals("WAIT_PAY")){ + orderPayMapper.updateOrderStatus(orderMain.getOrderNo(),"WAIT_PICK"); + }else if (OrderStatus.equals("RERENT_WAIT_PAY")){ + orderPayMapper.updateOrderStatus(orderMain.getOrderNo(),"RENT_ING"); + } + orderPayMapper.updateSubOrderPaymentStatus(outTradeNo,"ZFB_PAY", PayStatus.SUCCESS.getCode(),tradeNo); + return true; + } else { + log.warn("未找到对应的支付宝支付记录,订单号: {}", outTradeNo); + return false; + } + } catch (Exception e) { + log.error("处理支付宝支付成功通知异常,公司ID: {}", companyId, e); + return false; + } + } + + @Override + public boolean processRefundNotify(Map notifyMap) { + try { + String outTradeNo = notifyMap.get("out_trade_no"); + String outRequestNo = notifyMap.get("out_request_no"); + String refundAmount = notifyMap.get("refund_amount"); + String refundStatus = notifyMap.get("refund_status"); + + log.info("处理支付宝退款通知,订单号: {}, 退款请求号: {}, 退款金额: {}", + outTradeNo, outRequestNo, refundAmount); +// +// +// String outRefundNo = notifyData.get("out_refund_no"); +// String refundId = notifyData.get("refund_id"); +// String refundStatus = notifyData.get("refund_status"); +// String outTradeNo = notifyData.get("out_trade_no"); +// BigDecimal refundFee = new BigDecimal(notifyData.get("refund_fee")); + + // 根据退款状态更新退款记录 + String statusDesc = ""; + String payStatus = ""; + statusDesc = "退款成功"; + payStatus = "REFUND_SUCCESS"; +// switch (refundStatus) { +// case "SUCCESS": +// statusDesc = "退款成功"; +// payStatus = "REFUND_SUCCESS"; +// break; +// case "REFUNDCLOSE": +// statusDesc = "退款关闭"; +// payStatus = "REFUND_SUCCESS"; +// break; +// case "PROCESSING": +// statusDesc = "退款处理中"; +// payStatus = "REFUNDING"; +// break; +// case "CHANGE": +// statusDesc = "退款异常"; +// payStatus = "REFUND_ERROR"; +// break; +// default: +// statusDesc = "未知状态"; +// payStatus = "REFUND_ERROR"; +// } + orderPayMapper.updateSubOrderRefundStatus(outTradeNo,payStatus,new BigDecimal(refundAmount),new Date(),outRequestNo); + int updated = refundRecordMapper.updateRefundStatus( + outRequestNo, + refundStatus, + statusDesc, + outRequestNo, + "SUCCESS".equals(refundStatus) ? new Date() : null, // 退款成功时间 + new Date() // 更新时间 + ); + + if (updated > 0) { + log.info("支付宝退款记录状态已更新,退款单号: {}, 支付宝退款单号: {}, 状态: {}", outRequestNo, outRequestNo, refundStatus); + return true; + } else { + log.warn("未找到对应的微信退款记录,退款单号: {}", outRequestNo); + return false; + } + } catch (Exception e) { + log.error("处理微信退款通知异常,退款单号: {}", notifyMap.get("out_request_no"), e); + return false; + } + } + + /** + * 记录支付信息到数据库 + */ + private void recordPaymentInfo(AlipayCreateRequest request) { + try { + PaymentRecord paymentRecord = new PaymentRecord(); + paymentRecord.setCompanyId(request.getCompanyId()); + paymentRecord.setOutTradeNo(request.getOutTradeNo()); + paymentRecord.setTotalFee(new BigDecimal(request.getTotalAmount())); // 转换为元 + paymentRecord.setBody(request.getBody()); + paymentRecord.setOpenid(request.getOpenId()); + paymentRecord.setTradeState("NOTPAY"); // 未支付 + paymentRecord.setTradeStateDesc("未支付"); + paymentRecord.setCreateTime(new Date()); + paymentRecord.setUpdateTime(new Date()); +// paymentRecord.setAttach(request.getAttach()); + paymentRecord.setPayChannel(PaymentRecord.PayChannel.ALIPAY.name()); // 设置支付渠道为支付宝支付 + + paymentRecordMapper.insertPaymentRecord(paymentRecord); + log.info("支付记录已保存,订单号: {}", request.getOutTradeNo()); + } catch (Exception e) { + log.error("保存支付记录异常,订单号: {}", request.getOutTradeNo(), e); + } + } + + /** + * 记录退款信息到数据库 + */ + private void recordRefundInfo(AlipayRefundRequest request) { + try { + RefundRecord refundRecord = new RefundRecord(); + refundRecord.setCompanyId(request.getCompanyId()); + refundRecord.setOutTradeNo(request.getOutTradeNo()); + refundRecord.setOutRefundNo(request.getOutRequestNo()); +// refundRecord.setTotalFee(totalFee); + refundRecord.setRefundFee(new BigDecimal(request.getRefundAmount())); // 转换为元 + refundRecord.setRefundDesc(request.getRefundReason()); + refundRecord.setCreateTime(new Date()); + refundRecord.setUpdateTime(new Date()); + + refundRecord.setRefundStatus("PROCESSING"); // 退款处理中 + refundRecord.setRefundStatusDesc("退款处理中"); + refundRecord.setRefundId(request.getOutRequestNo()); + refundRecord.setPayChannel(PaymentRecord.PayChannel.ALIPAY.name()); + + + refundRecordMapper.insertRefundRecord(refundRecord); + log.info("退款记录已保存,退款单号: {}", request.getOutRequestNo()); + } catch (Exception e) { + log.error("保存退款记录异常,退款单号: {}", request.getOutRequestNo(), e); + } + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index c4b27a9..1c361c5 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -63,5 +63,16 @@ wechat: notify-url: https://www.minbo.wang:8020/api/payment/notify refund-notify-url: https://www.minbo.wang:8020/api/payment/refundNotify +ali: + pay: + app-id: 2021004169641281 + gateway-url: https://openapi.alipay.com/gateway.do + notify-url: https://www.minbo.wang:8020/api/alipay/notify + refund-notify-url: https://www.minbo.wang:8020/api/alipay/refundNotify + privateKey: MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCQke+mZsxNXJXMn2iUZRkhITWY9qPczwHMgRxl68JRuNzZE2AXhAc2ciF7EGob1y0al4hvJo5JUrDew9Zkv0BocAsPjLma3A9KFgj131xMuLxVvHtktkNSwwW9VIbOOhFAQAy3J9jt8PdEk40UONyu9J5Shjs6jbQ8RogdDuwuzKpNj0ZOTeUqgR6RME4xZ0VqvZe9XhVfq3QtVGttUzOpLPNg6boBy/5RqwC64lVFICMqjKkMW2NklVPBDFO46QwfWEbaA+APnd9bd+9WadyNySPb7kAK8GOlvZYfysy+QkOQdj/oebKWKzdKXpFnF+n52dYzeGTvckt1suDngwAFAgMBAAECggEAcPc39iTZe5HfE9d0FpCxBCw4/1+qRz4SP8SbdiC05Lq5B36WVYm7QRYJh2oaH8sR2XeTCpdsE2tj/Y21l1/Calkyq2HhHlraL5/sPIPeUa0ArVXsbZPmI2N0tq6376l8FWJ3DR876SGjdZh+YtDT0HogxIdS/LwBnB/Y+CvS7fWcqiMjcR4h28RU70CQqxpzYuPfqG6GZmByGyJAcdlhFAYgiksb+qZnkjoaKHsjb61xfUX4z+HGdQLqOlVKfNqIpiO7arXaeAb0RQiB8Lqi7fBvn8LLhlTmM1Hr4gyQO14lJmP5Vp2BIg9m5AC9vRkpZ9l79bUTIepDe9+Ovcx5eQKBgQDWZ5yoz8q8Z5VIfMSVTHO3wpfwOBM92S2c21hTsds7NezsMVqGcTuAcvbMW2i1MwxtS7kahXraRAxZnCDB9ZVJs+88xcgu5QJWZ1rJyrwEwB2gTQhColv+XZW6Ck/J6kk2/PG26rNQG6pg/xrKaMtPnXXyKCsdQTyEpr+mlNIJ2wKBgQCsnf4lIuwftCSm0jI73tO1Bb4U9TCIapKidnIhutbyg6u+hJMUTVDNkjsBnrTN24sSP7Cu4Zs/W4lkDqq86fHNEvnF+FouIfO/CwaGteDBNwXHSLM0D+zEBbK04bfoYi7lYZeDRPygFrM49Sxkp0MAmItDmXqbYRQBlhN1XVzznwKBgQCQ+72fFex1XOJBA0X345v4rlkKMxEn6J2EjXr8FbA3KO8OhQ0/DoD7CkLDzChRJ7UGj4cbXRnHUO69BevM3SHXlhp4ERKeS3Q6M2fcPwDHgZZHGPA2Bw6IQoaGKITt+EUMLx3Q4ILi7+JV9wwJxbV+H+9rEiidfsjKtuuwXMBvswKBgQChpElrCSrH/W8c8FSuD9l7+GapRXkvJW0uyW/S+h1yd66J96erKUNzXW339GAnLWErs4yGFynDyLn9gmaMBR6zBQP0SL5Z2N1hlreDyikvhZDZrtBw/kCexx8zlvMan2Z+0kaJXD6cwuUNfzkVADQUCMTQhpZzjhKn8ZtDGiyCzQKBgQCAhU0khG/ufZfQ089+1G7PAlErBr5MQaG40a2vfIWGtHkYyXq5N/3jow1bd2qsyLuz8mr2sWQeURK+B2xZridf6JtYz3gB+dLw0frlLKk4Q6jeehiRlE8H8tIYe/7KcgTmdIzEbo3lmyGMFAILvr/pSCWeUehQYR9PH91Qyi+Tog== + # publicKey: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArPG4JQ9YY9+tOeImQO0eNkp+NZkenJ9hMHEVVmwAHAI5BoJMCLvAm504BXSpgpqaiCJ6ARTwBkiDz4dyCMVfE3VE8+oMFtXqfHaZLhfd+X9VQNqRCz0HeR2IbjGnnbYxQOAEOM6z092UfNieG00HyU5yREfzjJkIcyuGeGgbIBG1gPpLhXsQKRhQYqp4Exgd4LX6qnKLPL90kJVkQnHcJkp+rCoQ5zS6ZUXE2d/2GzY7xi93uTU2CLMiZ7Vi2OZ1g7xY+yDQzTA/CseveJeW3rM6T8yBjlEJwsywEL5co3YqpJUIMIe/fLjhRRgj+JUq5w0sRqb3+CswQHIjgc71QwIDAQAB + appCertPath: /root/cert//appCertPublicKey_2021005174658269.crt + alipayCertPath: /root/cert//alipayCertPublicKey_RSA2.crt + alipayRootCertPath: /root/cert/alipayRootCert.crt cert-path: /root/cert/ \ No newline at end of file