SpringBoot+微信支付-JSAPI

引入微信支付SDK

Maven: com.github.wechatpay-apiv3:wechatpay-java-core:0.2.12
Maven: com.github.wechatpay-apiv3:wechatpay-java:0.2.12

代码示例

package xxxx.cashier.payChannel.handler;

import xxxx.common.domain.model.exception.BusinessException;
import xxxx.cashier.common.LocalTimeUtils;
import xxxx.cashier.common.RuleCommonUilt;
import xxxx.cashier.domain.dto.QueryRefundDto;
import xxxx.cashier.domain.model.CashierPayment;
import xxxx.cashier.domain.model.RefundStatusEnum;
import xxxx.cashier.payChannel.application.WxConfigService;
import xxxx.cashier.payChannel.callback.vo.WxPayRespDto;
import xxxx.cashier.payChannel.domain.model.PayChannel;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.cipher.Signer;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.util.NonceUtil;
import com.wechat.pay.java.service.payments.jsapi.JsapiService;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.Amount;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.net.URISyntaxException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Service
public class JsapiPrepayHandler {

    @Autowired
    private WxConfigService wxConfigService;

    /**
     * 微信支付JSAPI下单----改造多核
     * 多商户
     * @param cashierPayment 订单
     * @return WxPayRespDto
     */
    public WxPayRespDto handlePrepay(CashierPayment cashierPayment) {
        try {
            // 微信支付渠道配置
            Config wxConfig = wxConfigService.getWxConfig(cashierPayment.getMerchantTableId(),cashierPayment.getPayChannelType());
            PayChannel payChannel = wxConfigService.getPayChannel(cashierPayment.getMerchantTableId(),cashierPayment.getPayChannelType());
            String wxCallBackUrl = wxConfigService.getWxCallBackUrl(false,cashierPayment.getMerchantId());
            // 设置回渠道Id
            cashierPayment.setPayChannelId(payChannel.getMid());
            // 渠道手续费
//            cashierPayment.setChannelServiceFee(payChannel.getFee());
            // 下单请求参数
            PrepayRequest request = new PrepayRequest();
            // 微信appId
            request.setAppid(cashierPayment.getAppId());
            // 微信商户id||是微信支付收款的商户ID--来自渠道{不是业务商户}
            request.setMchid(wxConfig.createCredential().getMerchantId());
            // 商品描述
            request.setDescription(cashierPayment.getDescription());
            // 设置订单超时时间
            Date expireTime = cashierPayment.getExpireTime();
            if (expireTime == null) {
                request.setTimeExpire(LocalDateTime.now().plusMinutes(RuleCommonUilt.WX_EXPIRE_TIME).toString() + "+08:00");
            } else {
                try {
                    String expireTimeStr = LocalTimeUtils.simpleDateFormat.format(expireTime);
                    request.setTimeExpire(expireTimeStr + "+08:00");
                } catch (Exception e) {
                    log.error("xxxx.cashier.payChannel.handler.JsapiPrepayHandler.handlePrepay=:时间格式错误,走默认的过期时间策略");
                    request.setTimeExpire(LocalDateTime.now().plusMinutes(RuleCommonUilt.WX_EXPIRE_TIME).toString() + "+08:00");
                }
            }
            // 回调地址,仅支持https||微信侧回调收银台的地址
            request.setNotifyUrl(wxCallBackUrl);
            // 支付订单号||收银台侧的流水号||不是业务系统的流水号
            request.setOutTradeNo(cashierPayment.getPaymentNo());
            // 订单金额
            Amount amount = new Amount();
            amount.setTotal(cashierPayment.getAmount().intValue());
            amount.setCurrency(cashierPayment.getCurrencyType());
            request.setAmount(amount);
            // 支付环境
            request.setAttach("收银台:" + cashierPayment.getPaymentNo() + ";业务侧:" + cashierPayment.getOrderNo());
            // 付款人
            Payer payer = new Payer();
            // 用户id
            payer.setOpenid(cashierPayment.getOpenId());
            request.setPayer(payer);
            // 支付环境
            if (StringUtils.isNotBlank(cashierPayment.getClientIp())) {
                SceneInfo sceneInfo = new SceneInfo();
                sceneInfo.setPayerClientIp(cashierPayment.getClientIp());
                request.setSceneInfo(sceneInfo);
            }
            // 使用jsapi方式请求
            JsapiServiceExtension service =
                    new JsapiServiceExtension.Builder()
                            .config(wxConfig)
                            .signType("RSA") // 不填默认为RSA
                            .build();
            // 发起下单
            PrepayWithRequestPaymentResponse prepayResp = service.prepayWithRequestPayment(request);
            if (prepayResp == null || StringUtils.isEmpty(prepayResp.getPackageVal())) {
                log.error("xxxx.cashier.payChannel.handler.JsapiPrepayHandler.handlePrepay:发起付款失败, 返回的预付款订单号为空");
                throw new BusinessException("发起付款失败, 返回的预付款订单号为空");
            }
            // 下单成功---组装数据
            return this.buildWxPayRespVo(cashierPayment, prepayResp);
        } catch (Exception e) {
            log.error("xxxx.cashier.payChannel.handler.JsapiPrepayHandler.handlePrepay:生成签名失败:{}", e.getMessage(), e);
            throw new BusinessException("生成签名失败" + e.getMessage());
        }
    }

