- 添加支付常量类PaymentConstants,定义支付状态、微信、支付宝、银联等相关常量 - 创建微信支付类型常量类WechatPayType,支持JSAPI、NATIVE、H5、APP支付方式 - 新增支付控制器PaymentController,提供创建支付、查询状态、退款等统一接口 - 实现支付回调控制器PaymentNotifyController,处理微信、支付宝、银联异步通知 - 添加支付请求数据传输对象PaymentRequest,支持多种支付方式参数校验 - 定义支付响应、状态更新请求等相关DTO类- 集成Swagger注解,完善接口文档说明- 添加参数校验和异常处理机制,确保支付流程安全可靠
361 lines
16 KiB
Java
361 lines
16 KiB
Java
package com.gxwebsoft.payment.controller;
|
||
|
||
import com.gxwebsoft.common.core.web.ApiResult;
|
||
import com.gxwebsoft.common.core.web.BaseController;
|
||
import com.gxwebsoft.common.system.entity.User;
|
||
import com.gxwebsoft.payment.constants.PaymentConstants;
|
||
import com.gxwebsoft.payment.dto.PaymentRequest;
|
||
import com.gxwebsoft.payment.dto.PaymentResponse;
|
||
import com.gxwebsoft.payment.dto.PaymentStatusUpdateRequest;
|
||
import com.gxwebsoft.payment.dto.PaymentWithOrderRequest;
|
||
import com.gxwebsoft.payment.enums.PaymentType;
|
||
import com.gxwebsoft.payment.exception.PaymentException;
|
||
import com.gxwebsoft.payment.service.PaymentService;
|
||
import io.swagger.v3.oas.annotations.Operation;
|
||
import io.swagger.v3.oas.annotations.Parameter;
|
||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||
import lombok.extern.slf4j.Slf4j;
|
||
import org.springframework.validation.annotation.Validated;
|
||
import org.springframework.web.bind.annotation.*;
|
||
|
||
import javax.annotation.Resource;
|
||
import javax.validation.Valid;
|
||
import javax.validation.constraints.NotBlank;
|
||
import javax.validation.constraints.NotNull;
|
||
import javax.validation.constraints.Positive;
|
||
import java.math.BigDecimal;
|
||
import java.util.List;
|
||
import java.util.Map;
|
||
|
||
/**
|
||
* 统一支付控制器
|
||
* 提供所有支付方式的统一入口
|
||
*
|
||
* @author 科技小王子
|
||
* @since 2025-01-26
|
||
*/
|
||
@Slf4j
|
||
@Validated
|
||
@Tag(name = "统一支付接口", description = "支持所有支付方式的统一支付接口")
|
||
@RestController("unifiedPaymentController")
|
||
@RequestMapping("/api/payment")
|
||
public class PaymentController extends BaseController {
|
||
|
||
@Resource(name = "unifiedPaymentServiceImpl")
|
||
private PaymentService paymentService;
|
||
|
||
@Operation(summary = "创建支付订单", description = "支持微信、支付宝、银联等多种支付方式")
|
||
@PostMapping("/create")
|
||
public ApiResult<?> createPayment(@Valid @RequestBody PaymentRequest request) {
|
||
log.info("收到支付请求: {}", request);
|
||
final User loginUser = getLoginUser();
|
||
|
||
if(loginUser == null){
|
||
return fail("请先登录");
|
||
}
|
||
|
||
request.setUserId(loginUser.getUserId());
|
||
if(request.getTenantId() == null){
|
||
request.setTenantId(loginUser.getTenantId());
|
||
}
|
||
try {
|
||
PaymentResponse response = paymentService.createPayment(request);
|
||
return this.<PaymentResponse>success("支付订单创建成功", response);
|
||
|
||
} catch (PaymentException e) {
|
||
log.error("支付订单创建失败: {}", e.getMessage());
|
||
return fail(e.getMessage());
|
||
} catch (Exception e) {
|
||
log.error("支付订单创建系统错误: {}", e.getMessage(), e);
|
||
return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR);
|
||
}
|
||
}
|
||
|
||
@Operation(summary = "创建支付订单(包含订单信息)", description = "统一支付模块:创建订单并发起支付")
|
||
@PostMapping("/create-with-order")
|
||
public ApiResult<?> createPaymentWithOrder(@Valid @RequestBody PaymentWithOrderRequest request) {
|
||
log.info("收到支付与订单创建请求: {}", request);
|
||
final User loginUser = getLoginUser();
|
||
|
||
if(loginUser == null){
|
||
return fail("请先登录");
|
||
}
|
||
|
||
// 设置用户信息
|
||
if(request.getTenantId() == null){
|
||
request.setTenantId(loginUser.getTenantId());
|
||
}
|
||
|
||
try {
|
||
PaymentResponse response = paymentService.createPaymentWithOrder(request, loginUser);
|
||
return this.<PaymentResponse>success("订单创建并发起支付成功", response);
|
||
} catch (PaymentException e) {
|
||
log.error("创建支付订单失败: {}", e.getMessage());
|
||
return fail(e.getMessage());
|
||
} catch (Exception e) {
|
||
log.error("创建支付订单系统错误: {}", e.getMessage(), e);
|
||
return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR);
|
||
}
|
||
}
|
||
|
||
@Operation(summary = "查询支付状态", description = "查询指定订单的支付状态")
|
||
@GetMapping("/query")
|
||
public ApiResult<?> queryPayment(
|
||
@Parameter(description = "订单号", required = true)
|
||
@RequestParam @NotBlank(message = "订单号不能为空") String orderNo,
|
||
|
||
@Parameter(description = "支付类型", required = true)
|
||
@RequestParam @NotNull(message = "支付类型不能为空") PaymentType paymentType,
|
||
|
||
@Parameter(description = "租户ID", required = true)
|
||
@RequestParam @NotNull(message = "租户ID不能为空") @Positive(message = "租户ID必须为正数") Integer tenantId) {
|
||
|
||
log.info("查询支付状态: orderNo={}, paymentType={}, tenantId={}", orderNo, paymentType, tenantId);
|
||
|
||
// 参数验证
|
||
if (orderNo == null || orderNo.trim().isEmpty()) {
|
||
return fail("订单号不能为空");
|
||
}
|
||
if (paymentType == null) {
|
||
return fail("支付类型不能为空");
|
||
}
|
||
if (tenantId == null || tenantId <= 0) {
|
||
return fail("租户ID不能为空且必须为正数");
|
||
}
|
||
|
||
try {
|
||
PaymentResponse response = paymentService.queryPayment(orderNo, paymentType, tenantId);
|
||
return this.<PaymentResponse>success("支付状态查询成功", response);
|
||
|
||
} catch (PaymentException e) {
|
||
log.error("支付状态查询失败: {}", e.getMessage());
|
||
return fail(e.getMessage());
|
||
} catch (Exception e) {
|
||
log.error("支付状态查询系统错误: {}", e.getMessage(), e);
|
||
return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR);
|
||
}
|
||
}
|
||
|
||
@Operation(summary = "申请退款", description = "申请订单退款")
|
||
@PostMapping("/refund")
|
||
public ApiResult<?> refund(
|
||
@Parameter(description = "订单号", required = true)
|
||
@RequestParam @NotBlank(message = "订单号不能为空") String orderNo,
|
||
|
||
@Parameter(description = "退款单号", required = true)
|
||
@RequestParam @NotBlank(message = "退款单号不能为空") String refundNo,
|
||
|
||
@Parameter(description = "支付类型", required = true)
|
||
@RequestParam @NotNull(message = "支付类型不能为空") PaymentType paymentType,
|
||
|
||
@Parameter(description = "订单总金额", required = true)
|
||
@RequestParam @NotNull(message = "订单总金额不能为空") @Positive(message = "订单总金额必须大于0") BigDecimal totalAmount,
|
||
|
||
@Parameter(description = "退款金额", required = true)
|
||
@RequestParam @NotNull(message = "退款金额不能为空") @Positive(message = "退款金额必须大于0") BigDecimal refundAmount,
|
||
|
||
@Parameter(description = "退款原因")
|
||
@RequestParam(required = false) String reason,
|
||
|
||
@Parameter(description = "租户ID", required = true)
|
||
@RequestParam @NotNull(message = "租户ID不能为空") @Positive(message = "租户ID必须为正数") Integer tenantId) {
|
||
|
||
log.info("申请退款: orderNo={}, refundNo={}, paymentType={}, totalAmount={}, refundAmount={}, tenantId={}",
|
||
orderNo, refundNo, paymentType, totalAmount, refundAmount, tenantId);
|
||
|
||
try {
|
||
PaymentResponse response = paymentService.refund(orderNo, refundNo, paymentType,
|
||
totalAmount, refundAmount, reason, tenantId);
|
||
return this.<PaymentResponse>success("退款申请成功", response);
|
||
|
||
} catch (PaymentException e) {
|
||
log.error("退款申请失败: {}", e.getMessage());
|
||
return fail(e.getMessage());
|
||
} catch (Exception e) {
|
||
log.error("退款申请系统错误: {}", e.getMessage(), e);
|
||
return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR);
|
||
}
|
||
}
|
||
|
||
@Operation(summary = "查询退款状态", description = "查询指定退款单的状态")
|
||
@GetMapping("/refund/query")
|
||
public ApiResult<?> queryRefund(
|
||
@Parameter(description = "退款单号", required = true)
|
||
@RequestParam @NotBlank(message = "退款单号不能为空") String refundNo,
|
||
|
||
@Parameter(description = "支付类型", required = true)
|
||
@RequestParam @NotNull(message = "支付类型不能为空") PaymentType paymentType,
|
||
|
||
@Parameter(description = "租户ID", required = true)
|
||
@RequestParam @NotNull(message = "租户ID不能为空") @Positive(message = "租户ID必须为正数") Integer tenantId) {
|
||
|
||
log.info("查询退款状态: refundNo={}, paymentType={}, tenantId={}", refundNo, paymentType, tenantId);
|
||
|
||
try {
|
||
PaymentResponse response = paymentService.queryRefund(refundNo, paymentType, tenantId);
|
||
return this.<PaymentResponse>success("退款状态查询成功", response);
|
||
|
||
} catch (PaymentException e) {
|
||
log.error("退款状态查询失败: {}", e.getMessage());
|
||
return fail(e.getMessage());
|
||
} catch (Exception e) {
|
||
log.error("退款状态查询系统错误: {}", e.getMessage(), e);
|
||
return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR);
|
||
}
|
||
}
|
||
|
||
@Operation(summary = "关闭订单", description = "关闭未支付的订单")
|
||
@PostMapping("/close")
|
||
public ApiResult<?> closeOrder(
|
||
@Parameter(description = "订单号", required = true)
|
||
@RequestParam @NotBlank(message = "订单号不能为空") String orderNo,
|
||
|
||
@Parameter(description = "支付类型", required = true)
|
||
@RequestParam @NotNull(message = "支付类型不能为空") PaymentType paymentType,
|
||
|
||
@Parameter(description = "租户ID", required = true)
|
||
@RequestParam @NotNull(message = "租户ID不能为空") @Positive(message = "租户ID必须为正数") Integer tenantId) {
|
||
|
||
log.info("关闭订单: orderNo={}, paymentType={}, tenantId={}", orderNo, paymentType, tenantId);
|
||
|
||
try {
|
||
boolean result = paymentService.closeOrder(orderNo, paymentType, tenantId);
|
||
return success(result ? "订单关闭成功" : "订单关闭失败", result);
|
||
|
||
} catch (PaymentException e) {
|
||
log.error("订单关闭失败: {}", e.getMessage());
|
||
return fail(e.getMessage());
|
||
} catch (Exception e) {
|
||
log.error("订单关闭系统错误: {}", e.getMessage(), e);
|
||
return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR);
|
||
}
|
||
}
|
||
|
||
@Operation(summary = "获取支持的支付类型", description = "获取系统支持的所有支付类型列表")
|
||
@GetMapping("/types")
|
||
public ApiResult<?> getSupportedPaymentTypes() {
|
||
try {
|
||
List<PaymentType> paymentTypes = paymentService.getSupportedPaymentTypes();
|
||
return this.<List<PaymentType>>success("获取支付类型成功", paymentTypes);
|
||
} catch (Exception e) {
|
||
log.error("获取支付类型失败: {}", e.getMessage(), e);
|
||
return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR);
|
||
}
|
||
}
|
||
|
||
@Operation(summary = "获取支付策略信息", description = "获取指定支付类型的策略信息")
|
||
@GetMapping("/strategy/{paymentType}")
|
||
public ApiResult<?> getPaymentStrategyInfo(
|
||
@Parameter(description = "支付类型", required = true)
|
||
@PathVariable @NotNull(message = "支付类型不能为空") PaymentType paymentType) {
|
||
|
||
try {
|
||
Map<String, Object> strategyInfo = paymentService.getPaymentStrategyInfo(paymentType);
|
||
if (strategyInfo == null) {
|
||
return fail("不支持的支付类型: " + paymentType);
|
||
}
|
||
return success("获取策略信息成功", strategyInfo);
|
||
} catch (Exception e) {
|
||
log.error("获取策略信息失败: {}", e.getMessage(), e);
|
||
return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR);
|
||
}
|
||
}
|
||
|
||
@Operation(summary = "获取所有支付策略信息", description = "获取系统所有支付策略的详细信息")
|
||
@GetMapping("/strategies")
|
||
public ApiResult<?> getAllPaymentStrategyInfo() {
|
||
try {
|
||
List<Map<String, Object>> strategiesInfo = paymentService.getAllPaymentStrategyInfo();
|
||
return this.<List<Map<String, Object>>>success("获取所有策略信息成功", strategiesInfo);
|
||
} catch (Exception e) {
|
||
log.error("获取所有策略信息失败: {}", e.getMessage(), e);
|
||
return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR);
|
||
}
|
||
}
|
||
|
||
@Operation(summary = "检查支付类型支持情况", description = "检查指定支付类型的功能支持情况")
|
||
@GetMapping("/support/{paymentType}")
|
||
public ApiResult<?> checkPaymentTypeSupport(
|
||
@Parameter(description = "支付类型", required = true)
|
||
@PathVariable @NotNull(message = "支付类型不能为空") PaymentType paymentType) {
|
||
|
||
try {
|
||
Map<String, Boolean> support = Map.of(
|
||
"supported", paymentService.isPaymentTypeSupported(paymentType),
|
||
"refundSupported", paymentService.isRefundSupported(paymentType),
|
||
"querySupported", paymentService.isQuerySupported(paymentType),
|
||
"closeSupported", paymentService.isCloseSupported(paymentType),
|
||
"notifyNeeded", paymentService.isNotifyNeeded(paymentType)
|
||
);
|
||
return this.<Map<String, Boolean>>success("检查支持情况成功", support);
|
||
} catch (Exception e) {
|
||
log.error("检查支持情况失败: {}", e.getMessage(), e);
|
||
return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR);
|
||
}
|
||
}
|
||
|
||
@Operation(summary = "手动更新支付状态", description = "用于手动同步支付状态,通常用于异常情况处理")
|
||
@PutMapping("/update-status")
|
||
public ApiResult<?> updatePaymentStatus(@Valid @RequestBody PaymentStatusUpdateRequest request) {
|
||
log.info("收到支付状态更新请求: {}", request);
|
||
|
||
try {
|
||
// 查询并更新支付状态
|
||
PaymentResponse response = paymentService.queryPayment(
|
||
request.getOrderNo(),
|
||
PaymentType.WECHAT_NATIVE,
|
||
request.getTenantId()
|
||
);
|
||
|
||
return this.<PaymentResponse>success("支付状态更新成功", response);
|
||
} catch (Exception e) {
|
||
log.error("更新支付状态失败: {}", e.getMessage(), e);
|
||
return fail("更新支付状态失败: " + e.getMessage());
|
||
}
|
||
}
|
||
|
||
@Operation(summary = "检查支付配置", description = "检查指定租户的支付配置是否完整")
|
||
@GetMapping("/config/check")
|
||
public ApiResult<?> checkPaymentConfig(
|
||
@Parameter(description = "租户ID", required = true)
|
||
@RequestParam @NotNull(message = "租户ID不能为空") @Positive(message = "租户ID必须为正数") Integer tenantId) {
|
||
|
||
log.info("检查支付配置,租户ID: {}", tenantId);
|
||
|
||
try {
|
||
Map<String, Object> configStatus = paymentService.checkPaymentConfig(tenantId);
|
||
return this.<Map<String, Object>>success("配置检查完成", configStatus);
|
||
} catch (Exception e) {
|
||
log.error("检查支付配置失败: {}", e.getMessage(), e);
|
||
return fail("检查支付配置失败: " + e.getMessage());
|
||
}
|
||
}
|
||
|
||
@Operation(summary = "查询用户最近的支付订单", description = "当orderNo缺失时,查询用户最近创建的支付订单")
|
||
@GetMapping("/query-recent")
|
||
public ApiResult<?> queryRecentPayment(
|
||
@Parameter(description = "支付类型", required = true)
|
||
@RequestParam @NotNull(message = "支付类型不能为空") PaymentType paymentType,
|
||
|
||
@Parameter(description = "租户ID", required = true)
|
||
@RequestParam @NotNull(message = "租户ID不能为空") @Positive(message = "租户ID必须为正数") Integer tenantId) {
|
||
|
||
log.info("查询用户最近支付订单: paymentType={}, tenantId={}", paymentType, tenantId);
|
||
|
||
final User loginUser = getLoginUser();
|
||
if(loginUser == null){
|
||
return fail("请先登录");
|
||
}
|
||
|
||
try {
|
||
// 这里需要实现查询用户最近订单的逻辑
|
||
// 可以通过用户ID和租户ID查询最近创建的订单
|
||
return fail("此功能需要实现查询用户最近订单的业务逻辑");
|
||
|
||
} catch (Exception e) {
|
||
log.error("查询用户最近支付订单失败: {}", e.getMessage(), e);
|
||
return fail("查询失败: " + e.getMessage());
|
||
}
|
||
}
|
||
}
|