package com.ruoyi.payment.infrastructure.channel.wechat;
|
|
import com.ruoyi.payment.domain.model.PaymentOrder;
|
import com.ruoyi.payment.infrastructure.config.WechatPayConfig;
|
import lombok.extern.slf4j.Slf4j;
|
import org.apache.http.HttpEntity;
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
import org.apache.http.client.methods.HttpPost;
|
import org.apache.http.entity.StringEntity;
|
import org.apache.http.impl.client.CloseableHttpClient;
|
import org.apache.http.impl.client.HttpClients;
|
import org.apache.http.util.EntityUtils;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Component;
|
|
import java.util.HashMap;
|
import java.util.Map;
|
|
/**
|
* 微信支付v2客户端
|
*
|
* @author ruoyi
|
*/
|
@Slf4j
|
@Component
|
public class WxPayV2Client {
|
|
private static final String UNIFIED_ORDER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
|
private static final String ORDER_QUERY_URL = "https://api.mch.weixin.qq.com/pay/orderquery";
|
private static final String CLOSE_ORDER_URL = "https://api.mch.weixin.qq.com/pay/closeorder";
|
|
@Autowired
|
private WechatPayConfig wechatPayConfig;
|
|
@Autowired
|
private WxPayUtil wxPayUtil;
|
|
/**
|
* 统一下单 - Native支付
|
*/
|
public String unifiedOrder(PaymentOrder order) throws Exception {
|
log.info("调用微信统一下单接口,订单ID: {}", order.getId());
|
|
// 构造请求参数
|
Map<String, String> params = new HashMap<>();
|
params.put("appid", wechatPayConfig.getAppId());
|
params.put("mch_id", wechatPayConfig.getMchId());
|
params.put("nonce_str", generateNonceStr());
|
params.put("body", order.getSubject());
|
params.put("out_trade_no", String.valueOf(order.getId())); // 使用订单ID作为商户订单号
|
params.put("total_fee", String.valueOf(order.getAmount())); // 单位:分
|
params.put("spbill_create_ip", "127.0.0.1");
|
params.put("notify_url", wechatPayConfig.getNotifyUrl());
|
params.put("trade_type", "NATIVE");
|
|
if (order.getDescription() != null && !order.getDescription().isEmpty()) {
|
params.put("detail", order.getDescription());
|
}
|
|
// 生成签名
|
String sign = wxPayUtil.generateSign(params);
|
params.put("sign", sign);
|
|
// 转换为XML
|
String requestXml = wxPayUtil.mapToXml(params);
|
log.info("微信统一下单请求: {}", requestXml);
|
|
// 发送HTTP请求
|
String responseXml = doPost(UNIFIED_ORDER_URL, requestXml);
|
log.info("微信统一下单响应: {}", responseXml);
|
|
// 解析响应
|
Map<String, String> response = wxPayUtil.xmlToMap(responseXml);
|
|
// 验证响应签名
|
if (!wxPayUtil.verifySign(response)) {
|
throw new RuntimeException("微信返回签名验证失败");
|
}
|
|
// 检查返回状态
|
if (!"SUCCESS".equals(response.get("return_code"))) {
|
throw new RuntimeException("微信统一下单失败: " + response.get("return_msg"));
|
}
|
|
if (!"SUCCESS".equals(response.get("result_code"))) {
|
throw new RuntimeException("微信统一下单业务失败: " + response.get("err_code_des"));
|
}
|
|
// 返回code_url
|
String codeUrl = response.get("code_url");
|
if (codeUrl == null || codeUrl.isEmpty()) {
|
throw new RuntimeException("微信未返回code_url");
|
}
|
|
log.info("微信统一下单成功,code_url: {}", codeUrl);
|
return codeUrl;
|
}
|
|
/**
|
* 查询订单
|
*/
|
public Map<String, String> queryOrder(String outTradeNo) throws Exception {
|
log.info("查询微信订单,商户订单号: {}", outTradeNo);
|
|
Map<String, String> params = new HashMap<>();
|
params.put("appid", wechatPayConfig.getAppId());
|
params.put("mch_id", wechatPayConfig.getMchId());
|
params.put("out_trade_no", outTradeNo);
|
params.put("nonce_str", generateNonceStr());
|
|
String sign = wxPayUtil.generateSign(params);
|
params.put("sign", sign);
|
|
String requestXml = wxPayUtil.mapToXml(params);
|
String responseXml = doPost(ORDER_QUERY_URL, requestXml);
|
|
Map<String, String> response = wxPayUtil.xmlToMap(responseXml);
|
|
if (!wxPayUtil.verifySign(response)) {
|
throw new RuntimeException("查询订单响应签名验证失败");
|
}
|
|
if (!"SUCCESS".equals(response.get("return_code"))) {
|
throw new RuntimeException("查询订单失败: " + response.get("return_msg"));
|
}
|
|
return response;
|
}
|
|
/**
|
* 关闭订单
|
*/
|
public void closeOrder(String outTradeNo) throws Exception {
|
log.info("关闭微信订单,商户订单号: {}", outTradeNo);
|
|
Map<String, String> params = new HashMap<>();
|
params.put("appid", wechatPayConfig.getAppId());
|
params.put("mch_id", wechatPayConfig.getMchId());
|
params.put("out_trade_no", outTradeNo);
|
params.put("nonce_str", generateNonceStr());
|
|
String sign = wxPayUtil.generateSign(params);
|
params.put("sign", sign);
|
|
String requestXml = wxPayUtil.mapToXml(params);
|
String responseXml = doPost(CLOSE_ORDER_URL, requestXml);
|
|
Map<String, String> response = wxPayUtil.xmlToMap(responseXml);
|
|
if (!"SUCCESS".equals(response.get("return_code"))) {
|
throw new RuntimeException("关闭订单失败: " + response.get("return_msg"));
|
}
|
|
log.info("关闭微信订单成功");
|
}
|
|
/**
|
* 发送POST请求
|
*/
|
private String doPost(String url, String xmlData) throws Exception {
|
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
|
HttpPost httpPost = new HttpPost(url);
|
httpPost.setHeader("Content-Type", "text/xml;charset=UTF-8");
|
httpPost.setEntity(new StringEntity(xmlData, "UTF-8"));
|
|
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
|
HttpEntity entity = response.getEntity();
|
return EntityUtils.toString(entity, "UTF-8");
|
}
|
}
|
}
|
|
/**
|
* 生成随机字符串
|
*/
|
private String generateNonceStr() {
|
return java.util.UUID.randomUUID().toString().replace("-", "");
|
}
|
}
|