    /**
     * 微信发送--小程序下单返回字段填充
     *
     * @param cashierPayment cashierPayment
     * @param prepayResp     prepayResp
     * @return WxPayRespDto
     * @throws Exception Exception
     * @author GuoTong
     */
    public WxPayRespDto buildWxPayRespVo(CashierPayment cashierPayment, PrepayWithRequestPaymentResponse prepayResp) throws Exception {
        return new WxPayRespDto()
                .setPrepayId(prepayResp.getPackageVal())
                .setPaymentNo(cashierPayment.getPaymentNo())
                .setNonceStr(prepayResp.getNonceStr())
                .setTimeStamp(prepayResp.getTimeStamp())
                .setPaySign(prepayResp.getPaySign())
                .setSignType("RSA");
    }

    /**
     * 手动封装---吴爽
     *
     * @param cashierPayment cashierPayment
     * @param prepayId       prepayId
     * @param wxConfig       wxConfig
     * @return
     * @throws InvalidKeyException
     * @throws NoSuchAlgorithmException
     * @throws SignatureException
     * @throws URISyntaxException
     */
    public WxPayRespDto getWxPayRespVo(CashierPayment cashierPayment, String prepayId, Config wxConfig) throws Exception {

        Long timeStamp = System.currentTimeMillis() / 1000;
        String nonceStr = NonceUtil.createNonce(32);
        // 生成签名
        String signatureStr = Stream.of(cashierPayment.getAppId(),
                        String.valueOf(timeStamp),
                        nonceStr,
                        prepayId)
                .collect(Collectors.joining("\n", "", "\n"));
        Signer signer = wxConfig.createSigner();
        String sign = signer.sign(signatureStr).getSign();

        return new WxPayRespDto()
                .setPrepayId(prepayId)
                .setPaymentNo(cashierPayment.getPaymentNo())
                .setNonceStr(nonceStr)
                .setTimeStamp(timeStamp.toString())
                .setPaySign(sign)
                .setSignType(signer.getAlgorithm());
    }

