企業微信服務商創建第三方應用配置數據回調url和指令回調url的java代碼實現

關鍵區別說明(指令回調 vs 數據回調)

特性指令回調數據回調
觸發場景授權/取消授權等管理事件通訊錄變更、應用菜單點擊等業務事件
關鍵字段InfoTypeEvent?+?ChangeType
典型事件suite_auth, cancel_authchange_contact, suite_ticket
響應要求必須返回加密的"success"必須返回加密的"success"

xml:?

<dependencies><!-- Spring Boot Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- 企業微信官方加解密庫 --><dependency><groupId>com.github.binarywang</groupId><artifactId>weixin-java-cp</artifactId><version>4.5.0</version></dependency><!-- XML處理 --><dependency><groupId>org.dom4j</groupId><artifactId>dom4j</artifactId><version>2.1.3</version></dependency>
</dependencies>

controller


import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.example.testchat.aes.WXBizMsgCrypt;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;@RestController
@RequestMapping("/callback")
public class WxWorkCallbackController {private static final Logger logger = LoggerFactory.getLogger(WxWorkCallbackController.class);@Value("${qiyewx.token}")private String token;@Value("${qiyewx.encodingAESKey}")private String encodingAESKey;@Value("${qiyewx.corpid}")private String corpid;@Value("${qiyewx.suiteId}")private String suiteId;/*** 數據回調驗證接口 (GET請求)*/@GetMapping("/data")public String validateDataCallback(@RequestParam("msg_signature") String msgSignature,@RequestParam("timestamp") String timestamp,@RequestParam("nonce") String nonce,@RequestParam("echostr") String echostr) {logger.info("收到數據回調驗證請求: signature={}, timestamp={}, nonce={}, echostr={}",msgSignature, timestamp, nonce, echostr);try {WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, encodingAESKey, corpid);String plainText = wxcpt.VerifyURL(msgSignature, timestamp, nonce, echostr);logger.info("驗證成功,明文: {}", plainText);return plainText;} catch (Exception e) {logger.error("驗證失敗", e);return "fail";}}/*** 專門處理suite_ticket推送(數據回調)*/@PostMapping(value = "/data", produces = "text/plain;charset=UTF-8")public String handleDataCallback(@RequestParam("msg_signature") String signature,@RequestParam("timestamp") String timestamp,@RequestParam("nonce") String nonce,@RequestBody String encryptedMsg) {try {// 1. 解密消息WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, encodingAESKey, corpid);String plainText = wxcpt.DecryptMsg(signature, timestamp, nonce, encryptedMsg);// 2. 解析XMLMap<String, String> message = parseXml(plainText);if ("suite_ticket".equals(message.get("Event"))) {String suiteTicket = message.get("SuiteTicket");String suiteId = message.get("SuiteId");// 3. 保存ticket(示例代碼)saveSuiteTicket(suiteId, suiteTicket);logger.info("成功更新suite_ticket: {}", suiteTicket);}// 4. 關鍵點:返回加密的success!!!String encryptedSuccess = wxcpt.EncryptMsg("success", timestamp, nonce);return encryptedSuccess;} catch (Exception e) {logger.error("處理suite_ticket失敗", e);return "fail";}}private void saveSuiteTicket(String suiteId, String suiteTicket) {// 實現你的存儲邏輯,例如:// redisTemplate.opsForValue().set("wxwork:ticket:"+suiteId, suiteTicket, 20*60);System.out.println("suiteId: " + suiteId + "suiteTicket:" + suiteTicket);}/*** 指令回調驗證接口(GET請求)* 企業微信首次配置時會觸發此驗證*/@GetMapping("/cmd")public String validateCmdCallback(@RequestParam("msg_signature") String msgSignature,@RequestParam("timestamp") String timestamp,@RequestParam("nonce") String nonce,@RequestParam("echostr") String echostr) {logger.info("[指令回調] 驗證請求 - signature:{}, timestamp:{}, nonce:{}, echostr:{}",msgSignature, timestamp, nonce, echostr);try {WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, encodingAESKey, suiteId);String plainText = wxcpt.VerifyURL(msgSignature, timestamp, nonce, echostr);logger.info("[指令回調] 驗證成功,明文: {}", plainText);
//            return plainText; // 必須返回解密后的明文return "success";} catch (Exception e) {logger.error("[指令回調] 驗證失敗", e);return "fail";}}/*** 指令回調處理接口(POST請求)* 接收:授權成功、取消授權、變更授權等指令*/@PostMapping(value = "/cmd", produces = "application/xml;charset=UTF-8")public String handleCmdCallback(@RequestParam("msg_signature") String msgSignature,@RequestParam("timestamp") String timestamp,@RequestParam("nonce") String nonce,@RequestBody String encryptedMsg) {logger.info("[指令回調] 收到消息 - signature:{}, timestamp:{}, nonce:{}",msgSignature, timestamp, nonce);try {// 1. 解密消息WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, encodingAESKey, suiteId);String plainText = wxcpt.DecryptMsg(msgSignature, timestamp, nonce, encryptedMsg);logger.info("[指令回調] 解密后消息: {}", plainText);// 2. 解析XML(復用數據回調的解析方法)Map<String, String> message = parseXml(plainText);String infoType = message.get("InfoType");String authCorpId = message.get("AuthCorpId");String SuiteTicket = message.get("SuiteTicket");saveSuiteTicket(authCorpId, SuiteTicket);// 3. 處理不同類型的指令switch (infoType) {case "suite_auth":// 授權成功事件(含臨時授權碼)String authCode = message.get("AuthCode");logger.info("[指令回調] 企業授權成功: corpId={}, authCode={}", authCorpId, authCode);// TODO: 調用企業微信API換取永久授權碼break;case "change_auth":// 授權變更事件(如權限集變更)String state = message.get("State");logger.info("[指令回調] 授權變更: corpId={}, state={}", authCorpId, state);break;case "cancel_auth":// 取消授權事件logger.info("[指令回調] 取消授權: corpId={}", authCorpId);// TODO: 清理該企業相關數據break;default:logger.warn("[指令回調] 未知指令類型: {}", infoType);}// 4. 必須返回加密的success
//            return wxcpt.EncryptMsg("success", timestamp, nonce);return "success";} catch (Exception e) {logger.error("[指令回調] 處理失敗", e);return "fail";}}/*** 解析XML到Map*/private Map<String, String> parseXml(String xml) throws DocumentException {Map<String, String> result = new HashMap<>();Document document = DocumentHelper.parseText(xml);Element root = document.getRootElement();for (Iterator<Element> it = root.elementIterator(); it.hasNext(); ) {Element element = it.next();result.put(element.getName(), element.getText());}return result;}
}

yml

server:port: 8080servlet:context-path: /wxwork:token: 你的Token # 在企業微信后臺設置的回調TokenencodingAESKey: 你的EncodingAESKey # 在企業微信后臺設置的EncodingAESKeycorpId: 你的CorpID # 企業微信服務商的CorpIDsuiteId: 你的suiteId # 第三方應用id

踩坑:企業微信文檔寫的太爛了,而且坑也特別多,企業微信指令回調用的不是corpid,而是?

suiteId!!!!!!!!!!!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/91265.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/91265.shtml
英文地址,請注明出處:http://en.pswp.cn/web/91265.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

LazyLLM教程 | 第2講:10分鐘上手一個最小可用RAG系統

貼心小梗概本文將介紹使用LazyLLM搭建最基礎的RAG的流程。首先介紹使用LazyLLM搭建RAG系統的必要環境配置&#xff0c;然后簡單回顧RAG的基本流程&#xff0c;接下來分別介紹RAG中文檔加載、檢索組件、生成組件三個關鍵部分的參數和基本使用方法&#xff0c;最后利用LazyLLM實現…

android9-PMS-常見問題及分析步驟

以下是基于 Android 9 的 Package Manager Service (PMS) 常見問題及分析步驟&#xff0c;結合系統原理與優化實踐整理&#xff1a; &#x1f527; 一、開機性能問題 現象 開機時間隨應用增多顯著延長&#xff0c;卡在“正在啟動應用”階段。 分析步驟 ① 確認掃描階段耗時adb…

生成模型實戰 | GLOW詳解與實現

生成模型實戰 | GLOW詳解與實現0. 前言1. 歸一化流模型1.1 歸一化流與變換公式1.2 RealNVP 的通道翻轉2. GLOW 架構2.1 ActNorm2.2 可逆 11 卷積2.3 仿射耦合層2.4 多尺度架構3. 使用 PyTorch 實現 GLOW3.1 數據處理3.2 模型構建3.3 模型訓練0. 前言 GLOW (Generative Flow) 是…

行業案例:杰和科技為智慧教育構建數字化硬件底座

清晨8點10分&#xff0c;深圳某學生踏入校園&#xff0c;智慧門閘識別身份&#xff0c;并同步發給家長&#xff1b;走廊里的“智慧班牌”向他們展示今日的課表&#xff1b;課堂上&#xff0c;教室前方的多媒體播放器里&#xff0c;老師引導學生學習“居民樓消防隱患”知識&…

Redis與MySQL數據同步:從“雙寫一致性”到實戰方案

Redis與MySQL數據同步&#xff1a;從“雙寫一致性”到實戰方案 在分布式系統中&#xff0c;Redis作為高性能緩存被廣泛使用——它能將熱點數據從MySQL中“搬運”到內存&#xff0c;大幅降低數據庫壓力、提升接口響應速度。但隨之而來的核心問題是&#xff1a;當MySQL數據更新時…

Java源碼構建智能名片小程序

在移動互聯網時代&#xff0c;紙質名片的局限性日益凸顯——信息更新不便、客戶管理困難、營銷效果難以追蹤。智能電子名片小程序以其便捷、高效、智能的特點&#xff0c;正成為商務人士的"數字營銷門戶"。而基于Java技術棧開發的智能名片系統&#xff0c;憑借其穩定…

如何在短時間內顯著提升3D效果圖渲染速度?

在建筑設計、游戲開發、影視制作等行業&#xff0c;3D效果圖的渲染速度是項目進度與效率的關鍵瓶頸。面對復雜場景時&#xff0c;漫長的渲染等待尤為突出。要在保證質量的前提下大幅縮短渲染時間&#xff0c;以下優化策略至關重要&#xff1a; 1. 升級硬件配置&#xff1a;渲染…

配置daemon.json使得 Docker 容器能夠使用服務器GPU【驗證成功】

&#x1f947; 版權: 本文由【墨理學AI】原創首發、各位讀者大大、敬請查閱、感謝三連 文章目錄&#x1f50d;你遇到的錯誤&#xff1a;&#x1f50d; 根本原因? 解決方案&#xff1a;正確安裝 NVIDIA Container Toolkit? 第一步&#xff1a;卸載舊版本&#xff08;如果存在&…

Linux 系統進程管理與計劃任務詳解

Linux 系統進程管理與計劃任務詳解 一、程序與進程的基本概念 程序&#xff1a;保存在外部存儲介質中的可執行機器代碼和數據的靜態集合。進程&#xff1a;在CPU及內存中處于動態執行狀態的計算機程序。關系&#xff1a;每個程序啟動后&#xff0c;可創建一個或多個進程。 二、…

【圖像處理】直方圖均衡化c++實現

直方圖均衡化是一種通過調整圖像像素灰度值分布&#xff0c;來增強圖像對比度的經典數字圖像處理技術。其核心在于將原始圖像的灰度直方圖從集中的某個區間“拉伸”或“均衡”到更廣泛的區間&#xff0c;讓圖像的明暗細節更清晰&#xff0c;關鍵在于利用累積分布函數實現灰度值…

Web前端實戰:Vue工程化+ElementPlus

1.Vue工程化 1.1介紹 模塊化&#xff1a;將js和css等&#xff0c;做成一個個可復用模塊組件化&#xff1a;我們將UI組件&#xff0c;css樣式&#xff0c;js行為封裝成一個個的組件&#xff0c;便于管理規范化&#xff1a;我們提供一套標準的規范的目錄接口和編碼規范&#xff0…

ECMAScript2021(ES12)新特性

概述 ECMAScript2021于2021年6月正式發布&#xff0c; 本文會介紹ECMAScript2021(ES12)&#xff0c;即ECMAScript的第12個版本的新特性。 以下摘自官網&#xff1a;ecma-262 ECMAScript 2021, the 12th edition, introduced the replaceAll method for Strings; Promise.any,…

Tlias 案例-整體布局(前端)

開發流程前端開發和后端開發是一樣的&#xff0c;都需要閱讀接口文檔。 準備工作&#xff1a; 1&#xff1a;導入項目中準備的基礎過程到 VsCode。2&#xff1a;啟動前端項目&#xff0c;訪問該項目3&#xff1a;熟悉一下基本的布局<script setup></script><tem…

三十二、【Linux網站服務器】搭建httpd服務器演示虛擬主機配置、網頁重定向功能

httpd服務器功能演示一、虛擬主機配置虛擬主機技術全景虛擬主機目錄規范1. 基于端口的虛擬主機&#xff08;8080/8081&#xff09;2. 基于IP的虛擬主機&#xff08;192.168.1.100/192.168.1.101&#xff09;3. 基于域名的虛擬主機&#xff08;site1.com/site2.com&#xff09;二…

串行化:MYSQL事務隔離級別中的終極防護

在現代應用程序中&#xff0c;數據的一致性和可靠性至關重要。想象一下&#xff0c;如果在一個銀行系統中&#xff0c;兩個用戶同時試圖轉賬到同一個賬戶&#xff0c;最終的數據結果可能會出乎意料。為了避免這種情況&#xff0c;MYSQL提供了不同的事務隔離級別&#xff0c;其中…

RAG:檢索增強生成的范式演進、技術突破與前沿挑戰

1 核心定義與原始論文 RAG&#xff08;Retrieval-Augmented Generation&#xff09;由Facebook AI Research團隊于2020年提出&#xff0c;核心思想是將參數化記憶&#xff08;預訓練語言模型&#xff09;與非參數化記憶&#xff08;外部知識庫檢索&#xff09;結合&#xff0c…

2024年藍橋杯Scratch10月圖形化stema選拔賽真題——旋轉的圖形

旋轉的圖形編程實現旋轉的圖形。具體要求1&#xff09;點擊綠旗&#xff0c;在舞臺上出現滑桿形式的變量 r&#xff0c;取值范圍為-1、0、1&#xff0c;默認值為 0&#xff0c;如圖所示&#xff1b;2&#xff09;1秒后&#xff0c;在舞臺上繪制出一個紅色正方形&#xff08;邊長…

【音視頻】WebRTC 開發環境搭建-Web端

一、開發環境搭建 1.1 安裝vscode 下載VSCode&#xff1a;https://code.visualstudio.com/&#xff0c;下載后主要用于開發Web前端頁面&#xff0c;編寫前端代碼 安裝完成后下載Live Server插件&#xff0c;用于本地開發&#xff0c;實時加載前端頁面 1.1.1 前端代碼測試 下…

力扣54:螺旋矩陣

力扣54:螺旋矩陣題目思路代碼題目 給你一個 m 行 n 列的矩陣 matrix &#xff0c;請按照 順時針螺旋順序 &#xff0c;返回矩陣中的所有元素。 思路 思路很簡單創建一個二維數組然后按照箭頭所示的順序一層一層的給二維數組相應的位置賦值即可。難點是我們是一層一層的賦值…

【CSS】設置表格表頭固定

1.設置thead樣式在thead元素中增加樣式&#xff1a;position: sticky;top: 0;2.設置table樣式在table元素中增加樣式&#xff1a;border-collapse: separate; /* 分離邊框模式 */ border-spacing: 0;3.設置表頭偽元素樣式增加樣式&#xff1a;th::after {content: ;position: a…