huaweichenai头像

spring boot对接微信支付

一:参照文档

GitHub - binarywang/WxJava: 微信开发 Java SDK ,支持包括微信支付,开放平台,小程序,企业微信,视频号,公众号等的后端开发 · GitHub

二:依赖安装

<dependency>
    <groupId>com.github.binarywang</groupId>
    <artifactId>weixin-java-pay</artifactId>
    <version>4.7.0</version>
</dependency>

三:微信支付配置

wechat:
  pay:
    mch-id: xxx      # 商户号
    mch-key: xxx   # V2的API密钥(MD5签名用)
    sub-appid: xxx       # 小程序/公众号appid(当前商户关联的appid)
    # 证书(退款、红包等接口必须)
    cert-path:
    cert-password:

四:微信支付配置类

package com.example.demo.config;

import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Data
@Configuration
@ConfigurationProperties(prefix = "wechat.pay")
public class WxPayAutoConfig {
    private String mchId;
    private String mchKey;
    private String subAppid;
    private String certPath;
    private String certPassword;

    @Bean
    public WxPayService wxPayService() {
        WxPayConfig payConfig = new WxPayConfig();
        payConfig.setMchId(mchId);
        payConfig.setMchKey(mchKey);
        // yaml 里的 sub-appid 实际是商户关联的公众号/小程序 appid,对应 SDK 的 appId
        payConfig.setAppId(subAppid);
        // 退款、红包需要 p12 证书;证书密码 SDK 默认用商户号,无需 setCertPassword
        payConfig.setKeyPath(certPath);

        WxPayService wxPayService = new WxPayServiceImpl();
        wxPayService.setConfig(payConfig);
        return wxPayService;
    }
}

五:微信支付服务类

package com.example.demo.service;

import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayRefundQueryResult;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class WxPayAutoService {
    @Autowired
    private WxPayService wxPayService;

    /**
     * JSAPI 统一下单
     * @param openId 小程序用户openid
     * @param outTradeNo 商户订单号(自己生成,唯一)
     * @param totalFee 金额,单位:分
     * @param body 商品描述
     * @param notifyUrl 支付异步回调地址,公网https
     */
    public WxPayMpOrderResult jsapiUnifiedOrder(String openId, String outTradeNo, Integer totalFee, String body, String notifyUrl) throws WxPayException {
        WxPayUnifiedOrderRequest request = WxPayUnifiedOrderRequest.newBuilder()
                .openid(openId)
                .outTradeNo(outTradeNo)
                .totalFee(totalFee)
                .body(body)
                .notifyUrl(notifyUrl)
                .tradeType(WxPayConstants.TradeType.JSAPI)
                .spbillCreateIp("127.0.0.1")
                .build();
        // createOrder 会统一下单并生成小程序/JSAPI 调起支付签名,无需再调 createJsapiSign
        return wxPayService.createOrder(request);
    }

    /**
     * Native扫码支付下单(扫码支付)
     * @param outTradeNo 商户订单号(唯一,自己生成)
     * @param totalFee 金额【单位:分!】1元=100
     * @param body 商品描述
     * @param notifyUrl 异步回调地址,公网https
     * @param productId 商品ID,商户自定义,最长32字符
     * @return code_url 二维码内容,前端生成二维码
     */
    public String nativeCreateOrder(String outTradeNo, Integer totalFee, String body, String notifyUrl, String productId) throws WxPayException {
        WxPayUnifiedOrderRequest request = WxPayUnifiedOrderRequest.newBuilder()
                .outTradeNo(outTradeNo)
                .totalFee(totalFee)
                .body(body)
                .notifyUrl(notifyUrl)
                .tradeType(WxPayConstants.TradeType.NATIVE)
                .spbillCreateIp("127.0.0.1")
                .productId(productId)
                .build();
        WxPayUnifiedOrderResult result = wxPayService.unifiedOrder(request);
        // 核心返回:code_url,前端生成二维码
        return result.getCodeURL();
    }

    /**
     * 订单查询
     * @param outTradeNo 商户订单号
     * @return 订单状态
     */
    public String queryOrder(String outTradeNo) throws WxPayException {
        // SUCCESS 支付成功,NOTPAY 未支付,CLOSED已关闭
        return wxPayService.queryOrder(null, outTradeNo).getTradeState();
    }

    /**
     * 订单退款
     * @param outTradeNo
     * @param refundNo
     * @param totalFee
     * @param refundFee
     * @return
     */
    public WxPayRefundResult refund(String outTradeNo, String refundNo, Integer totalFee, Integer refundFee) throws WxPayException {
        WxPayRefundRequest refundReq = WxPayRefundRequest.newBuilder()
                .outTradeNo(outTradeNo)
                .outRefundNo(refundNo)
                .totalFee(totalFee)
                .refundFee(refundFee)
                .build();
        WxPayRefundResult refund = wxPayService.refund(refundReq);
        return refund;
    }

    /**
     * 订单退款查询
     * @param outTradeNo 商户订单号
     * @param refundNo 退款订单号
     * @return 退款状态
     */
    public String queryRefund(String outTradeNo, String refundNo) throws WxPayException {
        // 四个参数四选一:微信订单号、商户订单号、商户退款单号、微信退款单号
        WxPayRefundQueryResult result = wxPayService.refundQuery(null, outTradeNo, refundNo, null);
        if (result.getRefundRecords() == null || result.getRefundRecords().isEmpty()) {
            return null;
        }
        //SUCCESS 退款成功,PROCESSING 退款中,REFUNDCLOSE 退款关闭 CHANGE 退款异常 REFUNDNOTEXIST 退款单号不存在,SYSTEMERROR 退款失败,NOTSURE 退款异常,CHANGE 退款异常
        return result.getRefundRecords().get(0).getRefundStatus();
    }

}