    /**
     * 商户可以通过查询订单接口主动查询订单状态,完成下一步的业务逻辑。
     * <p>
     * 查询订单可通过微信支付订单号 (opens new window)和商户订单号 (opens new window)两种方式查询。
     * <p>
     * 需要调用查询接口的情况:
     * <p>
     * 当商户后台、网络、服务器等出现异常,商户系统最终未接收到支付通知。
     * 调用支付接口后,返回系统错误或未知交易状态情况。
     * 调用付款码支付API,返回USERPAYING的状态。
     * 调用关单或撤销接口API之前,需确认支付状态。
     *
     * @param cashierPayment CashierPayment
     * @param payChannelTarget payChannelTarget
     * @return WxPayRespDto
     */
    public Transaction queryOrderInfo(CashierPayment cashierPayment, PayChannel payChannelTarget) {
        Long payChannelId = cashierPayment.getPayChannelId();
        Config wxConfig = wxConfigService.getWxConfig(payChannelId,payChannelTarget);
        QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
        request.setMchid(wxConfig.createCredential().getMerchantId());
        request.setOutTradeNo(cashierPayment.getPaymentNo());
        JsapiServiceExtension service =
                new JsapiServiceExtension.Builder()
                        .config(wxConfig)
                        .signType("RSA") // 不填默认为RSA
                        .build();
        Transaction transaction = null;
        try {
            transaction = service.queryOrderByOutTradeNo(request);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return transaction;
    }

    /**
     * 关闭订单,以下情况需要调用关单接口:
     * <p>
     * 商户订单支付失败需要生成新单号重新发起支付,要对原订单号调用关单,避免重复支付;
     * 系统下单后,用户支付超时,系统退出不再受理,避免用户继续,请调用关单接口。
     *
     * @param cashierPayment cashierPayment
     */
    public void closePayment(CashierPayment cashierPayment) {
        CloseOrderRequest request = new CloseOrderRequest();
        Config wxConfig = wxConfigService.getWxConfig(cashierPayment.getPayChannelId(),new PayChannel());
        // 使用微信侧的商户
        request.setMchid(wxConfig.createCredential().getMerchantId());
        // 商户系统内部订单号
        request.setOutTradeNo(cashierPayment.getPaymentNo());
        JsapiService service = new JsapiService.Builder().config(wxConfig).build();
        service.closeOrder(request);
    }

    /**
     * 当交易发生之后一段时间内,由于买家或者卖家的原因需要退款时,卖家可以通过退款接口将支付款退还给买家,
     * <p>
     * 微信支付将在收到退款请求并且验证成功之后,按照退款规则将支付款按原路退到买家帐号上。
     *
     * @param cashierPayment cashierPayment
     * @return Refund
     */
    @SuppressWarnings("unchecked,deprecation,unused")
    public Refund refundOrderV3(CashierPayment cashierPayment, CashierPayment originalOrder) {
        Config wxConfig = wxConfigService.getWxConfig(cashierPayment.getPayChannelId(),new PayChannel());
        String wxCallBackUrl = wxConfigService.getWxCallBackUrl(true,originalOrder.getMerchantId());
        RefundService service = new RefundService.Builder().config(wxConfig).build();
        CreateRequest request = new CreateRequest();
        // 退款收银台订单号
        request.setOutRefundNo(cashierPayment.getPaymentNo());
        // 微信支付订单号(原支付渠道流水号)
        request.setTransactionId(cashierPayment.getChannelFlowNo());
        // 使用可用余额退款 ===== request.setFundsAccount(ReqFundsAccount.AVAILABLE);
        request.setNotifyUrl(wxCallBackUrl);
        // 退款金额
        AmountReq amountReq = new AmountReq();
        // 原始订单金额
        amountReq.setTotal(originalOrder.getAmount());
        // 退款订单金额
        amountReq.setRefund(cashierPayment.getRefundAmount());
        amountReq.setCurrency(StringUtils.isEmpty(cashierPayment.getCurrencyType()) ? "CNY" : cashierPayment.getCurrencyType());
        request.setAmount(amountReq);
        // 发起退款
        Refund refund = null;
        try {
            refund = service.create(request);
        } catch (ServiceException e) {
            // 捕捉-微信退款下单时返回的状态码是发送HTTP请求成功,服务返回异常。例如返回状态码小于200或大于等于300。
            String errorCode = e.getErrorCode();
            // 判断由定时任务调度过来的|跳过本地环境---直接操作微信环境---引起本地和微信订单不同步操作
            String message = e.getErrorMessage();
            if (errorCode.equals("INVALID_REQUEST") && message.equals("订单已全额退款")){
                log.info("订单已全额退款"+cashierPayment.getPaymentNo());
                throw new BusinessException(Status.SUCCESS.name());
            }
            log.error("发起退款失败,错误码:{}", errorCode, e);
            throw new BusinessException(errorCode);
        }
        log.debug("退款处理--微信结果:{}", refund.toString());
        if (refund.getStatus() == Status.SUCCESS ||
                refund.getStatus() == Status.PROCESSING) {
            log.info("发起退款成功:" + cashierPayment.getPaymentNo());
            return refund;
        } else {
            log.error("发起退款失败:{}", refund.getStatus());
            throw new BusinessException("发起退款失败");
        }
    }

    public QueryRefundDto queryRefundOrderV3(CashierPayment refundOrder) {
        Config wxConfig = wxConfigService.getWxConfig(refundOrder.getPayChannelId(),new PayChannel());
        RefundService service = new RefundService.Builder().config(wxConfig).build();
        QueryByOutRefundNoRequest request = new QueryByOutRefundNoRequest();
        // 【商户退款单号】 商户系统内部的退款单号
        request.setOutRefundNo(refundOrder.getPaymentNo());
        Refund refund = service.queryByOutRefundNo(request);
        log.error("退款订单查询--微信结果:{}", refund.toString());
        // 获取系统的退款单状态
        switch (refund.getStatus()) {
            case SUCCESS:
                log.info("退款成功......");
                refundOrder.setStatus(RefundStatusEnum.SUCCESS.getCode());
                refundOrder.setChannelRefundSuccessTime(LocalTimeUtils.dealDateFormatWithWx(refund.getSuccessTime()));
                break;
            case CLOSED:
                log.info("退款已关闭......");
                refundOrder.setStatus(RefundStatusEnum.CLOSED.getCode());
                break;
            case PROCESSING:
                log.info("退款处理中......");
                refundOrder.setStatus(RefundStatusEnum.PROCESSING.getCode());
                break;
            case ABNORMAL:
                log.error("退款异常......");
                refundOrder.setStatus(RefundStatusEnum.ABNORMAL.getCode());
                break;
            default:
                break;
        }
        refundOrder.setChannelRefundStatus(refund.getStatus().name());
        refundOrder.setChannelReturnCode(refund.getStatus().name());
        return buildQueryRefundDto(refund, refundOrder);
    }

    private QueryRefundDto buildQueryRefundDto(Refund refund, CashierPayment refundOrder) {
        QueryRefundDto queryRefundDto = new QueryRefundDto();
        queryRefundDto.setRefundNo(refund.getOutRefundNo());
        queryRefundDto.setRefundTime(LocalTimeUtils.dealDateFormatWithWx(refund.getSuccessTime()));
        queryRefundDto.setCreateTime(LocalTimeUtils.dealDateFormatWithWx(refund.getCreateTime()));
        queryRefundDto.setRefundAmount(refund.getAmount().getRefund());
        queryRefundDto.setAmount(refund.getAmount().getTotal());
        switch (refund.getStatus().name()) {
            case "SUCCESS":
                queryRefundDto.setStatus(1);
                break;
            case "CLOSED":
                queryRefundDto.setStatus(2);
                break;
            case "ABNORMAL":
                queryRefundDto.setStatus(4);
                break;
            default:
                queryRefundDto.setStatus(3);
                break;
        }
        return queryRefundDto;
    }
}

接口

package com.cztech.platform.cashier.payChannel.application;

import com.cztech.platform.cashier.domain.model.PayTypeEnum;
import com.cztech.platform.cashier.payChannel.domain.model.PayChannel;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.notification.NotificationConfig;

/**
 * packageName com.cztech.platform.cashier.payment
 *
 * @author GuoTong
 * @version JDK 8
 * @className WxConfigService
 * @date 2024/3/16
 * @description 初始化系统配置微信
 */
public interface WxConfigService {

