企业微信通讯录回调模板-XML转JSON-让回调不再难!

2023-08-01 10:28:08 浏览数 (1)

我们在开发企业内部应用时,需要实现内部应用和企业微信的双向同步,即互联互通。 举个例子 同步一:企业内部OA系统在修改内部通讯录时,可以同步企业微信(直接调API接口即可) 同步二:在企业微信后台修改通讯录时,反馈给内部OA系统(本文讲解)


总的来说,实现通讯录回调的流程分为四步:

第一步:管理员在企业微信在后台修改通讯录信息(除了API接口修改之外的都算)

第二步:企业微信修改通讯录后,以XML的方式,向企业内部系统发送修改详情

第三步:企业内部系统收到XML信息后,解密信息

第四步:对于解密后的信息,修改企业内部系统的通讯录


具体实现

一、导包

解密工具下载地址

下载企业微信提供的解密工具,放到自己的项目内。

注意com包不能改名字

如果1.9版本的包无法通过编译,可以使用1.4的包

代码语言:javascript复制
<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.4</version>
</dependency>

二、验证URL

在企业微信管理后台,配置URL

test方法为验证URL的模板,拿来即用

ParameterSettings是我放固定字段的类,相应参数替换即可

代码语言:javascript复制
import com.qq.weixin.mp.aes.AesException;
import com.qq.weixin.mp.aes.WXBizMsgCrypt;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;

/**
     * 验证URL
     * @param request
     * @param response
     * @throws Exception
     */
    public void test(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 微信加密签名
        String msg_signature = request.getParameter("msg_signature");
        // 时间戳
        String timestamp = request.getParameter("timestamp");
        // 随机数
        String nonce = request.getParameter("nonce");
        // 随机字符串
        String echostr = request.getParameter("echostr");

        System.out.println("request="   request.getRequestURL());

        PrintWriter out = response.getWriter();
        // 通过检验msg_signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败
        String result = null;
        try {
            WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(ParameterSettings.YHHD_TOKEN, ParameterSettings.YHHD_EAK, ParameterSettings.AS_CORPID);
            result = wxcpt.VerifyURL(msg_signature, timestamp, nonce, echostr);
        } catch (AesException e) {
            e.printStackTrace();
        }
        if (result == null) {
            result = ParameterSettings.YHHD_TOKEN;
        }
        out.print(result);
        out.close();
        out = null;
    }

原文CSDN链接:https://cloud.tencent.com/developer/article/2306868


三、解密

验证URL完成后,将该URL的接口方法替代成下方callBack方法的代码

当企业微信发送回调通知时,该方法会实现接收

该模板会将XML格式的数据转换为标准JSON,方便后续处理

JSON用了阿里的fastjson,maven依赖如下:

代码语言:javascript复制
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.9</version>
</dependency>
代码语言:javascript复制
import com.alibaba.fastjson.JSONObject;
import com.qq.weixin.mp.aes.AesException;
import com.qq.weixin.mp.aes.WXBizMsgCrypt;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.ServletInputStream;
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;


    /**
     * 企业微信发送XML到这个方法
     * @param request
     * @param response
     * @throws Exception
     */
    @RequestMapping(value = "/callBack", method = RequestMethod.POST)
    public void callBack(HttpServletRequest request, HttpServletResponse response) throws Exception {
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        String respMessage = "";
        respMessage=getDecryptMsg(request);
        //进行回调处理
        dealCallBackEvent(respMessage);
        PrintWriter out = response.getWriter();
        out.print(respMessage);
        out.close();
    }

    /**
     * 解密XML数据转换JSON
     * @param request
     * @return
     */
    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(ParameterSettings.YHHD_TOKEN, ParameterSettings.YHHD_EAK, ParameterSettings.YH_CORPID);
            result = wxcpt.DecryptMsg(msg_signature, timestamp, nonce, postData);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (AesException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 对解密后的数据进行业务逻辑处理
     * @param text
     */
    private void dealCallBackEvent(String text) {
        JSONObject json = XmlTool.documentToJSONObject(text);
        String event = json.getString("Event");
        String changeType = json.getString("ChangeType");
        if (event.equals("change_contact")) {
            if (changeType.equals("create_user")) { // 创建用户回调
                String name = json.getString("Name");
                String userID = json.getString("UserID");
                String departmentStr = json.getString("Department"); // 部门为逗号分开的字符串
                String[] departmentList = departmentStr.split(",");
                String corpID = json.getString("ToUserName");
                String mobile = json.getString("Mobile");
                if (corpID.equals(ParameterSettings.YH_CORPID)) { // 替换企业ID
                    // 业务逻辑代码
                }
            }
        }
    }

核心代码到此结束,以下是其他所有代码

代码语言:javascript复制
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;
    }
}
代码语言:javascript复制
import lombok.Data;
import java.util.List;

@Data
public class Items {
    List<Item> item;
}
代码语言:javascript复制
import lombok.Data;

import java.util.List;

@Data
public class Item {
    private String type;

    private List<TextValue> text;

    private String name;

    private List<WebValue> web;
}
代码语言:javascript复制
import lombok.Data;

import java.util.List;

@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;
}
代码语言:javascript复制
import lombok.Data;

@Data
public class TextValue {

    private String Value;
}
代码语言:javascript复制
import lombok.Data;

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

0 人点赞