SpringBoot 支付渠道实现统一的支付服务示例

 更新时间:2026年03月13日 09:55:00   作者:Java程序员 拥抱ai  
本文提出了一种基于工厂模式和策略模式的多渠道支付封装方案,该设计采用策略模式实现各支付渠道(微信、支付宝、银联)的统一接口,通过工厂模式动态创建支付策略,感兴趣的可以了解一下

设计思路

使用工厂和策略模式设计一个可扩展的多渠道支付封装方案,支持微信、支付宝、银联等支付渠道。

  • 策略模式:每个支付渠道实现统一的支付接口;
  • 工厂模式:根据支付类型创建对应的支付策略;
  • 配置化管理:支付参数通过配置文件管理;
  • 统一响应:标准化支付返回结果。

设计优势:

  • 开闭原则:新增支付渠道只需实现PayStrategy接口,无需修改现有代码;
  • 统一入口:通过PayService提供统一的支付入口
  • 配置化:支付参数通过配置文件管理,便于不同环境部署
  • 异常处理:统一的异常处理机制
  • 易于扩展:支持添加新的支付渠道和支付方式
  • 维护性:代码结构清晰,易于维护和测试

实现代码

主要包含:支付相关枚举、支付请求和响应对象、支付策略接口、支付策略实现、支付策略工厂、统一支付服务。

依赖 pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>
 
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
 
<dependency>
    <groupId>com.github.wechatpay-apiv3</groupId>
    <artifactId>wechatpay-java</artifactId>
    <version>0.2.17</version>
</dependency>
 
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

支付相关枚举定义

支付渠道 PayChannel.java

@Getter
@AllArgsConstructor
@NoArgsConstructor
public enum PayChannel {
 
    WECHAT_PAY("wechat", "微信支付"),
    ALI_PAY("alipay", "支付宝"),
    UNION_PAY("union", "银联支付");
 
    private String code;
 
    private String name;
 
    public static PayChannel getByCode(String code) {
        for (PayChannel item : values()) {
            if (item.getCode().equals(code)) {
                return item;
            }
        }
        return null;
    }
 
}
 
支付状态 PayStatus.java
 