    /**
     * 获取渠道的配置--微信
     *
     * @param channelId channelId
     * @return Config
     */
    Config getWxConfig(Long channelId,PayChannel payChannel);


    /**
     * 获取渠道的配置--微信
     *
     * @param payTypeEnumType PayTypeEnumType
     * @return Config
     */
    Config getWxConfig(Long merchantId, PayTypeEnum payTypeEnumType);


    /**
     * 微信支付回调验签配置
     *
     * @return NotificationConfig
     */
    NotificationConfig getCallBackConfig(String merchantNo,PayTypeEnum payTypeEnumType);


    /**
     * 获取渠道的配置--渠道自身信息
     *
     * @param merchantId payTypeEnumType
     * @return PayChannel
     */
    PayChannel getPayChannel(Long merchantId, PayTypeEnum payTypeEnumType);


    /**
     * 商户号区分回调
     * @param isRefund isRefund
     * @param merchantNo merchantNo
     * @return String
     */
    String getWxCallBackUrl(boolean isRefund,String merchantNo);
}

微信配置

package xxxx.platform.cashier.payChannel.application.impl;

import xxxx.common.domain.model.exception.BusinessException;
import xxxx.platform.cashier.common.RuleCommonUilt;
import xxxx.platform.cashier.common.config.SystemGlobalConfigProperties;
import xxxx.platform.cashier.domain.model.PayTypeEnum;
import xxxx.platform.cashier.payChannel.application.PayChannelService;
import xxxx.platform.cashier.payChannel.application.WxConfigService;
import xxxx.platform.cashier.payChannel.domain.model.PayChannel;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationConfig;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * packageName xxxx.platform.cashier.payment
 *
 * @author GuoTong
 * @version JDK 8
 * @className WxConfigService
 * @date 2024/3/16
 * @description 获取微信支付的配置
 */
@SuppressWarnings("all")
@Service
public class WxConfigServiceImpl implements WxConfigService {
    private Logger logger = LoggerFactory.getLogger(WxConfigServiceImpl.class);
    @Autowired
    private PayChannelService payChannelService;

