最新版宁夏武警公众号项目后端

This commit is contained in:
sangchengzhi
2026-01-07 10:36:02 +08:00
parent 364a48d4c7
commit f8bb9dc094
1512 changed files with 531911 additions and 0 deletions

View File

@@ -0,0 +1,289 @@
package com.guahao.common.util;
import cn.hutool.json.JSONUtil;
import com.github.wxpay.sdk.WXPayUtil;
import com.guahao.common.Exception.LogicException;
import com.guahao.common.config.WxPayConfig;
import com.guahao.h5.reserve.service.Reserve8Service;
import com.guahao.common.util.WxPayDUtil;
import com.guahao.h5.reserve.vo.WxPayVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Autowired;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
@Component
public class WxPayUtil {
private Logger log = LoggerFactory.getLogger(WxPayUtil.class);
@Autowired
private WxPayConfig wxPayConfig;
/**
* 关闭微信支付订单
* @param wxPayVo 支付参数对象
* @return 关单结果
*/
public Map<String, String> closeOrder(WxPayVo wxPayVo) {
Map<String, String> result = new HashMap<>();
String outTradeNo = wxPayVo.getOutTradeNo();
log.info("开始关单: {}",outTradeNo);
// log.info("wxpayconfig:"+wxPayConfig.getAppId());
try {
// 构建请求参数
Map<String, String> data = new HashMap<>();
data.put("appid", wxPayConfig.getAppId());
data.put("mch_id", wxPayConfig.getMchId());
data.put("out_trade_no", outTradeNo);
data.put("nonce_str", WXPayUtil.generateNonceStr());
log.info("请求参数: {}", data);
// 生成签名
String sign = WXPayUtil.generateSignature(data, wxPayConfig.getApiKey());
data.put("sign", sign);
log.info("请求参数: {}", data);
// 转换为XML
String xmlParam = mapToXml(data);
log.info("关单请求XML: {}", xmlParam);
URL url = new URL("https://api.mch.weixin.qq.com/pay/closeorder");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 设置请求参数
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
connection.setRequestProperty("User-Agent", "Mozilla/5.0 (compatible; WeChat Pay SDK)");
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setConnectTimeout(10000);
connection.setReadTimeout(30000);
// 写入请求体
try (OutputStream os = connection.getOutputStream()) {
os.write(xmlParam.getBytes("UTF-8"));
}
int code = connection.getResponseCode();
log.info("关单HTTP状态码: {}", code);
// 读取响应
StringBuilder response = new StringBuilder();
try (InputStream is = code == 200 ? connection.getInputStream() : connection.getErrorStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"))) {
String line;
while ((line = br.readLine()) != null) {
response.append(line);
}
}
String responseXml = response.toString();
log.info("关单响应XML: {}", responseXml);
// 解析响应
Map<String, String> resultMap = xmlToMap(responseXml);
// ✅ 关键:必须同时判断 return_code 和 result_code
if ("SUCCESS".equals(resultMap.get("return_code"))
&& "SUCCESS".equals(resultMap.get("result_code"))) {
log.info("✅ 微信关单成功: {}", outTradeNo);
return resultMap; // 返回 SUCCESS
} else {
// 业务失败
String errorMsg = resultMap.get("return_msg");
String errCodeDes = resultMap.get("err_code_des");
log.error(" 微信关单失败: {} | {} | {}", outTradeNo, errorMsg, errCodeDes);
result.put("return_code", "FAIL");
result.put("return_msg", "关单失败: " + errorMsg + ", 详情: " + errCodeDes);
return result;
}
} catch (Exception e) {
// 正确写法:打印异常类名 + 消息 + 堆栈
String errorMsg = e.getMessage();
log.error(" 调用微信关单接口异常 [订单号: {}] [异常类型: {}] [异常消息: {}]",
outTradeNo,
e.getClass().getSimpleName(),
errorMsg == null ? "null" : errorMsg,
e); // e 放最后,用于输出堆栈
result.put("return_code", "FAIL");
result.put("return_msg", "网络异常: " + (errorMsg == null ? e.getClass().getSimpleName() : errorMsg));
}
return result;
}
/**
* 微信支付统一下单
*
* @param wxPayVo 支付参数
* @return 微信支付响应结果
*/
public Map<String, String> unifiedOrder(WxPayVo wxPayVo) throws Exception {
// 构造统一下单请求参数
Map<String, String> paramMap = new HashMap<>();
paramMap.put("appid", wxPayConfig.getAppId());
paramMap.put("mch_id", wxPayConfig.getMchId());
paramMap.put("nonce_str", wxPayVo.getNonceStr());
paramMap.put("body", wxPayVo.getBody());
paramMap.put("out_trade_no", wxPayVo.getOutTradeNo());
paramMap.put("total_fee", wxPayVo.getTotalFee().toString());
paramMap.put("spbill_create_ip", wxPayVo.getSpbillCreateIp());
paramMap.put("notify_url", "https://nxwj.btlsoln.com/nxgzh/pay/wxpay/notify");
paramMap.put("trade_type", "JSAPI");
paramMap.put("openid", wxPayVo.getOpenid());
// log.info("进入1generateSignature");
log.info("签名参数: " + JSONUtil.toJsonStr(paramMap));
// 生成签名
String sign = WxPayDUtil.generateSignature(paramMap, wxPayConfig.getApiKey());
paramMap.put("sign", sign);
// 转换为XML格式
String xmlParam = mapToXml(paramMap);
log.info("xmlParam: " + xmlParam);
HttpURLConnection connection = null;
BufferedReader reader = null;
try {
// 1. 创建 URL 对象
URL url = new URL("https://api.mch.weixin.qq.com/pay/unifiedorder");
connection = (HttpURLConnection) url.openConnection();
// 2. 设置请求参数
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
connection.setRequestProperty("User-Agent", "Mozilla/5.0 (compatible; WeChat Pay SDK)");
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setConnectTimeout(10000);
connection.setReadTimeout(30000);
// 3. 写入请求体XML
try (OutputStream os = connection.getOutputStream()) {
byte[] input = xmlParam.getBytes("UTF-8");
os.write(input, 0, input.length);
}
// 4. 获取响应码
int code = connection.getResponseCode();
log.info("code:" + code);
if (code == 200) {
// 5. 读取响应内容
StringBuilder response = new StringBuilder();
try (InputStream is = connection.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"))) {
String line;
while ((line = br.readLine()) != null) {
response.append(line);
}
}
String responseXml = response.toString();
log.info("微信支付响应XML: " + responseXml);
// 解析返回结果
Map<String, String> resultMap = xmlToMap(responseXml);
// 检查业务结果
if ("SUCCESS".equals(resultMap.get("return_code")) &&
"SUCCESS".equals(resultMap.get("result_code"))) {
// 构造返回给前端的js-sdk参数
Map<String, String> result = new HashMap<>();
result.put("appId", wxPayConfig.getAppId());
result.put("timeStamp", DateUtils.getTimesStamp());
result.put("nonceStr", wxPayVo.getNonceStr());
result.put("package", "prepay_id=" + resultMap.get("prepay_id"));
result.put("signType", "MD5");
// log.info("进入2generateSignature");
result.put("paySign", WxPayDUtil.generateSignature(result, wxPayConfig.getApiKey()));
result.put("outTradeNo", wxPayVo.getOutTradeNo());
return result; // 包含prepay_id等信息
} else {
String returnMsg = resultMap.get("return_msg");
String errCodeDes = resultMap.get("err_code_des");
throw new LogicException("微信支付统一下单失败:" + returnMsg + (errCodeDes != null ? ", 详细: " + errCodeDes : ""));
}
} else {
// 读取错误流(如 4xx/5xx
try (InputStream es = connection.getErrorStream();
BufferedReader br = new BufferedReader(new InputStreamReader(es, "UTF-8"))) {
StringBuilder errorMsg = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
errorMsg.append(line);
}
log.error("HTTP错误响应: " + errorMsg);
throw new LogicException("微信支付统一下单失败HTTP状态码 " + code + ", 响应: " + errorMsg);
}
}
} catch (IOException e) {
log.error("调用微信统一下单接口异常", e);
throw new RuntimeException("网络请求失败: " + e.getMessage(), e);
} finally {
if (connection != null) {
connection.disconnect(); // 释放连接
}
}
}
/**
* Map转XML
*/
public String mapToXml(Map<String, String> paramMap) {
try {
return WXPayUtil.mapToXml(paramMap);
} catch (Exception e) {
// 如果WXPayUtil不可用使用备用实现
return mapToXmlFallback(paramMap);
}
}
/**
* 备用的Map转XML实现
*/
private String mapToXmlFallback(Map<String, String> paramMap) {
StringBuilder sb = new StringBuilder();
sb.append("<xml>");
for (Map.Entry<String, String> entry : paramMap.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
// 对值进行XML转义
String escapedValue = escapeXml(value);
sb.append("<").append(key).append(">");
sb.append("<![CDATA[").append(escapedValue).append("]]>");
sb.append("</").append(key).append(">");
}
sb.append("</xml>");
return sb.toString();
}
/**
* XML转义
*/
private String escapeXml(String str) {
if (str == null || str.isEmpty()) {
return str;
}
return str.replace("]]>", "]]]]><![CDATA[>");
}
/**
* 解析微信支付返回的XML
*/
public Map<String, String> xmlToMap(String xmlStr) throws Exception {
return WXPayUtil.xmlToMap(xmlStr);
}
}