企业微信回调-通讯录改变回调

2023-11-17

https://work.weixin.qq.com/api/doc/90000/90135/90966

先配置url,token,encodingAESKey


import com.ichangtou.common.util.AesException;
import com.ichangtou.common.util.WXBizMsgCrypt;
import com.ichangtou.service.WXCallBackService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;

@WebServlet(name = "CallbackServlet", urlPatterns = "/callbackServlet")  //标记为servlet,以便启动器扫描。
@Slf4j
public class CallbackServlet extends HttpServlet {

   

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        // 微信加密签名
        String msg_signature = request.getParameter("msg_signature");
        // 时间戳
        String timestamp = request.getParameter("timestamp");
        // 随机数
        String nonce = request.getParameter("nonce");
        // 随机字符串
        String echostr = request.getParameter("echostr");

        log.info("request=" + request.getRequestURL());
        log.info("请求的数据为,msg_signature:{},timestamp:{},nonce:{},echostr:{}",msg_signature,timestamp ,nonce,echostr);
        PrintWriter out = response.getWriter();
        // 通过检验msg_signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败
        String result = null;
        try {
            WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, encodingAESKey, corpid);
            result = wxcpt.VerifyURL(msg_signature, timestamp, nonce, echostr);
        } catch (AesException e) {
            e.printStackTrace();
        }
        if (result == null) {
            result = "ok";
        }
        log.info("result=:{}",result);
        out.print(result);
        out.close();
    }


    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.将请求、响应的编码均设置为UTF-8(防止中文乱码)
        log.info("进入post方法" + request.getRequestURL());
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        String respMessage=getDecryptMsg(request);
        //进行回调处理
        wXCallBackService.dealCallBackEvent(respMessage);
        log.info("respMessage=:{}",respMessage);
        PrintWriter out = response.getWriter();
        out.print(respMessage);
        out.close();
    }

    public String getDecryptMsg(HttpServletRequest request) {
        String postData="";   // 密文,对应POST请求的数据
        String result="";     // 明文,解密之后的结果
        String msg_signature = request.getParameter("msg_signature"); // 微信加密签名
        String timestamp = request.getParameter("timestamp");   // 时间戳
        String nonce = request.getParameter("nonce");          // 随机数
        try {
            //1.获取加密的请求消息:使用输入流获得加密请求消息postData
            ServletInputStream in = request.getInputStream();
            BufferedReader reader =new BufferedReader(new InputStreamReader(in));

            String tempStr="";   //作为输出字符串的临时串,用于判断是否读取完毕
            while(null!=(tempStr=reader.readLine())){
                postData+=tempStr;
            }
            //2.获取消息明文:对加密的请求消息进行解密获得明文
            WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, encodingAESKey, corpid);
            result = wxcpt.DecryptMsg(msg_signature, timestamp, nonce, postData);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (AesException e) {
            e.printStackTrace();
        }

        return result;
    }

}


@Slf4j
@Service
public class WXCallBackServiceImpl implements WXCallBackService {

	@Autowired
	private WXAddressBookService wXAddressBookService;

	@Override
	public void dealCallBackEvent(String text) {
		JSONObject json= XmlTool.documentToJSONObject(text);
		String event=json.getString("Event");
		String changeType=json.getString("ChangeType");
		AddressBookEventEnum eventEnum=AddressBookEventEnum.getAddressBookEvent(event,changeType);
		if(eventEnum!=null){
			Class tc=eventEnum.getT();
			if(tc.isAssignableFrom(Member.class)){
				Member member=JSONObject.parseObject(json.toJSONString(), Member.class);
				wXAddressBookService.dealAddressEvent(member);
			}
		}
	}
}

 下面是xml转json的工具类

import java.util.List;
 
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
 
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
 
public class XmlTool {
	/**
     * String 转 org.dom4j.Document
     * @param xml
     * @return
     * @throws DocumentException
     */
    public static Document strToDocument(String xml){
        try {
        	//加上xml标签是为了获取最外层的标签,如果不需要可以去掉
			return DocumentHelper.parseText(xml);
		} catch (DocumentException e) {
			return null;
		}
    }
 
    /**
     * org.dom4j.Document 转  com.alibaba.fastjson.JSONObject
     * @param xml
     * @return
     * @throws DocumentException
     */
    public static JSONObject documentToJSONObject(String xml){
		return elementToJSONObject(strToDocument(xml).getRootElement());
    }
 