    @Autowired
    private SystemGlobalConfigProperties systemGlobalConfigProperties;

    /**
     * 根据渠道类型和商户ID获取支付通道
     */
    private Map<String, Config> configMapByCache = new HashMap<>();

    /**
     * 根据渠道ID获取支付通道
     */
    private Map<Long, Config> configMapByIdCache = new HashMap<>();

    /**
     * 获取微信支付的配置| 根据商户号隔离
     */
    private Map<String, NotificationConfig> notificationConfig = new HashMap<>();


    /**
     * 渠道缓存
     */
    private Map<String, PayChannel> payChannelCache = new HashMap<>();
    @Value("${test.windows.certPath:D:\\BaiduNetdiskDownload\\微信支付秘密\\apiclient_key.pem}")
    private String certPathTestByWindows;

    /**
     * 内存多级缓存----缓存命中率优先
     */
    @Override
    public Config getWxConfig(Long channelId, PayChannel payChannelTarget) {
        if (configMapByIdCache.get(channelId) != null) {
            return configMapByIdCache.get(channelId);
        }
        PayChannel payChannel = null;
        if (payChannelTarget == null && channelId == null) {
            logger.error(this.getClass().getName() + RuleCommonUilt.NOT_FIND_PAY_CHANNEL);
            throw new BusinessException(RuleCommonUilt.NOT_FIND_PAY_CHANNEL);
        }
        payChannel = payChannelTarget;
        if (payChannel == null || payChannelTarget.getMid() == null) {
            payChannel = payChannelService.get(channelId);
        }
        String merchantId = payChannel.getMerchantId();
        String certPath = payChannel.getCertPath();
        if (StringUtils.isBlank(certPath)) {
            certPath = systemGlobalConfigProperties.getApiclientKeyByWechat();
        }
        if (StringUtils.isBlank(certPath)) {
            throw new BusinessException("微信支付配置错误,请Nacos先配置:微信支付私钥");
        }
        String os = System.getProperty("os.name");
        if (os.toLowerCase().startsWith("win")) {
            certPath = certPathTestByWindows;
        }
        String merchantSerialNumber = payChannel.getMerchantSerialNumber();
        String apiV3key = payChannel.getPrivateKey();
        // 获取微信支付的配置
        Config config = getConfig(merchantId, certPath, merchantSerialNumber, apiV3key);
        configMapByIdCache.put(channelId, config);
        return config;
    }

