【微信支付】Springboot对接开发微信支付

一、微信配置申请

1、微信支付配置申请
详细操作流程参考官方文档:https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_8_1.shtml#part-1

配置完成需要以下信息:

APPID
商户号(mchid)
商户API私钥(apiclient_key.pem)
商户证书序列号
商户APIv3密钥

二、开发环境

1、开发环境

开发语言:java ,编译工具:idea ,框架:springboot ,仓库:maven

maven依赖

<dependency>
  <groupId>com.github.wechatpay-apiv3</groupId>
  <artifactId>wechatpay-java</artifactId>
  <version>0.2.10</version>
</dependency>

application.yml文件配置

#微信支付配置
wx:
  pay:
    #应用id(小程序id)
    appId: wx6b5xxxxxxxxxxxx
    #商户号
    merchantId: 1xxxxxxxxx
    #商户API私钥
    privateKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    #商户证书序列号
    merchantSerialNumber: 315DDXXXXXXXXXXXXXXXXXXXXXXXXXXX
    #商户APIv3密钥
    apiV3Key: XXXXXXXXXXXXXXXXXXXXXXXXXX
    #支付通知地址
    payNotifyUrl: https://xxx.xxxx.xxx.xxx/xx/xxxx/xxxx/openapi/wx/payNotify
    #退款通知地址
    refundNotifyUrl: https://xxx.xxx.xxx.xxx/xxxx/xxxx/xxxx/openapi/wx/refundNotify

三、开发

配置类

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
 * @author zzjjyy
 * @ClassName WxPayConfig
 * @description: 微信支付配置类
 * @date 2024
 * @version: 1.0
 */
@Data
@Component
@ConfigurationProperties(prefix = "wx.pay")
public class WxPayConfig {
    //APPID
    private String appId;
    //mchid
    private String merchantId;
    //商户API私钥
    private String privateKey;
    //商户证书序列号
    private String merchantSerialNumber;
    //商户APIv3密钥
    private String apiV3Key;
    //支付通知地址
    private String payNotifyUrl;
    //退款通知地址
    private String refundNotifyUrl;
}

初始化商户配置

import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; 
import javax.annotation.Resource; 
/**
 * @author zzjjyy
 * @ClassName WxPayAutoCertificateConfig
 * @description: 微信支付证书自动更新配置
 * @date 2024年
 * @version: 1.0
 */
@Configuration
public class WxPayAutoCertificateConfig {
    @Resource
    private WxPayConfig wxPayConfig;
    /**
     * 初始化商户配置
     * @return
     */
    @Bean
    public RSAAutoCertificateConfig rsaAutoCertificateConfig() {
        RSAAutoCertificateConfig config = new RSAAutoCertificateConfig.Builder()
                .merchantId(wxPayConfig.getMerchantId())
                .privateKey(wxPayConfig.getPrivateKey())
                .merchantSerialNumber(wxPayConfig.getMerchantSerialNumber())
                .apiV3Key(wxPayConfig.getApiV3Key())
                .build();
        return config;
    }
}

微信支付回调通知