    /**
     * org.dom4j.Element 转  com.alibaba.fastjson.JSONObject
     * @param node
     * @return
     */
    public static JSONObject elementToJSONObject(Element node) {
        JSONObject result = new JSONObject();
        // 当前节点的名称、文本内容和属性
        List<Attribute> listAttr = node.attributes();// 当前节点的所有属性的list
        for (Attribute attr : listAttr) {// 遍历当前节点的所有属性
            result.put(attr.getName(), attr.getValue());
        }
        // 递归遍历当前节点所有的子节点
        List<Element> listElement = node.elements();// 所有一级子节点的list
        if (!listElement.isEmpty()) {
            for (Element e : listElement) {// 遍历所有一级子节点
                if (e.attributes().isEmpty() && e.elements().isEmpty()) // 判断一级节点是否有属性和子节点
                    result.put(e.getName(), e.getTextTrim());// 沒有则将当前节点作为上级节点的属性对待
                else {
                    if (!result.containsKey(e.getName())) // 判断父节点是否存在该一级节点名称的属性
                        result.put(e.getName(), new JSONArray());// 没有则创建
                    ((JSONArray) result.get(e.getName())).add(elementToJSONObject(e));// 将该一级节点放入该节点名称的属性对应的值中
                }
            }
        }
        return result;
    }
}
@Data
public class Member {
    private String toUserName;
    private String fromUserName;
    private String createTime;
    private String msgType;
    private String event;
    private String changeType;
    private String userID;
    private String newUserID;
    private String name;
    private String department;
    private String isLeaderInDept;
    private String position;
    private String mobile;
    private String gender;
    private String email;
    private String status;
    private String avatar;
    private String alias;
    private String telephone;
    private String address;
    private List<Items> extAttr;
}


@Data
public class Items {

    List<Item> item;

}


@Data
public class Item {
    private String type;

    private List<TextValue> text;

    private String name;

    private List<WebValue> web;

}


@Data
public class TextValue {

    private String Value;
}


@Data
public class WebValue {
    private String Title;
    private String Url;
}

https://work.weixin.qq.com/api/doc/90000/90138/90307

注意:企业微信提供的WXBizMsgCrypt类中,

Base64 要使用org.apache.commons.codec.binary.Base64

 

       <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.9</version>
        </dependency>

        <dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>1.6.1</version>
        </dependency>

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

