背景
客户提了关于对接企业微信【审批】功能的需求,具体需求包括:
1、当企业微信审批流程到达某个节点后,能将审批信息推送到我们系统,或者我们系统能够拉取某个流程的信息;
2、能在审批流程中嵌套一个评价节点,跳转我们系统的评价页面。
1 调研企业微信是否支持
根据这篇博文,可知企业微信支持 审批回调 ,这个在官方文档中也可以找到。所以1中 当企业微信审批流程到达某个节点后,能将审批信息推送到我们系统是可以做到的。
对于2中的需求,经调研,发现企业微信支持定制审批流程的 模版 ,可以在 模版 中加上一个 说明文字 的控件,在控件中插入链接,然后靠用户的自觉性,在某个节点点击链接去评价,这个实现客户也是认可的。
2 流程梳理
审批回调 自然需要配置回调接口,企业微信的逻辑是先在企业微信中 自建 一个应用,然后给这个自建应用进行 接收消息服务器配置 ,这个 接收消息服务器配置 就是回调的url,然后在 审批 中配置 开启回调通知的模版 和 可调用接口的应用 ,这样开启了企业微信审批申请状态变化回调。
2.1 自建应用
在这里先讲一下如何创建一个企业用于自己开发测试,移动端比较简单,左侧点击图标新建即可。
首先在PC端的企业微信上进入工作台
接着随便点击一个应用,比如审批,点击右上角的图标前往管理后台
然后就会打开浏览器,点击顶部的 应用管理 菜单,可以看大下面有 创建应用 的选项
点击创建,填入必填项,创建成功
接着就是配置应用中的一些信息,上面的这个 AgentId 是应用的ID,那个 Secret 是应用的凭证密钥,这个在获取企业微信access_token的时候需要
接下来往下拖,点击那个 API接收消息,我这里配置过了,显示的是已启用
可以看到这里有3个参数,下面2个是点击右边的 随机获取 按钮随机获取的,第1个参数URL,可以参考边上的获取帮助链接,这个是企业微信的验证URL,这里的实现放在2.2中
还需要配置 企业可信IP , 企业可信IP 是配置哪些IP可以通过API获取企业数据,比如审批流程信息
2.2 回调接口实现
这一节说明的是企业微信应用验证URL和回调接口的实现。
首先,需要下载企业微信的加解密库,选择XML版本,下面的代码依赖于这些。
点击查看代码
package com.springboot.demo.scheduled;import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.springboot.demo.aes.WXBizMsgCrypt;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringReader;/*** 企业微信审批状态变化回调** @author Lip* @since 2024-12-31*/
@Slf4j
@RestController
@RequestMapping("qy")
public class QywxCallbackController {@GetMapping(value = "/Callback")public void connect(HttpServletRequest request, HttpServletResponse response) {// 企业号将发送GET请求到填写的URL上,GET请求携带四个参数,企业在获取时需要做url_decode处理,否则会验证不成功// 微信加密签名String msgSignature = request.getParameter("msg_signature");// 时间戳String timestamp = request.getParameter("timestamp");// 随机数String nonce = request.getParameter("nonce");// 随机字符串String echoStr = request.getParameter("echostr");// 自建应用中生成的String contactsToken = "5AsIzFkiXMaa";String contactsEncodingAesKey = "GwJH5XOLPSmlTGJ2qKEcIy1k3wGg4rsFO51Df7woNsi";// 企业IDString corpId = "ww1f0eebf7e9d7c54d";// 回调key值String sEchoStr;try {PrintWriter out = response.getWriter();WXBizMsgCrypt wxCrypt = new WXBizMsgCrypt(contactsToken, contactsEncodingAesKey, corpId);sEchoStr = wxCrypt.VerifyURL(msgSignature, timestamp, nonce, echoStr);if (StringUtils.isBlank(sEchoStr)) {log.error("URL验证失败");}out.write(sEchoStr);out.flush();} catch (Exception e) {log.error("企业微信回调url验证错误", e);}}@PostMapping(value = "/Callback")public void acceptMessage(HttpServletRequest request) {System.out.println("————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————");log.info("企业微信信息交互");// 微信加密签名String sMsgSignature = request.getParameter("msg_signature");// 时间戳String sTimestamp = request.getParameter("timestamp");// 随机数String sNonce = request.getParameter("nonce");System.out.println("acceptMessage方法sMsgSignature: " + sMsgSignature);System.out.println("acceptMessage方法sTimestamp: " + sTimestamp);System.out.println("acceptMessage方法sNonce: " + sNonce);try {// 获取请求的输入流ServletInputStream inputStream = request.getInputStream();// 创建一个 StringBuilder 对象来存储请求内容StringBuilder xmlContent = new StringBuilder();// 使用 BufferedReader 读取输入流内容BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));String line;while ((line = reader.readLine()) != null) {xmlContent.append(line);}// 关闭输入流和读取器inputStream.close();reader.close();// 输出请求内容System.out.println("请求 XML 内容:" + xmlContent);String sReqData = xmlContent.toString();
// String sReqData = "<xml><ToUserName><![CDATA[wx5823bf96d3bd56c7]]></ToUserName><Encrypt><![CDATA[RypEvHKD8QQKFhvQ6QleEB4J58tiPdvo+rtK1I9qca6aM/wvqnLSV5zEPeusUiX5L5X/0lWfrf0QADHHhGd3QczcdCUpj911L3vg3W/sYYvuJTs3TUUkSUXxaccAS0qhxchrRYt66wiSpGLYL42aM6A8dTT+6k4aSknmPj48kzJs8qLjvd4Xgpue06DOdnLxAUHzM6+kDZ+HMZfJYuR+LtwGc2hgf5gsijff0ekUNXZiqATP7PF5mZxZ3Izoun1s4zG4LUMnvw2r+KqCKIw+3IQH03v+BCA9nMELNqbSf6tiWSrXJB3LAVGUcallcrw8V2t9EL4EhzJWrQUax5wLVMNS0+rUPA3k22Ncx4XXZS9o0MBH27Bo6BpNelZpS+/uh9KsNlY6bHCmJU9p8g7m3fVKn28H3KDYA5Pl/T8Z1ptDAVe0lXdQ2YoyyH2uyPIGHBZZIs2pDBS8R07+qN+E7Q==]]></Encrypt><AgentID><![CDATA[218]]></AgentID></xml>";String contactsToken = "5AsIzFkiXMaa";String contactsEncodingAesKey = "GwJH5XOLPSmlTGJ2qKEcIy1k3wGg4rsFO51Df7woNsi";String corpId = "ww1f0eebf7e9d7c54d";WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(contactsToken, contactsEncodingAesKey, corpId);String sMsg = wxcpt.DecryptMsg(sMsgSignature, sTimestamp, sNonce, sReqData);System.out.println("after decrypt msg: " + sMsg);// TODO: 解析出明文xml标签的内容进行处理DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();DocumentBuilder db = dbf.newDocumentBuilder();StringReader sr = new StringReader(sMsg);InputSource is = new InputSource(sr);Document document = db.parse(is);Element root = document.getDocumentElement();NodeList nodelist1 = root.getElementsByTagName("SpNo");// 获取审批编号String SpNo = nodelist1.item(0).getTextContent();System.out.println("审批编号为:" + SpNo);NodeList SpStatus_Node = root.getElementsByTagName("SpStatus");// 申请单状态:1-审批中;2-已通过;3-已驳回;4-已撤销;6-通过后撤销;7-已删除;10-已支付String SpStatus = SpStatus_Node.item(0).getTextContent();NodeList SpRecord_Node = root.getElementsByTagName("SpRecord");for (int i = 0; i < SpRecord_Node.getLength(); i++) {System.out.println("审批记录第" + (i + 1) + "个节点审批状态为:" + SpRecord_Node.item(i).getFirstChild().getTextContent());}} catch (Exception e) {log.error("企业微信消息交互错误", e);}}
}
这两个接口的路径是一样的,GET方法是验证接口,POST方法是回调接口。
2.3 审批流程模板添加链接
看图,3步搞定