```java
@Getter
@AllArgsConstructor
@NoArgsConstructor
public enum PayStatus {
 
    WAITING(0, "待支付"),
 
    SUCCESS(1, "成功"),
 
    FAILED(2, "失败"),
 
    CANCELED(3, "已取消"),
 
    REFUND(4, "已退款");
 
    private Integer code;
 
    private String desc;
 
    public static PayStatus getByCode(String code) {
        for (PayStatus item : values()) {
            if (item.getCode().equals(code)) {
                return item;
            }
        }
        return null;
    }
 
}

交易类型 TradeType.java,根据支付渠道筛选可用的交易类型

@Getter
@AllArgsConstructor
@NoArgsConstructor
public enum TradeType {
 
    APP("app", "APP支付"),
    JSAPI("jsapi", "公众号/小程序支付"),
    NATIVE("native", "扫码支付"),
    H5("h5", "H5支付");
 
    private String code;
 
    private String desc;
 
    public static TradeType getByCode(String code) {
        for (TradeType item : values()) {
            if (item.getCode().equals(code)) {
                return item;
            }
        }
        return null;
    }
 
}

交易方式 TradeMethod.java

@Getter
@AllArgsConstructor
@NoArgsConstructor
public enum TradeMethod {
 
    PAY("pay", "支付"),
    REFUND("refund", "退款");
 
    private String code;
 
    private String desc;
 
    public static TradeMethod getByCode(String code) {
        for (TradeMethod item : values()) {
            if (item.getCode().equals(code)) {
                return item;
            }
        }
        return null;
    }
 
}

常量 Constants.java

public class Constants {
 
    /**
     * 操作状态
     */
    public final static Integer OPERATE_SUCCESS_STATE = 200;
    public final static String OPERATE_SUCCESS_MSG = "success";
 
    public final static Integer OPERATE_ERROR_STATE = 500;
    public final static String OPERATE_ERROR_MSG = "error";
 
}

支付请求和响应对象

公共请求参数 BaseRequest.java

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class BaseRequest implements Serializable {
 
    /**
     * appid
     */
    private String appId;
 
    /**
     * 商户号
     */
    private String mchId;
 
    /**
     * 商户证书序列号
     */
    private String serialNo;
 
    /**
     * 商户API私钥
     */
    private String privateKey;
 
    /**
     * 商户API公钥
     */
    private String publicKey;
 
    /**
     * 商户APIV3密钥
     */
    private String apiV3Key;
 
}

关闭订单响应参数 CloseResponse.java

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class CloseResponse implements Serializable {
 
    private static final long serialVersionUID = 1L;
 
    /**
     * 是否成功
     */
    private Boolean success;
 
    /**
     * 订单号
     */
    private String orderNo;
 
    /**
     * 错误码
     */
    private String errorCode;
 
    /**
     * 错误信息
     */
    private String errorMsg;
 
    public static CloseResponse success(String orderNo) {
        CloseResponse response = new CloseResponse();
        response.setSuccess(true);
        response.setOrderNo(orderNo);
        return response;
    }
 
    public static CloseResponse failure(String errorCode, String errorMsg) {
        CloseResponse response = new CloseResponse();
        response.setSuccess(false);
        response.setErrorCode(errorCode);
        response.setErrorMsg(errorMsg);
        return response;
    }
}

回调处理请求 NotifyRequest.java

@Data
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor
public class NotifyRequest extends BaseRequest implements Serializable {
 
    private static final long serialVersionUID=1L;
 
    /**
     * 支付渠道
     */
    private PayChannel payChannel;
 
    /**
     * 交易方式
     */
    private TradeMethod method;
 
    /**
     * 请求体
     */
    private HttpServletRequest servletRequest;
 
}

回调处理响应 NotifyResponse.java

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class NotifyResponse implements Serializable {
 
    private static final long serialVersionUID = 1L;
 
    /**
     * 是否成功
     */
    private Boolean success;
 
    /**
     * 交易订单号
     */
    private String orderNo;
 
    /**
     * 三方交易订单号
     */
    private String transactionId;
 
    /**
     * 退款单号
     */
    private String refundNo;
 
    /**
     * 退款三方订单号
     */
    private String refundId;
 
    /**
     * 状态
     */
    private PayStatus status;
 
    /**
     * 时间
     */
    private LocalDateTime time;
 
    /**
     * 错误码
     */
    private String errorCode;
 
    /**
     * 错误信息
     */
    private String errorMsg;
 
    public static NotifyResponse failure(String errorCode, String errorMsg) {
        return NotifyResponse.builder().success(false).errorCode(errorCode).errorMsg(errorMsg).build();
    }
 
}

统一支付请求 PayRequest.java

@Data
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor
public class PayRequest extends BaseRequest implements Serializable {
 
    private static final long serialVersionUID = 1L;
 
    /**
     * 支付渠道
     */
    private PayChannel payChannel;
 
    /**
     * 交易类型
     */
    private TradeType tradeType;
 
    /**
     * 订单号
     */
    private String orderNo;
 
    /**
     * 订单金额(单位:分)
     */
    private BigDecimal amount;
 
    /**
     * 订单描述
     */
    private String description;
 
    /**
     * 用户IP
     */
    private String clientIp;
 
    /**
     * 过期时间
     */
    private LocalDateTime expireTime;
 
    /**
     * 附加数据
     */
    private String attach;
 
    /**
     * 通知地址
     */
    private String notifyUrl;
 
    /**
     * 用户标识
     */
    private String openId;
 
    /**
     * 场景类型:Wap、iOS、Android
     */
    private String h5Type;
 
}

统一支付响应 PayResponse.java

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class PayResponse implements Serializable {
 
    private static final long serialVersionUID = 1L;
 
    /**
     * 是否成功
     */
    private Boolean success;
 
    /**
     * 错误码
     */
    private String errorCode;
 
    /**
     * 错误信息
     */
    private String errorMsg;
 
    /**
     * 支付所需参数(前端调起支付所需)
     */
    private Map<String, Object> payParams;
 
    /**
     * 预支付交易会话标识
     */
    private String prepayId;
 
    /**
     * 支付跳转URL
     */
    private String payUrl;
 
    /**
     * 二维码链接
     */
    private String codeUrl;
 
    public static PayResponse failure(String errorCode, String errorMsg) {
        PayResponse response = new PayResponse();
        response.setSuccess(false);
        response.setErrorCode(errorCode);
        response.setErrorMsg(errorMsg);
        return response;
    }
 
}

查询响应 QueryResponse.java

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class QueryResponse implements Serializable {
 
    private static final long serialVersionUID = 1L;
 
    /**
     * 是否成功
     */
    private Boolean success;
 
    /**
     * 订单号
     */
    private String orderNo;
 
    /**
     * 三方交易订单号
     */
    private String transactionId;
 
    /**
     * 状态
     */
    private PayStatus payStatus;
 
    /**
     * 支付时间
     */
    private LocalDateTime payTime;
 
    /**
     * 错误码
     */
    private String errorCode;
 
    /**
     * 错误信息
     */
    private String errorMsg;
 
    public static QueryResponse failure(String errorCode, String errorMsg) {
        QueryResponse response = new QueryResponse();
        response.setSuccess(false);
        response.setErrorCode(errorCode);
        response.setErrorMsg(errorMsg);
        return response;
    }
}

退款请求 RefundRequest.java

@Data
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor
public class RefundRequest extends BaseRequest implements Serializable {
 
    private static final long serialVersionUID = 1L;
 
    /**
     * 交易订单号
     */
    private String orderNo;
 
    /**
     * 退款单号
     */
    private String refundNo;
 
    /**
     * 交易金额
     */
    private BigDecimal payAmount;
 
    /**
     * 退款金额
     */
    private BigDecimal refundAmount;
 
    /**
     * 退款原因
     */
    private String refundReason;
 
    /**
     * 退款回调地址
     */
    private String notifyUrl;
 
}

退款响应 RefundResponse.java

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class RefundResponse implements Serializable {
 
    private static final long serialVersionUID = 1L;
 
    /**
     * 是否成功
     */
    private Boolean success;
 
    /**
     * 交易订单号
     */
    private String orderNo;
 
    /**
     * 退款单号
     */
    private String refundNo;
 
    /**
     * 退款三方订单号
     */
    private String refundId;
 
    /**
     * 状态
     */
    private PayStatus refundStatus;
 
    /**
     * 退款时间
     */
    private LocalDateTime refundTime;
 
    /**
     * 错误码
     */
    private String errorCode;
 
    /**
     * 错误信息
     */
    private String errorMsg;
 
    public static RefundResponse failure(String errorCode, String errorMsg) {
        return RefundResponse.builder().success(false).errorCode(errorCode).errorMsg(errorMsg).build();
    }
 
}

支付策略接口 PayStrategy.java

public interface PayStrategy {
 
    /**
     * 获取支付渠道
     */
    PayChannel getPayChannel();
 
    /**
     * 统一支付
     */
    PayResponse pay(PayRequest request);
 
    /**
     * 查询订单
     */
    QueryResponse queryOrder(PayRequest request);
 
    /**
     * 关闭订单
     */
    CloseResponse close(PayRequest request);
 
    /**
     * 退款
     */
    RefundResponse refund(RefundRequest request);
 
    /**
     * 退款查询
     */
    RefundResponse queryRefund(RefundRequest request);
 
    /**
     * 处理回调
     */
    NotifyResponse handleNotify(NotifyRequest request);
 
}

支付策略实现 AbstractPayStrategy.java

抽象支付策略

@Slf4j
public abstract class AbstractPayStrategy implements PayStrategy {
 
    @Override
    public PayResponse pay(PayRequest request) {
        try {
            log.info("开始支付,渠道:{},订单号:{}", getPayChannel().getName(), request.getOrderNo());
            return doPay(request);
        } catch (Exception e) {
            log.error("支付异常,渠道:{},订单号:{}", getPayChannel().getName(), request.getOrderNo(), e);
            return PayResponse.failure(Constants.OPERATE_ERROR_MSG, "支付处理异常:" + e.getMessage());
        }
    }
 
    @Override
    public QueryResponse queryOrder(PayRequest request) {
        try {
            log.info("查询订单,渠道:{},订单号:{}", getPayChannel().getName(), request.getOrderNo());
            return doQueryOrder(request);
        } catch (Exception e) {
            log.error("查询订单异常,渠道:{},订单号:{}", getPayChannel().getName(), request.getOrderNo(), e);
            return QueryResponse.failure(Constants.OPERATE_ERROR_MSG, "查询订单异常:" + e.getMessage());
        }
    }
 
    @Override
    public CloseResponse close(PayRequest request) {
        try {
            log.info("关闭订单,渠道:{},订单号:{}", getPayChannel().getName(), request.getOrderNo());
            return doClose(request);
        } catch (Exception e) {
            log.error("关闭订单异常,渠道:{},订单号:{}", getPayChannel().getName(), request.getOrderNo(), e);
            return CloseResponse.failure(Constants.OPERATE_ERROR_MSG, "关闭订单异常:" + e.getMessage());
        }
    }
 
    @Override
    public RefundResponse refund(RefundRequest request) {
        try {
            log.info("开始退款,渠道:{},退款单号:{}", getPayChannel().getName(), request.getRefundNo());
            return doRefund(request);
        } catch (Exception e) {
            log.error("退款异常,渠道:{},退款单号:{}", getPayChannel().getName(), request.getRefundNo(), e);
            return RefundResponse.failure(Constants.OPERATE_ERROR_MSG, "退款处理异常:" + e.getMessage());
        }
    }
 
    @Override
    public RefundResponse queryRefund(RefundRequest request) {
        try {
            log.info("开始退款查询,渠道:{},退款单号:{}", getPayChannel().getName(), request.getRefundNo());
            return doQueryRefund(request);
        } catch (Exception e) {
            log.error("退款查询异常,渠道:{},退款单号:{}", getPayChannel().getName(), request.getRefundNo(), e);
            return RefundResponse.failure(Constants.OPERATE_ERROR_MSG, "退款查询处理异常:" + e.getMessage());
        }
    }
 
    protected abstract PayResponse doPay(PayRequest request);
 
    protected abstract QueryResponse doQueryOrder(PayRequest request);
 
    protected abstract CloseResponse doClose(PayRequest request);
 
    protected abstract RefundResponse doRefund(RefundRequest request);
 
    protected abstract RefundResponse doQueryRefund(RefundRequest request);
 
}

各渠道实现

主要以微信支付为列,实现支付、退款、查询、关闭订单、支付退款回调等功能。

微信支付实现 WechatPayStrategy.java

import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.app.AppServiceExtension;
import com.wechat.pay.java.service.payments.app.model.CloseOrderRequest;
import com.wechat.pay.java.service.payments.app.model.QueryOrderByOutTradeNoRequest;
import com.wechat.pay.java.service.payments.h5.H5Service;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.*;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
 
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
 
@Slf4j
@Component
public class WechatPayStrategy extends AbstractPayStrategy {
 
    @Override
    protected PayResponse doPay(PayRequest request) {
        try {
            // 初始化商户配置
            Config config = new RSAAutoCertificateConfig.Builder()
                    .merchantId(request.getMchId())
                    .privateKey(request.getPrivateKey())
                    .merchantSerialNumber(request.getSerialNo())
                    .apiV3Key(request.getApiV3Key())
                    .build();
 
            switch (request.getTradeType()) {
                case TradeType.APP:
                    com.wechat.pay.java.service.payments.app.model.PrepayRequest appRrq = new com.wechat.pay.java.service.payments.app.model.PrepayRequest();
                    appRrq.setAppid(request.getAppId());
                    appRrq.setMchid(request.getMchId());
                    appRrq.setOutTradeNo(request.getOrderNo());
                    appRrq.setDescription(request.getDescription());
                    appRrq.setAttach(request.getAttach());
                    appRrq.setNotifyUrl(request.getNotifyUrl());
                    com.wechat.pay.java.service.payments.app.model.Amount appAmount = new com.wechat.pay.java.service.payments.app.model.Amount();
                    appAmount.setCurrency("CNY");
                    appAmount.setTotal(request.getAmount().multiply(new BigDecimal("100")).setScale(0, RoundingMode.HALF_UP).intValue());
                    appRrq.setAmount(appAmount);
                    if (Objects.nonNull(request.getExpireTime())) {
                        appRrq.setTimeExpire(request.getExpireTime().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
                    }
 
                    log.info("APP支付,请求参数:{}", appRrq);
                    com.wechat.pay.java.service.payments.app.model.PrepayWithRequestPaymentResponse appRes = new AppServiceExtension.Builder().config(config).build().prepayWithRequestPayment(appRrq);
                    log.info("APP支付,返回参数:{}", appRes);
 
                    if (Objects.nonNull(appRes)) {
                        Map<String, Object> appParams = new HashMap<>();
                        appParams.put("appid", appRes.getAppid());
                        appParams.put("partnerid", appRes.getPartnerId());
                        appParams.put("prepayid", appRes.getPrepayId());
                        appParams.put("package", appRes.getPackageVal());
                        appParams.put("noncestr", appRes.getNonceStr());
                        appParams.put("timestamp", appRes.getTimestamp());
                        appParams.put("sign", appRes.getSign());
                        return PayResponse.builder().success(true).payParams(appParams).prepayId(appRes.getPrepayId()).build();
                    }
                    return PayResponse.failure(Constants.OPERATE_ERROR_MSG, Constants.OPERATE_ERROR_MSG);
                case TradeType.JSAPI:
                    com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest jsapiReq = new com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest();
                    jsapiReq.setAppid(request.getAppId());
                    jsapiReq.setMchid(request.getMchId());
                    jsapiReq.setOutTradeNo(request.getOrderNo());
                    jsapiReq.setDescription(request.getDescription());
                    jsapiReq.setAttach(request.getAttach());
                    jsapiReq.setNotifyUrl(request.getNotifyUrl());
                    com.wechat.pay.java.service.payments.jsapi.model.Amount jsapiAmount = new com.wechat.pay.java.service.payments.jsapi.model.Amount();
                    jsapiAmount.setCurrency("CNY");
                    jsapiAmount.setTotal(request.getAmount().multiply(new BigDecimal("100")).setScale(0, RoundingMode.HALF_UP).intValue());
                    jsapiReq.setAmount(jsapiAmount);
                    com.wechat.pay.java.service.payments.jsapi.model.Payer jsapiPayer = new com.wechat.pay.java.service.payments.jsapi.model.Payer();
                    jsapiPayer.setOpenid(request.getOpenId());
                    jsapiReq.setPayer(jsapiPayer);
                    if (Objects.nonNull(request.getExpireTime())) {
                        jsapiReq.setTimeExpire(request.getExpireTime().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
                    }
 
                    log.info("JSAPI支付,请求参数:{}", jsapiReq);
                    com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse jsapiRes = new JsapiServiceExtension.Builder().config(config).build().prepayWithRequestPayment(jsapiReq);
                    log.info("JSAPI支付,返回参数:{}", jsapiRes);
 
                    if (Objects.nonNull(jsapiRes)) {
                        Map<String, Object> jsapiParams = new HashMap<>();
                        jsapiParams.put("appId", jsapiRes.getAppId());
                        jsapiParams.put("paySign", jsapiRes.getPaySign());
                        jsapiParams.put("signType", jsapiRes.getSignType());
                        jsapiParams.put("package", jsapiRes.getPackageVal());
                        jsapiParams.put("nonceStr", jsapiRes.getNonceStr());
                        jsapiParams.put("timeStamp", jsapiRes.getTimeStamp());
                        return PayResponse.builder().success(true).payParams(jsapiParams).build();
                    }
                    return PayResponse.failure(Constants.OPERATE_ERROR_MSG, Constants.OPERATE_ERROR_MSG);
                case TradeType.NATIVE:
                    com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest nativeReq = new com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest();
                    nativeReq.setAppid(request.getAppId());
                    nativeReq.setMchid(request.getMchId());
                    nativeReq.setOutTradeNo(request.getOrderNo());
                    nativeReq.setDescription(request.getDescription());
                    nativeReq.setAttach(request.getAttach());
                    nativeReq.setNotifyUrl(request.getNotifyUrl());
                    com.wechat.pay.java.service.payments.nativepay.model.Amount nativeAmount = new com.wechat.pay.java.service.payments.nativepay.model.Amount();
                    nativeAmount.setCurrency("CNY");
                    nativeAmount.setTotal(request.getAmount().multiply(new BigDecimal("100")).setScale(0, RoundingMode.HALF_UP).intValue());
                    nativeReq.setAmount(nativeAmount);
                    if (Objects.nonNull(request.getExpireTime())) {
                        nativeReq.setTimeExpire(request.getExpireTime().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
                    }
 
                    log.info("NATIVE支付,请求参数:{}", nativeReq);
                    com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse nativeRes = new NativePayService.Builder().config(config).build().prepay(nativeReq);
                    log.info("NATIVE支付,返回参数:{}", nativeRes);
 
                    if (Objects.nonNull(nativeRes)) {
                        return PayResponse.builder().success(true).codeUrl(nativeRes.getCodeUrl()).build();
                    }
                case TradeType.H5:
                    com.wechat.pay.java.service.payments.h5.model.PrepayRequest h5Req = new com.wechat.pay.java.service.payments.h5.model.PrepayRequest();
                    h5Req.setAppid(request.getAppId());
                    h5Req.setMchid(request.getMchId());
                    h5Req.setOutTradeNo(request.getOrderNo());
                    h5Req.setDescription(request.getDescription());
                    h5Req.setAttach(request.getAttach());
                    h5Req.setNotifyUrl(request.getNotifyUrl());
 
                    com.wechat.pay.java.service.payments.h5.model.Amount h5Amount = new com.wechat.pay.java.service.payments.h5.model.Amount();
                    h5Amount.setCurrency("CNY");
                    h5Amount.setTotal(request.getAmount().multiply(new BigDecimal("100")).setScale(0, RoundingMode.HALF_UP).intValue());
                    h5Req.setAmount(h5Amount);
 
                    com.wechat.pay.java.service.payments.h5.model.SceneInfo h5Scene = new com.wechat.pay.java.service.payments.h5.model.SceneInfo();
                    h5Scene.setPayerClientIp(request.getClientIp());
                    com.wechat.pay.java.service.payments.h5.model.H5Info h5Info = new com.wechat.pay.java.service.payments.h5.model.H5Info();
                    h5Info.setType(request.getH5Type());
                    h5Scene.setH5Info(h5Info);
                    h5Req.setSceneInfo(h5Scene);
                    if (Objects.nonNull(request.getExpireTime())) {
                        h5Req.setTimeExpire(request.getExpireTime().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
                    }
 
                    log.info("H5支付,请求参数:{}", h5Req);
                    com.wechat.pay.java.service.payments.h5.model.PrepayResponse h5Re s= new H5Service.Builder().config(config).build().prepay(h5Req);
                    log.info("H5支付,返回参数:{}", h5Res);
 
                    if (Objects.nonNull(h5Res)) {
                        return PayResponse.builder().success(true).codeUrl(h5Res.getH5Url()).build();
                    }
                default:
                    return PayResponse.failure(Constants.OPERATE_ERROR_MSG, "不支持的微信交易类型");
            }
        } catch (Exception e) {
            log.error("微信支付失败: {}", e);
            return PayResponse.failure(Constants.OPERATE_ERROR_MSG, e.getMessage());
        }
    }
 
    @Override
    protected QueryResponse doQueryOrder(PayRequest request) {
        try {
            QueryOrderByOutTradeNoRequest req = new QueryOrderByOutTradeNoRequest();
            req.setMchid(request.getMchId());
            req.setOutTradeNo(request.getOrderNo());
 
            log.info("订单开始,请求参数:{}", req);
            Transaction res = new AppServiceExtension.Builder().config(
                    new RSAAutoCertificateConfig.Builder()
                            .merchantId(request.getMchId())
                            .privateKey(request.getPrivateKey())
                            .merchantSerialNumber(request.getSerialNo())
                            .apiV3Key(request.getApiV3Key())
                            .build()
            ).build().queryOrderByOutTradeNo(req);
            log.info("订单结束,返回参数:{}", res);
 
            if (Objects.nonNull(res)) {
                PayStatus payStatus = PayStatus.WAITING;
                LocalDateTime payTime = null;
                if (Transaction.TradeStateEnum.SUCCESS == res.getTradeState()) {
                    // 成功
                    payTime = LocalDateTime.parse(res.getSuccessTime());
                    payStatus = PayStatus.SUCCESS;
                } else if (Transaction.TradeStateEnum.NOTPAY == res.getTradeState() || Transaction.TradeStateEnum.USERPAYING == res.getTradeState()) {
                    // 未支付、支付中
                    payStatus = PayStatus.WAITING;
                } else if (Transaction.TradeStateEnum.CLOSED == res.getTradeState() || Transaction.TradeStateEnum.REVOKED == res.getTradeState()) {
                    // 已关闭、已撤销
                    payStatus = PayStatus.CANCELED;
                } else if (Transaction.TradeStateEnum.PAYERROR == res.getTradeState()) {
                    // 失败
                    payStatus = PayStatus.FAILED;
                }
 
                return QueryResponse.builder()
                        .success(true)
                        .orderNo(res.getOutTradeNo())
                        .transactionId(res.getTransactionId())
                        .payStatus(payStatus)
                        .payTime(payTime)
                        .build();
            }
            return QueryResponse.failure(Constants.OPERATE_ERROR_MSG, "订单查询失败");
        } catch (Exception e) {
            log.error("微信支付查询失败: {}", e);
            return QueryResponse.failure(Constants.OPERATE_ERROR_MSG, e.getMessage());
        }
    }
 
    @Override
    protected CloseResponse doClose(PayRequest request) {
        try {
            CloseOrderRequest req = new CloseOrderRequest();
            req.setMchid(request.getMchId());
            req.setOutTradeNo(request.getOrderNo());
 
            log.info("关闭订单开始,请求参数:{}", req);
            new AppServiceExtension.Builder().config(
                    new RSAAutoCertificateConfig.Builder()
                            .merchantId(request.getMchId())
                            .privateKey(request.getPrivateKey())
                            .merchantSerialNumber(request.getSerialNo())
                            .apiV3Key(request.getApiV3Key())
                            .build()
            ).build().closeOrder(req);
            log.info("关闭订单结束");
 
            return CloseResponse.success(request.getOrderNo());
        } catch (Exception e) {
            log.error("微信关闭订单失败: {}", e);
            return CloseResponse.failure(Constants.OPERATE_ERROR_MSG, e.getMessage());
        }
    }
 
    @Override
    protected RefundResponse doRefund(RefundRequest request) {
        try {
            CreateRequest req = new CreateRequest();
            req.setOutTradeNo(request.getOrderNo());
            AmountReq amountReq = new AmountReq();
            amountReq.setTotal(request.getPayAmount().multiply(new BigDecimal("100")).setScale(0, RoundingMode.HALF_UP).longValue());
            amountReq.setRefund(request.getRefundAmount().multiply(new BigDecimal("100")).setScale(0, RoundingMode.HALF_UP).longValue());
            amountReq.setCurrency("CNY");
            req.setAmount(amountReq);
            req.setOutRefundNo(request.getRefundNo());
            req.setReason(request.getRefundReason());
            req.setNotifyUrl(request.getNotifyUrl());
 
            log.info("退款开始,请求参数:{}", req);
            Refund res = new RefundService.Builder().config(
                    new RSAAutoCertificateConfig.Builder()
                            .merchantId(request.getMchId())
                            .privateKey(request.getPrivateKey())
                            .merchantSerialNumber(request.getSerialNo())
                            .apiV3Key(request.getApiV3Key())
                            .build()
            ).build().create(req);
            log.info("退款结束,返回参数:{}", res);
 
            if (Objects.nonNull(res)) {
                return RefundResponse.builder().success(true).refundNo(res.getOutRefundNo()).build();
            }
            return RefundResponse.failure(Constants.OPERATE_ERROR_MSG, "退款失败");
        } catch (Exception e) {
            log.error("微信退款失败: {}", e);
            return RefundResponse.failure(Constants.OPERATE_ERROR_MSG, e.getMessage());
        }
    }
 
    @Override
    protected RefundResponse doQueryRefund(RefundRequest request) {
        try {
            QueryByOutRefundNoRequest req = new QueryByOutRefundNoRequest();
            req.setOutRefundNo(request.getRefundNo());
 
            log.info("退款查询开始,请求参数:{}", req);
            Refund res = new RefundService.Builder().config(
                    new RSAAutoCertificateConfig.Builder()
                            .merchantId(request.getMchId())
                            .privateKey(request.getPrivateKey())
                            .merchantSerialNumber(request.getSerialNo())
                            .apiV3Key(request.getApiV3Key())
                            .build()
            ).build().queryByOutRefundNo(req);
            log.info("退款查询结束,返回参数:{}", res);
 
            if (Objects.nonNull(res)) {
                PayStatus payStatus = PayStatus.WAITING;
                BigDecimal amount = null;
                LocalDateTime refundTime = null;
                if (Status.SUCCESS == res.getStatus()) {
                    // 成功
                    refundTime = LocalDateTime.parse(res.getSuccessTime());
                    payStatus = PayStatus.SUCCESS;
                } else if (Status.PROCESSING == res.getStatus()) {
                    // 处理中
                    payStatus = PayStatus.WAITING;
                } else if (Status.CLOSED == res.getStatus()) {
                    // 已关闭
                    payStatus = PayStatus.CANCELED;
                } else if (Status.ABNORMAL == res.getStatus()) {
                    // 失败
                    payStatus = PayStatus.FAILED;
                }
 
                return RefundResponse.builder()
                        .success(true)
                        .orderNo(res.getOutTradeNo())
                        .refundNo(res.getOutRefundNo())
                        .refundId(res.getRefundId())
                        .refundStatus(payStatus)
                        .refundTime(refundTime)
                        .build();
            }
            return RefundResponse.failure(Constants.OPERATE_ERROR_MSG, "退款查询失败");
        } catch (Exception e) {
            log.error("微信退款查询失败: {}", e);
            return RefundResponse.failure(Constants.OPERATE_ERROR_MSG, e.getMessage());
        }
    }
 
    @Override
    public NotifyResponse handleNotify(NotifyRequest request) {
        try {
            log.info("微信回调处理开始...");
            HttpServletRequest servletRequest = request.getServletRequest();
            // 读取请求体的信息
            ServletInputStream inputStream = servletRequest.getInputStream();
            StringBuffer stringBuffer = new StringBuffer();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            String s;
            while ((s = bufferedReader.readLine()) != null) {
                stringBuffer.append(s);
            }
            log.info("微信回调处理,请求体参数:{}", stringBuffer);
 
            // 初始化 NotificationParser
            NotificationParser parser = new NotificationParser(
                    new RSAAutoCertificateConfig.Builder()
                            .merchantId(request.getMchId())
                            .privateKey(request.getPrivateKey())
                            .merchantSerialNumber(request.getSerialNo())
                            .apiV3Key(request.getApiV3Key())
                            .build()
            );
            RequestParam requestParam = new RequestParam.Builder()
                    .serialNumber(servletRequest.getHeader("Wechatpay-Serial"))
                    .nonce(servletRequest.getHeader("Wechatpay-Nonce"))
                    .signature(servletRequest.getHeader("Wechatpay-Signature"))
                    .timestamp(servletRequest.getHeader("Wechatpay-Timestamp"))
                    .signType(servletRequest.getHeader("Wechatpay-Signature-Type"))
                    .body(stringBuffer.toString())
                    .build();
 
            log.info("微信回调处理,RequestParam:{}", requestParam);
 
            switch (request.getMethod()) {
                case TradeMethod.PAY:
                    Transaction transaction = parser.parse(requestParam, Transaction.class);
                    log.info("微信支付回调返回参数:{}", transaction);
                    NotifyResponse payResponse = NotifyResponse.builder().success(true).orderNo(transaction.getOutTradeNo()).build();
                    if (Transaction.TradeStateEnum.SUCCESS == transaction.getTradeState()) {
                        // SUCCESS:支付成功
                        payResponse.setTransactionId(transaction.getTransactionId());
                        payResponse.setTime(LocalDateTime.parse(transaction.getSuccessTime()));
                        payResponse.setStatus(PayStatus.SUCCESS);
                    } else if (Transaction.TradeStateEnum.CLOSED == transaction.getTradeState() || Transaction.TradeStateEnum.REVOKED == transaction.getTradeState() || Transaction.TradeStateEnum.PAYERROR == transaction.getTradeState()) {
                        // CLOSED:已关闭、REVOKED:已撤销、PAYERROR:支付失败
                        payResponse.setStatus(PayStatus.FAILED);
                    } else {
                        // REFUND:转入退款、NOTPAY:未支付、USERPAYING:用户支付中
                        log.info("支付中的暂不处理:{}", transaction);
                    }
 
                    log.info("微信支付回调结束:{}", payResponse);
                    return payResponse;
                case TradeMethod.REFUND:
                    RefundNotification refund = parser.parse(requestParam, RefundNotification.class);
                    log.info("微信退款回调返回参数:{}", refund);
                    NotifyResponse refundResponse = NotifyResponse.builder().success(true).refundNo(refund.getOutRefundNo()).build();
                    if (Status.SUCCESS == refund.getRefundStatus()) {
                        // SUCCESS:退款成功
                        refundResponse.setRefundId(refund.getRefundId());
                        refundResponse.setOrderNo(refund.getOutTradeNo());
                        refundResponse.setTransactionId(refund.getTransactionId());
                        refundResponse.setTime(LocalDateTime.parse(refund.getSuccessTime()));
                        refundResponse.setStatus(PayStatus.SUCCESS);
                    } else {
                        // ABNORMAL:退款异常、CLOSED:退款关闭
                        refundResponse.setRefundId(refund.getRefundId());
                        refundResponse.setOrderNo(refund.getOutTradeNo());
                        refundResponse.setTransactionId(refund.getTransactionId());
                        refundResponse.setTime(LocalDateTime.parse(refund.getCreateTime()));
                        refundResponse.setStatus(PayStatus.FAILED);
                    }
 
                    log.info("微信退款回调结束:{}", refundResponse);
                    return refundResponse;
                default:
                    return NotifyResponse.failure(Constants.OPERATE_ERROR_MSG, "不支持的回调方式");
            }
        } catch (Exception e) {
            log.error("微信回调处理失败: {}", e);
            return NotifyResponse.failure(Constants.OPERATE_ERROR_MSG, e.getMessage());
        }
    }
 
    @Override
    public PayChannel getPayChannel() {
        return PayChannel.WECHAT_PAY;
    }
 
}

支付宝支付实现 AlipayStrategy.java

@Slf4j
@Component
public class AlipayStrategy extends AbstractPayStrategy {
 
    @Override
    protected PayResponse doPay(PayRequest request) {
        try {
            // TODO 业务实现
            return null;
        } catch (Exception e) {
            throw new RuntimeException("支付宝支付失败", e);
        }
    }
 
    @Override
    protected QueryResponse doQueryOrder(PayRequest request) {
        return null;
    }
 
    @Override
    protected CloseResponse doClose(PayRequest request) {
        return null;
    }
 
    @Override
    protected RefundResponse doRefund(RefundRequest request) {
        return null;
    }
 
    @Override
    protected RefundResponse doQueryRefund(RefundRequest request) {
        return null;
    }
 
    @Override
    public PayChannel getPayChannel() {
        return PayChannel.ALI_PAY;
    }
 
    @Override
    public NotifyResponse handleNotify(NotifyRequest request) {
        return null;
    }
 
}

银联支付实现 UnionPayStrategy.java

@Slf4j
@Component
public class UnionPayStrategy extends AbstractPayStrategy {
 
    @Override
    protected PayResponse doPay(PayRequest request) {
        try {
            // TODO 业务实现
            return null;
        } catch (Exception e) {
            throw new RuntimeException("银联支付失败", e);
        }
    }
 
    @Override
    protected QueryResponse doQueryOrder(PayRequest request) {
        return null;
    }
 
    @Override
    protected CloseResponse doClose(PayRequest request) {
        return null;
    }
 
    @Override
    protected RefundResponse doRefund(RefundRequest request) {
        return null;
    }
 
    @Override
    protected RefundResponse doQueryRefund(RefundRequest request) {
        return null;
    }
 
    @Override
    public PayChannel getPayChannel() {
        return PayChannel.UNION_PAY;
    }
 
    @Override
    public NotifyResponse handleNotify(NotifyRequest request) {
        return null;
    }
 
}

支付策略工厂 PayStrategyFactory.java

@Component
public class PayStrategyFactory {
 
    private final Map<PayChannel, PayStrategy> strategyMap = new ConcurrentHashMap<>();
 
    public PayStrategyFactory(List<PayStrategy> strategies) {
        for (PayStrategy strategy : strategies) {
            strategyMap.put(strategy.getPayChannel(), strategy);
        }
    }
 
    public PayStrategy getStrategy(PayChannel payChannel) {
        PayStrategy strategy = strategyMap.get(payChannel);
        if (strategy == null) {
            throw new RuntimeException("不支持的支付渠道:" + payChannel.getName());
        }
        return strategy;
    }
 
    public PayStrategy getStrategy(String channelCode) {
        PayChannel payChannel = PayChannel.getByCode(channelCode);
        if (payChannel == null) {
            throw new RuntimeException("不支持的支付渠道代码:" + channelCode);
        }
        return getStrategy(payChannel);
    }
 
}

统一支付服务 PayService.java

@Slf4j
@Service
public class PayService {
 
    @Autowired
    private PayStrategyFactory payStrategyFactory;
 
    /**
     * @Description: 支付
     * @Date: 2025/11/21
     * @Param: [request]
     **/
    public PayResponse pay(PayRequest request) {
        PayStrategy strategy = payStrategyFactory.getStrategy(request.getPayChannel());
        return strategy.pay(request);
    }
 
    /**
     * @Description: 查询订单
     * @Date: 2025/11/21
     * @Param: [request]
     **/
    public QueryResponse queryOrder(PayRequest request) {
        PayStrategy strategy = payStrategyFactory.getStrategy(request.getPayChannel());
        return strategy.queryOrder(request);
    }
 
    /**
     * @Description: 关闭订单
     * @Date: 2025/11/21
     * @Param: [request]
     **/
    public CloseResponse close(PayRequest request) {
        PayStrategy strategy = payStrategyFactory.getStrategy(request.getPayChannel());
        return strategy.close(request);
    }
 
    /**
     * @Description: 退款
     * @Date: 2025/11/21
     * @Param: [payChannel, request]
     **/
    public RefundResponse refund(PayChannel payChannel, RefundRequest request) {
        PayStrategy strategy = payStrategyFactory.getStrategy(payChannel);
        return strategy.refund(request);
    }
 
    /**
     * @Description: 退款查询
     * @Date: 2025/11/21
     * @Param: [payChannel, request]
     **/
    public RefundResponse queryRefund(PayChannel payChannel, RefundRequest request) {
        PayStrategy strategy = payStrategyFactory.getStrategy(payChannel);
        return strategy.queryRefund(request);
    }
 
    /**
     * @Description: 处理回调
     * @Date: 2025/11/21
     * @Param: [request]
     **/
    public NotifyResponse handleNotify(NotifyRequest request) {
        PayStrategy strategy = payStrategyFactory.getStrategy(request.getPayChannel());
        return strategy.handleNotify(request);
    }
 
}

使用示例

@Service
public class OrderService {
 
    @Autowired
    private PayService payService;
 
    public void createOrderAndPay() {
        // 创建支付请求
        PayRequest request = new PayRequest();
 
        // 公共参数
        request.setAppId("wxd678efxxxxxxxxxxxxxxxxx");
        request.setMchId("123xxxxxxxx");
        request.setSerialNo("1DDE55AD98Exxxxxxxxxx");
        request.setPrivateKey("XXXXXXXXXXXXXXXXXXXXXXXXX");
        request.setPublicKey("XXXXXXXXXXXXXXXXXXXXXXXXXX");
        request.setApiV3Key("XXXXXXXXXXXXXXXXXXXXXX");
 
        // 订单参数
        request.setPayChannel(PayChannel.WECHAT_PAY);
        request.setTradeType(TradeType.APP);
        request.setOrderNo("ORDER_" + System.currentTimeMillis());
        request.setAmount(100); // 1元
        request.setDescription("测试商品");
        request.setClientIp("127.0.0.1");
 
        // 发起支付
        PayResponse response = payService.pay(request);
 
        if (response.isSuccess()) {
            // 支付创建成功,返回支付参数给前端
            System.out.println("支付参数:" + response.getPayParams());
        } else {
            // 处理支付失败
            System.out.println("支付失败:" + response.getErrorMsg());
        }
    }
}

到此这篇关于SpringBoot 支付渠道实现统一的支付服务的文章就介绍到这了,更多相关SpringBoot 支付渠道统一支付内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • JAVA和JAVAC 命令详细介绍

    JAVA和JAVAC 命令详细介绍

    这篇文章主要介绍了JAVA和JAVAC 命令详细介绍的相关资料,本文对java 和javac 命令进行了详解,并在Windows和Linux 平台分别说明,需要的朋友可以参考下
    2016-11-11
  • Java基础题新手练习(二)

    Java基础题新手练习(二)

    下面小编就为大家带来一篇Java基础的几道练习题(分享)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧,希望可以帮到你
    2021-07-07
  • MybatisPlus开启二级缓存的方法详解

    MybatisPlus开启二级缓存的方法详解

    这篇文章主要介绍了MybatisPlus开启二级缓存的方法详解,二级缓存是基于mapper文件的namespace级别,也就是说多个sqlSession可以共享一个mapper中的二级缓存区域,需要的朋友可以参考下
    2023-11-11
  • Android开发Activity管理工具类的操作方法

    Android开发Activity管理工具类的操作方法

    这篇文章主要介绍了Android开发Activity管理工具类,下面是一个完整的Activity管理工具类实现,可以帮助你管理应用中的所有Activity,方便一键退出应用、获取当前Activity等操作,需要的朋友可以参考下
    2021-02-02
  • Spring Boot 中密码加密的两种方法

    Spring Boot 中密码加密的两种方法

    这篇文章主要介绍了Spring Boot 中密码加密的两种方法,帮助大家更好的理解和使用Spring Boot框架,感兴趣的朋友可以了解下
    2020-09-09
  • Java Swing组件复选框JCheckBox用法示例

    Java Swing组件复选框JCheckBox用法示例

    这篇文章主要介绍了Java Swing组件复选框JCheckBox用法,结合具体实例形式分析了Swing复选框JCheckBox简单用法与相关操作注意事项,需要的朋友可以参考下
    2017-11-11
  • 一个合格JAVA软件工程师应该具备什么

    一个合格JAVA软件工程师应该具备什么

    一个合格JAVA软件工程师应该具备哪些专业技能,面试技巧是什么?本文为大家分享了2016版最新Java软件工程师就业思维图,感兴趣的小伙伴们可以参考一下
    2016-11-11
  • java关于字符串的常用API

    java关于字符串的常用API

    字符串其实就是一串连续的字符,它是由许多单个字符连接而成的。如多个英文字母所组成的一个英文单词。字符串中可以包含任意字符,这些字符必须包含在一对双引号之内,今天就来介绍字符串常用的API
    2023-05-05
  • Spring框架初始化解析

    Spring框架初始化解析

    这篇文章主要介绍了Spring框架初始化解析,具有一定参考价值,需要的朋友可以了解下。
    2017-11-11
  • 异常try catch的常见四类方式(案例代码)

    异常try catch的常见四类方式(案例代码)

    这篇文章主要介绍了异常try catch的常见四类方式,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-05-05

最新评论