package com.ruoyi.payment.infrastructure.channel.wechat; import com.ruoyi.payment.infrastructure.config.WechatPayConfig; import com.ruoyi.payment.infrastructure.util.SignUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.util.*; /** * 微信支付工具类 * * @author ruoyi */ @Slf4j @Component public class WxPayUtil { @Autowired private WechatPayConfig wechatPayConfig; /** * XML转Map */ public Map xmlToMap(String xml) throws Exception { Map data = new HashMap<>(); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); InputStream is = new ByteArrayInputStream(xml.getBytes("UTF-8")); Document doc = builder.parse(is); doc.getDocumentElement().normalize(); NodeList nodeList = doc.getDocumentElement().getChildNodes(); for (int i = 0; i < nodeList.getLength(); i++) { Node node = nodeList.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { data.put(node.getNodeName(), node.getTextContent()); } } return data; } /** * Map转XML */ public String mapToXml(Map data) { StringBuilder xml = new StringBuilder(""); for (Map.Entry entry : data.entrySet()) { xml.append("<").append(entry.getKey()).append(">"); xml.append(""); xml.append(""); } xml.append(""); return xml.toString(); } /** * 生成签名 */ public String generateSign(Map data) { // 1. 参数名ASCII码从小到大排序 Set keySet = data.keySet(); String[] keyArray = keySet.toArray(new String[0]); Arrays.sort(keyArray); // 2. 拼接参数 StringBuilder sb = new StringBuilder(); for (String k : keyArray) { if ("sign".equals(k)) { continue; } String value = data.get(k); if (value != null && value.trim().length() > 0) { sb.append(k).append("=").append(value).append("&"); } } // 3. 拼接密钥 sb.append("key=").append(wechatPayConfig.getMchKey()); // 4. MD5加密并转大写 return SignUtil.md5(sb.toString()); } /** * 验证签名 */ public boolean verifySign(Map data) { if(!wechatPayConfig.getCheckSign()){ log.info("微信回调不检测验证签名"); return true; } String sign = data.get("sign"); if (sign == null || sign.isEmpty()) { return false; } String calculatedSign = generateSign(data); return sign.equals(calculatedSign); } /** * 构造成功应答 */ public String buildSuccessResponse() { Map response = new HashMap<>(); response.put("return_code", "SUCCESS"); response.put("return_msg", "OK"); return mapToXml(response); } /** * 构造失败应答 */ public String buildFailResponse(String msg) { Map response = new HashMap<>(); response.put("return_code", "FAIL"); response.put("return_msg", msg); return mapToXml(response); } }