一:参照文档
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