企业微信回调-通讯录改变回调 的相关文章

  • 我们可以在 XML 文件中使用数字作为文本节点吗?

    我们可以在 XML 文件中使用数字作为文本节点吗 例如 lt 2 gt
  • 如何在Spring的applicationContext.xml中指定默认范围来请求范围?

    我想让所有 bean 请求默认作用域 但是 Spring 文档说默认作用域是 Singleton 第 3 4 1 和 3 4 2 节http static springsource org spring docs 2 5 x referen
  • 如何正确配置Tomcat SSLHostConfig?

    我正在按照本教程在 tomcat 中启用 ssl https medium com raupach how to install lets encrypt with tomcat 3db8a469e3d2 https medium com
  • 如何在具有动态列的表中插入值 Jdbc/Mysql

    我想在具有动态列的表中添加值 我设法创建一个包含动态列的表 但我不知道如何插入数据 Create Table sql CREATE TABLE MyDB myTable level INTEGER 255 int columnNumber
  • 无法从后台服务通过 WiFi 访问互联网

    我将直接介绍我发现的一些事实 数据 如果您遇到 解决了类似的问题 请帮助我 我每 5 分钟向服务器发送一次数据 除非用户在服务器的帮助下手动将其关闭 wakeful broadcast receiver通过一个intent service
  • Maven 多模块项目结构问题

    自从过去几周构建我的 Maven 多模块项目以来 这是我的一次有趣的经历 当我决定使用 Maven 进行构建生命周期管理时 我有几个原因希望选择 Maven A 大多数开发团队都是分开的 这样每个团队都可以在项目中的单独模块上工作 例如团队
  • 如何模拟一个方面

    我目前正在使用aspectj 开发一些监控工具 因为这个工具应该是技术独立的 尽可能 所以我没有使用 Spring 进行注入 但我希望我的方面能够经过单元测试 方面示例 Aspect public class ClassLoadAspect
  • 如何使用 Java 原生接口从 Java 调用 Go 函数?

    可以通过以下方式调用 C 方法JNA https en wikipedia org wiki Java Native AccessJava 中的接口 如何使用 Go 实现相同的功能 package main import fmt impor
  • 源服务器未找到目标资源的当前表示或不愿意透露该表示存在

    web xml
  • 为基于架构的 XML 文件创建 WPF 编辑器

    这是场景 我们的服务器产品之一使用大型 XML 配置文件 该文件的布局相当好 并且针对 XSD 文件进行了验证 现在是时候构建一个配置 GUI 来维护这个文件了 我想深入研究 WPF 来完成它 我可以为每个配置部分布置一个单独的表单 每次向
  • 字节码和位码有什么区别[重复]

    这个问题在这里已经有答案了 可能的重复 LLVM 和 java 字节码有什么区别 https stackoverflow com questions 454720 what are the differences between llvm
  • 哪种 Java DOM 包装器是最好或最受欢迎的? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 如何将 Xml 文件转换为文本文件 [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我有大约 8000 个 xml 文件需要转换为文本文件 文本文件必须包含 xml 文件的标题 描述和关键字 不含标签 并删除其他元素和
  • 用 Java 创建迷宫求解算法

    我被分配了用 Java 创建迷宫求解器的任务 这是任务 Write an application that finds a path through a maze The maze should be read from a file A
  • 如何计算文件中单词的长度?爪哇

    我正在尝试编写一个代码来计算文件中特定长度的单词数 例如 How are you 会打印 Proportion of 3 letter words 100 3 words 我想计算长度为 1 2 3 4 5 6 7 8 9 10 11 12
  • 将字符串中的字符向左移动

    我是 Stack Overflow 的新手 有一道编程课的实验室问题一直困扰着我 该问题要求我们将字符串 s 的元素向左移动 k 次 例如 如果输入是 Hello World 和3 它将输出 lo WorldHel 对于非常大的 k 值 它
  • 防止 Firebase 中的待处理写入事务不起作用

    我的目标是在单击按钮时将名称插入 Cloud Firestore 中 但如果用户未连接到互联网 我不希望保存处于挂起状态 我不喜欢 Firebase 保存待处理写入的行为 即使互联网连接已恢复 我研究发现Firebase 开发人员建议使用事
  • JDK 7 的快速调试/调试构建

    我正在寻找 JDK 的调试 或者我猜他们称之为快速调试构建 以启用在运行时生成的打印程序集以及查找性能问题时所需的其他诊断 就目前情况而言 我似乎找不到可以直接使用的 现成的 快速调试构建二进制包 有人可以帮我提供下载链接 或者至少提供有关
  • 监控 Java 应用程序上的锁争用

    我正在尝试创建一个小基准 在 Groovy 中 以显示几个同步方法上的高线程争用 当监控自愿上下文切换时 应该会出现高争用 在 Linux 中 这可以通过 pidstat 来实现 程序如下 class Res private int n s
  • 将隐藏(生物识别)数据附加到 pdf 上的数字签名

    我想知道是否可以使用 iText 我用于签名 或 Java 中的其他工具在 pdf 上添加生物识别数据 我会更好地解释一下 在手写板上签名时 我会收集签名信息 例如笔压 签名速度等 我想将这些信息 java中的变量 与pdf上的签名一起存储

随机推荐

  • 基于布谷鸟算法结合灰狼算法求解最优目标

    基于布谷鸟算法结合灰狼算法求解最优目标 在本文中 我们将介绍如何使用布谷鸟算法和灰狼算法的组合来求解最优目标问题 我们将提供相应的MATLAB代码 以便读者可以直接实现和测试这种算法组合的效果 布谷鸟算法 Cuckoo Search Alg
  • 使用Git Bash从Git上下载代码到本地以及上传代码到码云Git

    前提是已经安装了GitBash 这个稍后再出教程 1 新建一个目录 存放下载下来的项目 我在D盘新建了一个 gitspace 文件夹 用来存放下载下来的项目 2 进入刚刚新建的文件夹 即进入 gitspace 点击鼠标右键 选择 Git B
  • 2021年国家平均工资出炉,你又被平均了吗?

    近期 国家统计局发布2021全国平均薪资 IT业年平均工资突破20万位于榜首 分行业门类看 IT行业年平均工资私营 非私营均位列第一 年平均工资最高的3个行业分别是信息传输 软件和信息技术服务业201506元 科学研究和技术服务业15177
  • Django基础入门⑧:Django路由详细讲解

    Django基础入门 Django路由 Django路由 路由分发函数 反向解析 反向解析应用 使用url标签实现反向解析 reverse 函数实现反向解析 reverse 函数简析 命名空间namespace 个人简介 以山河作礼 Pyt
  • mysql常用日期时间/数值函数

    author skate time 2013 05 16 1 日期时间函数 时间转化秒函数 time to sec mysql gt select time to sec 01 01 01 time to sec 01 01 01 3661
  • 将数组以逗号拼接_javascript将数组拼接成一个字符串

    这里记录下在JavaScript中如何将数组拼接成一个字符串 所谓的将数组拼接成一个字符串 意思就是将数组中的元素逐个拼接到一个字符串中 并加以特定的分隔符 在JavaScript中可以有两种方式 一种是Array对象提供的join 方法
  • Mysql-表关系多对多设计

    多对多 如 订单 和 商品 一个商品对应多个订单 一个订单包含多个商品 实现方式 建立第三张中间表 中间表至少包含两个外键 分别关联两方主键 DROP TABLE tb order DROP TABLE tb goods DROP TABL
  • C++ 引用

    引用变量是一个别名 也就是说 它是某个已存在变量的另一个名字 一旦把引用初始化为某个变量 就可以使用该引用名称或变量名称来指向变量 引用和指针 引用很容易与指针混淆 它们之间有三个主要的不同 不存在空引用 引用必须连接到一块合法的内存 一旦
  • MinGW-w64下载文件失败the file has been downloaded incorrectly

    文章目录 前言 必读 1 问题背景 2 报错原因 3 解决方案 前言 必读 笔者强烈推荐使用 linux平台 搭建C 环境所需的东西 如果是用windows平台 则会出现很多小问题 或者即使安装好了 程序跑起来的时候仍会有问题 如果是单纯想
  • The Raft Group [naming_instance_metadata] did not find the Leader node;caused: The Raft Group

    1 异常信息 caused errCode 500 errMsg do metadata operation failed caused com alibaba nacos consistency exception Consistency
  • 安装MySQL(无管理员权限)

    Install MySQL without administrator permission Step 1 Download https cdn mysql com Downloads MySQL 5 7 mysql 5 7 24 win3
  • “echo 0 > /proc/sys/kernel/hung_task_timeout_secs“ disables this message

    现象 主机无缘无故死机 主机上服务无响应 日志出现大量 echo 0 gt proc sys kernel hung task timeout secs disables this message 日志输出信息 分析 echo 0 gt p
  • Future异步

    Future异步是Java中常用的异步编程方式之一 它能够在代码执行过程中返回一个代表未来结果的Future对象 使得程序能够在等待结果的同时继续执行其他操作 本文将从Future异步的定义 使用方法和优缺点等方面对其进行详细介绍 一 Fu
  • Qt信号发送过快,槽函数处理不过来解决方法

    问题 跨线程使用信号与槽连接 信号的发送时间间隔小于槽函数处理的时间间隔 造成的问题 子线程下的槽函数 用sleep来模拟槽函数的耗时操作 void MyThread myTimeout qDebug lt lt test QThread
  • 矩阵转置代码,速度优化

    今天心血来潮 想写个CPU版本的矩阵转置代码 过几天写GPU版本的 按照我的想法 就是以下几种方式 1 gt 整块矩阵转置 横读纵写或纵读横写 2 gt 将矩阵分成固定大小的block block与block可以分成横读纵写或纵读横写 而b
  • const修饰成员函数

    常函数 成员函数后加const后 我们称这个函数为常函数 在常函数内不可以修改成员的属性 成员属性声明时加关键字mutable后 在常函数中依然可以修改 常对象 声明对象前加const称该对象为常对象 常对象不能在类外修改其成员属性 但可以
  • K8s(Kubernetes)工具

    文章目录 Kubernetes简介 kubernetes背景和历史 kubernetes特点 kubernetes相关概念 基本对象 Pod Service Volume 持久存储卷 Persistent Volume PV 和持久存储卷声
  • linux怎么用python运维命令_运维笔记--linux环境提示python: command not found

    场景描述 新部署的容器环境 终端执行python命令 提示没有该命令 从报错异常可以看出 可能是python环境未安装 分析思路 检查python路径 方式一 type a python 方式二 ls l usr bin python ls
  • 【python总结】python学习框架梳理

    目录 基础 注释与变量名等基本规则 关键字 操作符 数字 流程控制 序列 文本序列 字符串 二进制序列 字节 列表 元组 映射 字典 集合 函数 面向对象编程 错误和异常 模块 数据结构与算法 数组 字符串 链表 二分查找 排序 栈 队列
  • 企业微信回调-通讯录改变回调

    https work weixin qq com api doc 90000 90135 90966 先配置url token encodingAESKey import com ichangtou common util AesExcep