    /**
     * 内存缓存
     */
    @Override
    public Config getWxConfig(Long merchantMid, PayTypeEnum payTypeEnumType) {
        if (configMapByCache.get(RuleCommonUilt.WX_JSAPI + "_" + merchantMid + "_" + payTypeEnumType.getCode()) != null) {
            return configMapByCache.get(RuleCommonUilt.WX_JSAPI + "_" + merchantMid + "_" + payTypeEnumType.getCode());
        }
        // 查找关联关系的-------渠道商户
        List<PayChannel> payChannels = payChannelService.getMerchantAssociatedChannelVoGrid(merchantMid, payTypeEnumType.getCode());
        if (CollectionUtils.isEmpty(payChannels)) {
            logger.error("xxxx.platform.cashier.payChannel.application.impl.WxConfigServiceImpl.getWxConfig(java.lang.Long, xxxx.platform.cashier.domain.model.PayTypeEnum)==>未找到支付通道");
            return null;
        }
        PayChannel payChannelVarT = payChannels.get(0);
        String merchantId = payChannelVarT.getMerchantId();
        String certPath = payChannelVarT.getCertPath();
        if (StringUtils.isBlank(certPath)) {
            certPath = systemGlobalConfigProperties.getApiclientKeyByWechat();
        }
        if (StringUtils.isBlank(certPath)) {
            throw new BusinessException("微信支付配置错误,请Nacos先配置:微信支付私钥");
        }
        String os = System.getProperty("os.name");
        if (os.toLowerCase().startsWith("win")) {
            certPath = certPathTestByWindows;
        }
        String merchantSerialNumber = payChannelVarT.getMerchantSerialNumber();
        String apiV3key = payChannelVarT.getPrivateKey();
        // 获取微信支付的配置||内存缓存
        Config config = getConfig(merchantId, certPath, merchantSerialNumber, apiV3key);
        configMapByCache.put(RuleCommonUilt.WX_JSAPI + "_" + merchantMid + "_" + payTypeEnumType.getCode(), config);
        // 渠道赋值
        configMapByIdCache.put(payChannelVarT.getMid(), config);
        // 渠道缓存
        payChannelCache.put(RuleCommonUilt.WX_JSAPI + "_" + merchantMid + "_" + payTypeEnumType.getCode(), payChannelVarT);
        return config;
    }