/***
     * 微信支付回调通知
     * @param request
     * @return
     * @throws IOException
     */
    @Transactional
    public synchronized String payNotify(HttpServletRequest request) throws Exception {
        log.info("------收到支付通知------");
        // 请求头Wechatpay-Signature
        String signature = request.getHeader("Wechatpay-Signature");
        // 请求头Wechatpay-nonce
        String nonce = request.getHeader("Wechatpay-Nonce");
        // 请求头Wechatpay-Timestamp
        String timestamp = request.getHeader("Wechatpay-Timestamp");
        // 微信支付证书序列号
        String serial = request.getHeader("Wechatpay-Serial");
        // 签名方式
        String signType = request.getHeader("Wechatpay-Signature-Type");
        // 构造 RequestParam
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(serial)
                .nonce(nonce)
                .signature(signature)
                .timestamp(timestamp)
                .signType(signType)
                .body(HttpServletUtils.getRequestBody(request))
                .build();
        // 初始化 NotificationParser
        NotificationParser parser = new NotificationParser(rsaAutoCertificateConfig);
        // 以支付通知回调为例,验签、解密并转换成 Transaction
        log.info("验签参数:{}", requestParam);
        Transaction transaction = parser.parse(requestParam, Transaction.class);
        log.info("验签成功!-支付回调结果:{}", transaction.toString());
        Map<String, String> returnMap = new HashMap<>(2);
        returnMap.put("code", "FAIL");
        returnMap.put("message", "失败");
        //修改订单前,建议主动请求微信查询订单是否支付成功,防止恶意post
        Wrapper wrapper = new EntityWrapper<WxOrderEntity>();
        wrapper.eq("out_trade_no", transaction.getOutTradeNo());
        //wrapper.eq("transaction_id", transaction.getTransactionId());
        WxOrderEntity wxOrderEntity = wxOrderDataService.selectOne(wrapper);
        if (wxOrderEntity != null) {
            if (wxOrderEntity.getPayStatus() == 1) {
                //此时已经是支付成功,不在处理订单信息
                returnMap.put("code", "SUCCESS");
                returnMap.put("message", "成功");
                return JSONObject.toJSONString(returnMap);
            }
        }
        if (Transaction.TradeStateEnum.SUCCESS != transaction.getTradeState()) {
            log.info("内部订单号【{}】,微信支付订单号【{}】支付未成功", transaction.getOutTradeNo(), transaction.getTransactionId());
            if (wxOrderEntity != null) {
                wxOrderEntity.setUpdateTime(new Date());
                wxOrderEntity.setPayStatus(2);
                wxOrderEntity.setPayNonce(nonce);
                wxOrderEntity.setTransactionId(transaction.getTransactionId());
                //修改订单信息
                wxOrderDataService.updateById(wxOrderEntity);
            }
            return JSONObject.toJSONString(returnMap);
        }
        if (wxOrderEntity != null) {
            wxOrderEntity.setUpdateTime(new Date());
            wxOrderEntity.setPayTime(DateUtils.stringToDateTime(transaction.getSuccessTime()));
            wxOrderEntity.setPayDate(DateUtils.stringToDateTime(transaction.getSuccessTime()));
            wxOrderEntity.setPayStatus(1);
            wxOrderEntity.setPayNonce(nonce);
            wxOrderEntity.setTransactionId(transaction.getTransactionId());
            //修改订单信息
            wxOrderDataService.updateById(wxOrderEntity);
            //同时处理支付记录
            Wrapper payWrapper = new EntityWrapper<WxPayLogEntity>();
            wrapper.eq("out_trade_no", transaction.getOutTradeNo());
            wrapper.eq("pay_status", 1);//支付
            WxPayLogEntity wxPayLogEntity = wxPayLogDataService.selectOne(payWrapper);
            if (wxPayLogEntity == null) {
                wxPayLogEntity = new WxPayLogEntity();
                wxPayLogEntity.setCreateTime(new Date());
                wxPayLogEntity.setOutTradeNo(wxOrderEntity.getOutTradeNo());
                wxPayLogEntity.setPayStatus(1);
                wxPayLogEntity.setTotalFee(wxOrderEntity.getTotalFee());
                wxPayLogEntity.setTransactionId(wxOrderEntity.getTransactionId());
                wxPayLogEntity.setWxOpenId(wxOrderEntity.getWxOpenId());
                wxPayLogDataService.insert(wxPayLogEntity);
            }
        }
        returnMap.put("code", "SUCCESS");
        returnMap.put("message", "成功");
        return JSONObject.toJSONString(returnMap);
    }

根据商户订单号查询订单(out_trade_no)

/***
     * 根据商户订单号查询订单 outTradeNo
     * @param req
     * @return
     */
    @Transactional
    public R queryOrderByOrderNo(QueryOrderReq req) {
        QueryOrderByOutTradeNoRequest queryRequest = new QueryOrderByOutTradeNoRequest();
        queryRequest.setMchid(wxPayConfig.getMerchantId());
        queryRequest.setOutTradeNo(req.getOrderNo());
        try {
            JsapiServiceExtension service =
                    new JsapiServiceExtension.Builder()
                            .config(rsaAutoCertificateConfig)
                            .signType("RSA") // 不填默认为RSA
                            .build();
            Transaction result = service.queryOrderByOutTradeNo(queryRequest);
            LinkedHashMap retmap = new LinkedHashMap();
            //支付成功
            if (Transaction.TradeStateEnum.SUCCESS == result.getTradeState()) {
                log.info("内部订单号【{}】,微信支付订单号【{}】支付成功", result.getOutTradeNo(), result.getTransactionId());
                retmap.put("out_trade_no", result.getOutTradeNo());
                retmap.put("transaction_id", result.getTransactionId());
                retmap.put("success", true);
                retmap.put("msg", "支付成功!");
                retmap.put("success_time", DateUtils.getDateTimeString(DateUtils.stringToDateTime(result.getSuccessTime())));
                //主动查询
                Wrapper wrapper = new EntityWrapper<WxOrderEntity>();
                wrapper.eq("out_trade_no", req.getOrderNo());
                WxOrderEntity wxOrderEntity = wxOrderDataService.selectOne(wrapper);
                if (wxOrderEntity != null) {
                    if (wxOrderEntity.getPayStatus() != 1) {
                        wxOrderEntity.setPayStatus(1);
                        wxOrderEntity.setTransactionId(result.getTransactionId());
                        wxOrderEntity.setPayDate(DateUtils.stringToDateTime(result.getSuccessTime()));
                        wxOrderEntity.setPayTime(DateUtils.stringToDateTime(result.getSuccessTime()));
                        wxOrderEntity.setUpdateTime(new Date());
                        wxOrderDataService.updateById(wxOrderEntity);
                        //同时处理支付记录
                        Wrapper payWrapper = new EntityWrapper<WxPayLogEntity>();
                        wrapper.eq("out_trade_no", req.getOrderNo());
                        WxPayLogEntity wxPayLogEntity = wxPayLogDataService.selectOne(payWrapper);
                        if (wxPayLogEntity == null) {
                            wxPayLogEntity = new WxPayLogEntity();
                            wxPayLogEntity.setCreateTime(new Date());
                            wxPayLogEntity.setOutTradeNo(wxOrderEntity.getOutTradeNo());
                            wxPayLogEntity.setPayStatus(1);
                            wxPayLogEntity.setTotalFee(wxOrderEntity.getTotalFee());
                            wxPayLogEntity.setTransactionId(result.getTransactionId());
                            wxPayLogEntity.setWxOpenId(wxOrderEntity.getWxOpenId());
                            wxPayLogDataService.insert(wxPayLogEntity);
                        }
                    }
                }
            } else {
                log.info("内部订单号【{}】,微信支付订单号【{}】支付未成功", result.getOutTradeNo(), result.getTransactionId());
                retmap.put("out_trade_no", result.getOutTradeNo());
                retmap.put("transaction_id", result.getTransactionId());
                retmap.put("success", false);
                retmap.put("msg", "支付失败!");
                retmap.put("success_time", null);
            }
            return R.ok().put("data", retmap);
        } catch (ServiceException e) {
            log.error("订单查询失败,返回码:{},返回信息:{}", e.getErrorCode(), e.getErrorMessage());
            return R.error("订单查询失败!");
        }
    }

