package org.jeecg.modules.qywx.message.controller; import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.digest.DigestUtils; import org.jeecg.modules.qywx.message.utils.WXBizMsgCrypt; import org.springframework.web.bind.annotation.*; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import java.io.StringReader; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.util.*; /** * 企业微信消息回调接口(支持 URL 验证 + 消息接收) */ @RestController @RequestMapping("/qywx/message/callback") @Slf4j public class WeComCallbackController { // 替换为你的应用配置 private static final String TOKEN = "bPGpQimYTtjAfAj2uTE4fb"; private static final String AES_KEY = "hkbscaEtxWAydMIoWe8EW4drpHXaYroQPKBMoKCs2bf"; // EncodingAESKey private static final String CORP_ID = "ww5999b2643c95fa75"; // 企业 ID 或 AppId private static WXBizMsgCrypt wxBizMsgCrypt; static { try { wxBizMsgCrypt = new WXBizMsgCrypt(TOKEN, AES_KEY, CORP_ID); } catch (Exception e) { throw new RuntimeException("初始化 WXBizMsgCrypt 失败,请检查 Token/AESKey/AppId 是否正确", e); } } /** * GET 请求:用于 URL 验证(Token 校验) */ @GetMapping(produces = "text/plain;charset=utf-8") public String verifyUrl( @RequestParam("msg_signature") String msgSignature, @RequestParam("timestamp") String timestamp, @RequestParam("nonce") String nonce, @RequestParam("echostr") String echostr) { try { log.info("收到企业微信 URL 验证请求:msg_signature={}, timestamp={}, nonce={}, echostr={}", msgSignature, timestamp, nonce, echostr); // 调用官方 SDK 验证并解密 String decryptedEchoStr = wxBizMsgCrypt.VerifyURL(msgSignature, timestamp, nonce, echostr); log.info("解密后的 echostr: {}", decryptedEchoStr); // 返回解密后的内容(企业微信要求必须原样返回) return decryptedEchoStr; } catch (Exception e) { log.error("URL 验证失败", e); return "fail"; } } /** * POST 请求:接收企业微信推送的消息 */ @PostMapping(produces = "text/xml;charset=utf-8") public String handleWeComCallback(@RequestBody String xmlData, @RequestParam("msg_signature") String msgSignature, @RequestParam("timestamp") String timestamp, @RequestParam("nonce") String nonce) { try { log.info("收到企业微信消息推送:msg_signature={}, timestamp={}, nonce={}", msgSignature, timestamp, nonce); log.info("原始 XML 数据: {}", xmlData); // Step 1: 解密消息 String plainXml = wxBizMsgCrypt.DecryptMsg(msgSignature, timestamp, nonce, xmlData); log.info("解密后的明文消息: {}", plainXml); // Step 2: 解析 XML 并处理业务逻辑 Map msgMap = parseXmlToMap(plainXml); String eventType = msgMap.get("Event"); String content = msgMap.get("Content"); log.info("事件类型: {}, 消息内容: {}", eventType, content); // Step 3: 业务处理(示例:回复 success) String responseXml = "0success"; return responseXml; } catch (Exception e) { log.error("处理企业微信消息失败", e); return "1fail"; } } /** * 将 XML 转为 Map */ private Map parseXmlToMap(String xml) throws Exception { Map map = new HashMap<>(); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); StringReader reader = new StringReader(xml); InputSource source = new InputSource(reader); Document doc = builder.parse(source); Element root = doc.getDocumentElement(); NodeList list = root.getChildNodes(); for (int i = 0; i < list.getLength(); i++) { if (list.item(i).getNodeType() == Document.ELEMENT_NODE) { Element element = (Element) list.item(i); map.put(element.getNodeName(), element.getTextContent()); } } return map; } //public static void main(String[] args) throws UnsupportedEncodingException { // String msg_signature = "eae930cbae5d988ed29f8aac6cf221016f81669e"; // String timestamp = "1751356163"; // String nonce = "16ljuxd4gd8"; // String echostr = "Ax30h%2BharWss%2FeNNQl8x4KdzggrpmLFH8i%2F0mHqVGbcKcq1NeascovZV%2B08ooq5o0ng8RJ2WPyo69A8oGhKpxA%3D%3D"; // // String decode = URLDecoder.decode(echostr, "UTF-8"); // //System.out.println(decode); // WeComCallbackController weComCallbackController = new WeComCallbackController(); // String decryptedEchoStr = weComCallbackController.verifyUrl(msg_signature, timestamp, nonce, decode); // System.out.println(decryptedEchoStr); //} }