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<String, String> xmlToMap(String xml) throws Exception {
|
Map<String, String> 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<String, String> data) {
|
StringBuilder xml = new StringBuilder("<xml>");
|
for (Map.Entry<String, String> entry : data.entrySet()) {
|
xml.append("<").append(entry.getKey()).append(">");
|
xml.append("<![CDATA[").append(entry.getValue()).append("]]>");
|
xml.append("</").append(entry.getKey()).append(">");
|
}
|
xml.append("</xml>");
|
return xml.toString();
|
}
|
|
/**
|
* 生成签名
|
*/
|
public String generateSign(Map<String, String> data) {
|
// 1. 参数名ASCII码从小到大排序
|
Set<String> 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<String, String> 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<String, String> response = new HashMap<>();
|
response.put("return_code", "SUCCESS");
|
response.put("return_msg", "OK");
|
return mapToXml(response);
|
}
|
|
/**
|
* 构造失败应答
|
*/
|
public String buildFailResponse(String msg) {
|
Map<String, String> response = new HashMap<>();
|
response.put("return_code", "FAIL");
|
response.put("return_msg", msg);
|
return mapToXml(response);
|
}
|
}
|