接入企业微信审批开发记录
背景
客户提了关于对接企业微信【审批】功能的需求,具体需求包括:
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";
// 企业ID
String 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步搞定

浙公网安备 33010602011771号