Files
template-10559/java/payment/controller/PaymentController.java
赵忠林 5749fab9e8 feat(payment): 初始化支付模块核心代码
- 添加支付常量类PaymentConstants,定义支付状态、微信、支付宝、银联等相关常量
- 创建微信支付类型常量类WechatPayType,支持JSAPI、NATIVE、H5、APP支付方式
- 新增支付控制器PaymentController,提供创建支付、查询状态、退款等统一接口
- 实现支付回调控制器PaymentNotifyController,处理微信、支付宝、银联异步通知
- 添加支付请求数据传输对象PaymentRequest,支持多种支付方式参数校验
- 定义支付响应、状态更新请求等相关DTO类- 集成Swagger注解,完善接口文档说明- 添加参数校验和异常处理机制,确保支付流程安全可靠
2025-11-03 12:31:47 +08:00

361 lines
16 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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());
}
}
}