微信申请退款

/***
     * 微信申请退款
     * @param outTradeNo 商户订单号
     * @param totalAmount
     * @return
     */
    public R createRefund(String outTradeNo, Long totalAmount) {
        //返回参数
        LinkedHashMap map = new LinkedHashMap();
        map.put("out_trade_no", outTradeNo);
        map.put("success", false);
        map.put("msg", "正在申请退款中!");
        String outRefundNo = "REFUND_" + outTradeNo;
        map.put("out_refund_no", outRefundNo);
        //申请退款订单,需要变更订单记录
        Wrapper wrapper = new EntityWrapper<WxOrderEntity>();
        wrapper.eq("out_trade_no", outTradeNo);
        WxOrderEntity wxOrderEntity = wxOrderDataService.selectOne(wrapper);
        if (wxOrderEntity == null) {
            return R.error("订单不存在,申请退款不存在!");
        }
        wxOrderEntity.setPayStatus(4);//退款中
        wxOrderEntity.setUpdateTime(new Date());
        wxOrderDataService.updateById(wxOrderEntity);
        try {
            // 构建退款service
            RefundService service = new RefundService.Builder()
                    .config(rsaAutoCertificateConfig)
                    .build();
            CreateRequest request = new CreateRequest();
            // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
            request.setOutTradeNo(outTradeNo);
            request.setOutRefundNo(outRefundNo);
            AmountReq amount = new AmountReq();
            amount.setTotal(totalAmount);
            amount.setRefund(totalAmount);
            amount.setCurrency("CNY");
            request.setAmount(amount);
            request.setNotifyUrl(wxPayConfig.getRefundNotifyUrl());
            //接收退款返回参数
            Refund refund = service.create(request);
            log.info("退款返回信息:{}", refund);
            if (refund.getStatus().equals(Status.SUCCESS)) {
                map.put("success", true);
                map.put("msg", "退款成功!");
                //说明退款成功,开始接下来的业务操作
                //主动查询
                Wrapper againWrapper = new EntityWrapper<WxOrderEntity>();
                againWrapper.eq("out_trade_no", outTradeNo);
                WxOrderEntity orderEntity = wxOrderDataService.selectOne(againWrapper);
                if (orderEntity != null) {
                    orderEntity.setPayStatus(3);//退款成功
                    orderEntity.setUpdateTime(new Date());
                    wxOrderDataService.updateById(orderEntity);
                    //同时处理退款记录
                    Wrapper payWrapper = new EntityWrapper<WxPayLogEntity>();
                    payWrapper.eq("out_trade_no", outTradeNo);
                    payWrapper.eq("pay_status", 2);//退款
                    WxPayLogEntity wxPayLogEntity = wxPayLogDataService.selectOne(payWrapper);
                    if (wxPayLogEntity == null) {
                        wxPayLogEntity = new WxPayLogEntity();
                        wxPayLogEntity.setCreateTime(new Date());
                        wxPayLogEntity.setOutTradeNo(outTradeNo);
                        wxPayLogEntity.setPayStatus(2);
                        wxPayLogEntity.setTotalFee(totalAmount.intValue());
                        wxPayLogEntity.setTransactionId(wxOrderEntity.getTransactionId());
                        wxPayLogEntity.setOutRefundNo(outRefundNo);
                        wxPayLogEntity.setWxOpenId(wxOrderEntity.getWxOpenId());
                        wxPayLogDataService.insert(wxPayLogEntity);
                    }
                }
            }
        } catch (ServiceException e) {
            log.error("退款失败!,错误信息:{}", e.getMessage());
            return R.error("退款失败!");
        } catch (Exception e) {
            log.error("服务返回成功,返回体类型不合法,或者解析返回体失败,错误信息:{}", e.getMessage());
            return R.error("退款失败!");
        }
        return R.ok().put("data", map);
    }

Jinming

95后典型金牛座,强迫症。

相关推荐

暂无评论

小程序 小程序
小程序