    /**
     * 渠道侧接受微信回调|以商户号区分厂商
     * lazy多级缓存
     *
     * @param merchantNo
     * @param payTypeEnumType
     * @return
     */
    @Override
    public NotificationConfig getCallBackConfig(String merchantNo, PayTypeEnum payTypeEnumType) {
        // 多级缓存---提高性能
        if (notificationConfig.get(merchantNo) != null) {
            return notificationConfig.get(merchantNo);
        }
        // 查找关联关系的-------渠道商户
        List<PayChannel> payChannels = payChannelService.getThisMerchantNoPayChannel(merchantNo, payTypeEnumType.getCode());
        if (CollectionUtils.isEmpty(payChannels)) {
            logger.error("xxxx.platform.cashier.payChannel.application.impl.WxConfigServiceImpl.getWxConfig(java.lang.Long, xxxx.platform.cashier.domain.model.PayTypeEnum)==>未找到支付通道");
            return null;
        }
        PayChannel payChannel = payChannels.get(0);
        PayChannel payChannelVarT = payChannels.get(0);
        String merchantId = payChannel.getMerchantId();
        String certPath = payChannel.getCertPath();
        if (StringUtils.isBlank(certPath)) {
            certPath = systemGlobalConfigProperties.getApiclientKeyByWechat();
        }
        if (StringUtils.isBlank(certPath)) {
            throw new BusinessException("微信支付配置错误,请Nacos先配置:微信支付私钥");
        }
        String os = System.getProperty("os.name");
        if (os.toLowerCase().startsWith("win")) {
            certPath = certPathTestByWindows;
        }
        String merchantSerialNumber = payChannel.getMerchantSerialNumber();
        String apiV3key = payChannel.getPrivateKey();
        // 缓存回写----
        NotificationConfig config = getConfig(merchantId, certPath, merchantSerialNumber, apiV3key);
        notificationConfig.put(merchantNo, config);
        return config;
    }

    private static RSAAutoCertificateConfig getConfig(String merchantId, String certPath, String merchantSerialNumber, String apiV3key) {
        return new RSAAutoCertificateConfig.Builder()
                .merchantId(merchantId)
                .privateKeyFromPath(certPath)
                .merchantSerialNumber(merchantSerialNumber)
                .apiV3Key(apiV3key)
                .build();
    }

    @Override
    public PayChannel getPayChannel(Long merchantMid, PayTypeEnum payTypeEnumType) {
        PayChannel payChannel = payChannelCache.get(RuleCommonUilt.WX_JSAPI + "_" + merchantMid + "_" + payTypeEnumType.getCode());
        if (payChannel != null) {
            return payChannel;
        }
        // 查找关联关系的-------渠道商户
        List<PayChannel> payChannels = payChannelService.getMerchantAssociatedChannelVoGrid(merchantMid, payTypeEnumType.getCode());
        if (CollectionUtils.isEmpty(payChannels)) {
            logger.error("xxxx.platform.cashier.payChannel.application.impl.WxConfigServiceImpl.getPayChannel==>未找到支付通道");
            return null;
        }
        PayChannel payChannelVarT = payChannels.get(0);
        payChannelCache.put(RuleCommonUilt.WX_JSAPI + "_" + merchantMid + "_" + payTypeEnumType.getCode(), payChannelVarT);
        return payChannelVarT;
    }

    /**
     * 获取回调地址|路径参数--最后一位是商户编码:根据商户编码区分
     *
     * @param isRefund   isRefund
     * @param merchantNo merchantNo
     * @return
     */
    @Override
    public String getWxCallBackUrl(boolean isRefund, String merchantNo) {
        if (!isRefund) {
            String callBackUrl = systemGlobalConfigProperties.getBackUrlByWechat();
            if (StringUtils.isEmpty(callBackUrl)) {
                return "https://cashier.chinamuseum.cn/wxpay/notify/pay";
            } else {
                callBackUrl = callBackUrl + "/wxpay/notify/pay";
            }
            return callBackUrl + "/" + merchantNo;
        } else {
            String callBackUrl = systemGlobalConfigProperties.getBackUrlByWechat();
            if (StringUtils.isEmpty(callBackUrl)) {
                return "https://cashier.chinamuseum.cn/wxpay/notify/refund";
            } else {
                callBackUrl = callBackUrl + "/wxpay/notify/refund";
            }
            return callBackUrl + "/" + merchantNo;
        }
    }

}

posted on 2024-06-04 20:28  白嫖老郭  阅读(88)  评论(0编辑  收藏  举报

导航