六:微信支付调用示例

package com.example.demo.controller;

import com.example.demo.service.WxPayAutoService;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.nio.charset.StandardCharsets;

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

@RestController
@RequestMapping("/wechat-pay")
public class WechatPayController {
    @Autowired
    private WxPayAutoService wxPayAutoService;

    @Autowired
    private WxPayService wxPayService;

    /**
     * JSAPI/小程序下单,返回 wx.requestPayment 所需参数
     */
    @GetMapping("/jsapi")
    public WxPayMpOrderResult jsapiPay() throws WxPayException {
        return wxPayAutoService.jsapiUnifiedOrder(
                "o8LXM6hDf4MLhWu5QoBM5arxj84A",
                "test001",
                1, // 1元 = 100分
                "测试",
                "http://xxx"
        );
    }

    /**
     * 创建扫码订单,返回code_url,前端生成二维码
     */
    @GetMapping("/native")
    public String createNative(){
        Map<String,Object> map = new HashMap<>();
        try {
            String codeUrl = wxPayAutoService.nativeCreateOrder(
                    "test002",
                    1,       // 1元 = 100分
                    "测试",
                    "http://xxx", // 你的回调地址,必须公网https
                    "001"
            );
            return codeUrl;
        } catch (WxPayException e) {
            return e.getMessage();
        }
    }

    /**
     * 查询订单状态
     */
    @GetMapping("/query")
    public String query() throws WxPayException {
        return wxPayAutoService.queryOrder("test001");
    }

    /**
     * 订单退款
     */
    @GetMapping("/refund")
    public WxPayRefundResult refund() throws WxPayException {
        return wxPayAutoService.refund("test001", "refund001", 1, 1);
    }

    /**
     * 订单退款
     */
    @GetMapping("/refund-query")
    public String refundQuery(String outTradeNo) throws WxPayException {
        return wxPayAutoService.queryRefund("test001", "refund001");
    }

    /**
     * 支付回调
     */
    @PostMapping("/notify")
    @ResponseBody
    public String payNotify(HttpServletRequest request) {
        try {
            String xmlData = new String(request.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
            // SDK 验签并解析 XML,入参是通知原文而不是 HttpServletRequest
            WxPayOrderNotifyResult notifyResult = wxPayService.parseOrderNotifyResult(xmlData);
            String outTradeNo = notifyResult.getOutTradeNo();

            // =====【幂等!】先查数据库订单状态,如果已经处理,直接返回success,不要再执行业务=====
            // if(订单已支付) return WxPayNotifyResponse.success("success");

            // 支付回调里用 result_code,trade_state 是查单接口的字段
            if ("SUCCESS".equals(notifyResult.getResultCode())) {
                // 业务:更新数据库订单为【已支付】、记录支付流水
            }
            // 成功返回SUCCESS,微信停止重试
            return WxPayNotifyResponse.success("success");
        } catch (Exception e) {
            // 返回fail,微信会继续重试推送通知
            return WxPayNotifyResponse.fail("fail");
        }
    }

}

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/huaweichenai/article/details/168139309

文章来源转载

评论

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--