企业微信开发实战:自建审批流引擎
1.概述
企业微信上是这样介绍的。不过经本人的研究测试,该工作流引擎的功能是比较有限的。
首先只有移动端才能发起,流程的定义是必须在企业微信控制台中定义,而且不支持条件分支,适用于比较简单的应用场景,请假之类的。而且审批界面数据展示自定义程度很低。
2.企业微信开发基础
文档链接:
https://work.weixin.qq.com/api/doc#90000/90135/90665
corpid
每个企业都拥有唯一的corpid,获取此信息可在管理后台“我的企业”-“企业信息”下查看“企业ID”(需要有管理员权限)
agentid
每个应用都有唯一的agentid。在管理后台->“应用与小程序”->“应用”,点进某个应用,即可看到agentid。
secret
secret是企业应用里面用于保障数据安全的“钥匙”,每一个应用都有一个独立的访问密钥,为了保证数据的安全,secret务必不能泄漏。
access_token
access_token是企业后台去企业微信的后台获取信息时的重要票据,由corpid和secret产生。所有接口在通信时都需要携带此信息用于验证接口的访问权限
3.审批流引擎开发
文档链接
https://work.weixin.qq.com/api/doc#90000/90135/90269
1.创建自建应用审批模板
2.前端调用页面
1.通过config接口注入权限验证配置。查看
2.通过agentConfig注入应用的权限。查看
3.调用审批流程引擎JS-API(如下文请求示例)。
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>菜鸟教程(runoob.com)</title><script src="js/jquery.min.js"></script><script src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script><script>$(document).ready(function(){var link = window.location.href;$("button").click(function(){$.ajax({//请求方式type : "GET",//请求的媒体类型contentType: "application/json;charset=UTF-8",//请求地址url : "http://zdwtest.nat300.top/weichat-config/getSignature",//数据,json字符串data : {"url":link},//请求成功success : function(res) {// console.log(data);wx.config({beta: true,debug: true,appId: res.data.corpId,timestamp: res.data.timestamp,nonceStr: res.data.noncestr,signature: res.data.signature,jsApiList: ['agentConfig','openUserProfile','thirdPartyOpenPage','selectExternalContact']});wx.ready(function(){wx.agentConfig({corpid: res.data.corpId, // 必填,企业微信的corpid,必须与当前登录的企业一致agentid: res.data.agentId, // 必填,企业微信的应用idtimestamp: res.data.timestamp, // 必填,生成签名的时间戳nonceStr: res.data.noncestr, // 必填,生成签名的随机串signature: res.data.agentSignature,// 必填,签名,见附录1jsApiList: ['agentConfig','openUserProfile','thirdPartyOpenPage','selectExternalContact'], //必填success: function(res) {// 发起审批流程wx.invoke('thirdPartyOpenPage', {"oaType": "10001",// String"templateId": "e38e4df283a991b00e3394dc71fbef79_1837057289",// String"thirdNo": "t01",// 审批单号,开发者自己控制,不可重复"extData": {'fieldList': [{'title': '采购类型','type': 'text','value': '市场活动',},{'title': '采购类型','type': 'text','value': '市场活动',},{'title': '采购类型','type': 'text','value': '市场活动',},{'title': '采购类型','type': 'text','value': '市场活动',},{'title': '采购类型','type': 'text','value': '市场活动',}],}},function(res) {// 输出接口的回调信息console.log(res);});},fail: function(res) {if(res.errMsg.indexOf('function not exist') > -1){alert('版本过低请升级')}}});})}});});});</script>
</head><body>
<button>点我</button>
</body>
</html>
注意:调试前端页面必须用企业微信客户端,pc版均不支持。
3.获取签名的后台接口
@Api(value="企业微信相关信息获取",description = "企业微信相关信息获取")
@RequestMapping("/weichat-config")
@Controller
public class WeiChatConfigController {@AutowiredApprovalPrecessService approvalPrecessService;@ApiOperation(value = "获取前端登录时需要的签名信息",notes = "获取前端登录时需要的签名信息",httpMethod = "GET")@RequestMapping(value = "/getSignature",method = RequestMethod.GET)@ResponseBodypublic RestResult<WeixinConfigDTO> getTWeixinConfig(String url){WeixinConfigDTO tWeixinConfig = approvalPrecessService.getTweixinConfig(url);return new RestResult(tWeixinConfig);}
}
public class ApprovalProcessServiceImpl implements ApprovalPrecessService {
// private static log log = log.getlog(ApprovalProcessServiceImpl.class);
// private static PropertiesFileUtil propertiesFileUtil = new PropertiesFileUtil();
// @Autowired
// TWeixinConfigMapper tWeixinConfigMapper;@Autowiredprivate WeichatService weichatService;@Overridepublic String getSignature(String jsTickt,String noncestr,String timestamp,String url) throws Exception {String str = "jsapi_ticket="+jsTickt+"&"+"noncestr="+noncestr+"&"+"timestamp="+timestamp+"&"+"url="+url;return DigestUtils.sha1Hex(str);}@Overridepublic WeixinConfigDTO getTweixinConfig(String url){WeixinConfigDTO weixinConfigDTO = new WeixinConfigDTO();try {String agentId = WeiChatConfigConstants.QIYEWEICHAT_AGENTID;String corpId = WeiChatConfigConstants.QIYEWEICHAT_CORPID;String secret = WeiChatConfigConstants.QIYEWEICHAT_CORPSECRET;String accessToken = weichatService.getWeiChatAccessTokern();//企业的jsTicktString jsTickt = CallWxUtil.getJsTicket(accessToken);//应用的jsTicktString agentJsTickt = CallWxUtil.getAgentJsTicket(accessToken);String timestamp=String.valueOf(System.currentTimeMillis());String noncestr =getRandomString(16);String userUrl=url;String signature = getSignature(jsTickt, noncestr, timestamp, userUrl);String agentSignature = getSignature(agentJsTickt, noncestr, timestamp, userUrl);weixinConfigDTO.setCorpId(corpId);weixinConfigDTO.setAgentId(agentId);weixinConfigDTO.setCorpSecret(secret);weixinConfigDTO.setSignature(signature);weixinConfigDTO.setAgentSignature(agentSignature);weixinConfigDTO.setNoncestr(noncestr);weixinConfigDTO.setJsapiTicket(jsTickt);weixinConfigDTO.setTimestamp(Long.valueOf(timestamp));weixinConfigDTO.setAccessToken(accessToken);}catch (Exception e){log.info(e.getMessage());log.info("获取签名异常!!");}return weixinConfigDTO;}private static String getRandomString(int length){String keyString = "ergrfewfwdgggcvv;uihefujsncjdvngrjegeuirgverggvbergbvuigverug";int len = keyString.length();StringBuffer str = new StringBuffer();for(int i=0;i<length;i++){str.append(keyString.charAt((int) Math.round(Math.random() * (len - 1))));}return str.toString();}
}
获取jsticket 参考文档
https://work.weixin.qq.com/api/doc#10029/获取应用的jsapi_ticket
其中jsticket是签名的重要参数,和access_token一样具有时效性,建议缓存处理。
4.接受审批回调信息的接口
文档参考:https://work.weixin.qq.com/api/doc#90000/90135/90930
首先在控制台配置url为介绍审批回调信息的接口,然后随机生成token,encodingAESkey,建议生成后固定。
企业微信首先会对回调接口进行校验,成功之后便会推送回调信息。
这里GET 为检验接口,
1.对收到的请求,解析上述的各个参数值(参数值需要做Urldecode处理)
2.根据已有的token,结合第1步获取的参数timestamp, nonce, echostr重新计算签名,然后与参数msg_signature检查是否一致,确认调用者的合法性。计算方法参考:消息体签名检验
3.解密echostr参数得到消息内容(即msg字段)
4.在1秒内响应GET请求,响应内容为上一步得到的明文消息内容(不能加引号,不能带bom头,不能带换行符)
POST为推送接口
1.对msg_signature进行校验
2.解密Encrypt,得到明文的消息结构体(消息结构体后面章节会详说)
3.如果需要被动回复消息,构造被动响应包
4.正确响应本次请求
· 企业微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次
· 当接收成功后,http头部返回200表示接收ok,其他错误码企业微信后台会一律当做失败并发起重试
@Controller
@RequestMapping("/weichat-callBack")
public class WeiChatCallbackController {@Autowiredprivate WeiChatCallbackService weiChatCallbackService;//第一次get请求验证@GetMapping(value = "/callBack")@ResponseBodypublic String verifyURL(String msg_signature, String timestamp, String nonce, String echostr) {return weiChatCallbackService.verifyURL(msg_signature,timestamp,nonce,echostr);}//接受post请求消息推送@PostMapping("/callBack")@ResponseBodypublic void callBack(HttpServletRequest request, String msg_signature, String timestamp, String nonce) {weiChatCallbackService.doCallBack(request, msg_signature, timestamp, nonce);}}
public class WeiChatCallbackServiceImpl implements WeiChatCallbackService {private WXBizMsgCrypt getWXBizMsgCrypt() throws AesException {String sToken = WeiChatConfigConstants.QIYEWEICHAT_MSGTOKEN;String sCorpID = WeiChatConfigConstants.QIYEWEICHAT_CORPID;String sEncodingAESKey = WeiChatConfigConstants.QIYEWEICHAT_ENCODINGAESKEY;return new WXBizMsgCrypt(sToken, sEncodingAESKey, sCorpID);}@Overridepublic String verifyURL(String msg_signature, String timestamp, String nonce, String echostr) {try {WXBizMsgCrypt wxcpt = getWXBizMsgCrypt();String sEchoStr; //需要返回的明文sEchoStr = wxcpt.VerifyURL(msg_signature, timestamp,nonce, echostr);return sEchoStr;} catch (Exception e) {//验证URL失败,错误原因请查看异常e.printStackTrace();log.error(e.getMessage());}return "无";}@Overridepublic void doCallBack(HttpServletRequest request, String msg_signature, String timestamp, String nonce) {// post请求的密文数据try {WXBizMsgCrypt wxcpt = getWXBizMsgCrypt();InputStream inputStream = request.getInputStream();String sPostData = IOUtils.toString(inputStream,"UTF-8");String sMsg = wxcpt.DecryptMsg(msg_signature, timestamp, nonce, sPostData);System.out.println("after decrypt msg: " + sMsg);// TODO: 解析出明文xml标签的内容进行处理// For example: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();//获取消息类型String msgType = getContentByTagName(root,"MsgType");System.out.println("MsgType:" + msgType);//处理文本信息if (WeiChatMsgTypeEnum.TEXT.getValueInFact().equals(msgType)){dealWeiChatTextMsg(root);//处理事件信息}else if (WeiChatMsgTypeEnum.EVENT.getValueInFact().equals(msgType)){dealWeiChatEventMsg(root);}} catch (Exception e) {// TODO// 解密失败,失败原因请查看异常e.printStackTrace();log.error(e.getMessage());}}private void dealWeiChatTextMsg(Element root) {String content = getContentByTagName(root,"Content");System.out.println("Content:" + content);content = getContentByTagName(root,"FromUserName");System.out.println("FromUserName:" + content);}private void dealWeiChatEventMsg(Element root) {String content = getContentByTagName(root,"OpenSpName");System.out.println("审批模板名称:" + content);content = getContentByTagName(root,"ApplyUserName");System.out.println("提交人姓名:" + content);content = getContentByTagName(root,"NodeStatus");System.out.println("节点审批状态:" + content);}private String getContentByTagName(Element root, String tagName){NodeList nodelist = root.getElementsByTagName(tagName);String Content = nodelist.item(0).getTextContent();return Content;}}
解密,签名的工具类可参考官方的demo
https://work.weixin.qq.com/api/doc#90000/90138/90307
下载java 版即可
4.效果测试
这里使用移动端app测试,必须让项目处于公网可信域名下。笔者是通过内网穿透到自己买的域名上,具体可以自己学习研究。
同时在工作台配置
在企业微信上打开前端页面
点击提交
后台回调到审批信息回传信息
企业微信开发实战:自建审批流引擎相关推荐
- 企业微信开发实战(五、自建应用-审批流程引擎之配置可信任域名、创建审批模版、发起审批)
文章目录 四.自建应用-审批流程引擎 1.概述 2.创建自建应用审批模板 2.1创建自建审批应用 2.2配置可信任域名 2.3创建审批模版 3.自建应用发起审批 3.1概述 3.2代码实战 3.2.1 ...
- 企业微信开发实战(四、OA审批之企业假期管理配置、获取成员假期余额、修改成员假期余额)
文章目录 7.获取企业假期管理配置 7.1概述 7.2代码实战 8.获取成员假期余额 8.1概述 8.2代码实战 8.3试错 9.修改成员假期余额 9.1概述 9.2代码实战 9.3试错 源码 赞赏 ...
- 企业微信开发(自建应用h5)
1.企微后台(管理应用.设置应用可见人员范围等):企业微信 2. 企微开发者中心(API文档):简易教程 - 接口文档 - 企业微信开发者中心 3. oAuth2链接创建(静默授权和手动授权):开始开 ...
- 企业微信开发:自建应用配置可信域名(一)
前言 企业微信自建应用配置网页授权可信任域名(需要管理员权限) 配置 打开应用管理 - 选择已经创建的应用,找到如图内容 配置网页授权及 JS-SDK,直接输入域名,然后点击申请校验域名, ...
- 企业微信开发实战(一、相关说明及注册企业微信)
文章目录 一.写着前面 1.说明 2.环境 二.注册企业微信 源码 赞赏 一.写着前面 1.说明 1.官方文档地址:https://open.work.weixin.qq.com/api/doc/90 ...
- 企业微信开发——企业内部自建应用开发(第一篇)---环境搭建
一.背景介绍 现在越来越多的企业开始注重私域流量的运营和建设,防止客户随着人员流动而流失,所以就出现了基于企业微信开发的需求,但是目前关于企业微信开发的生态环境依旧不太丰富,腾讯的api文档写的也是晦 ...
- 服务器端缓存企业微信,企业微信开发
企业微信开发又以下三类,可以根据需要查看相应的文档 企业内部应用开发:开发内部使用应用,开发个性化办公应用 第三方应用开发:开发出来的应用可供其他企业使用 第三方应用开发.png 智慧硬件开发 企业内 ...
- 企业微信开发第三方应用开发视频教程,ToB Dev李月喜全网首发
csdn程序员学院<企业微信三方应用开发>视频课程,全网企业微信三方应用开发教程首发, https://edu.csdn.net/course/detail/30582 即将完结欢迎试看 ...
- Spring 3.x企业应用开发实战
Java技术大系 Spring 3.x企业应用开发实战 陈雄华 林开雄 著 Publishing House ofElectronics Industry 北京· BEIJING 内 ...
- 23 20210525+0529直播 企业微信接口测试实战1+2
文章目录 企业微信接口测试实战1 RESTFUL 规范 实战内容 接口测试基础 restful 架构 接口测试流程 接口自动化脚本编写 项目流程 需求分析 需求理解 接口业务关系 接口测试用例编写思路 ...
最新文章
- C++类的定义和声明
- 牛客网(剑指offer) 第十五题 反转链表
- SharePoint2010 连接配置数据库字符串保存位置(转)
- 初学者学python,列表推导到zip()函数,必须会的五种技巧
- springbatch导出mysql数据到外部文件
- A-Webkit第四章:添加学生
- 代码平台Github半年发布125项更新,私库无限免费开启(附步骤)
- mysql 命令行关闭fuw_网络管理 - eSight V300R009C00 维护指南 12 - 华为
- 解决方案 | 解决Adobe Acrobat 2020安装报错的一些问题,如无法打开键
- Windows 10 (64位)下 VMware 15虚拟机下载及安装教程(内附安装包)
- Ubuntu mate自启脚本/命令+关闭图形桌面
- 多点移动电子地图定位
- ubuntu下重装WIN7
- 江苏省计算机高考试题,08-12江苏省单招计算机原理高考试题汇总
- Python中rect属性
- 【汽车配件管理系统-管理员-配件管理模块】配件管理分类
- METIS安装与使用
- 目标检测训练数据扩充增强工具使用说明
- 工作生活可能用得到的资源
- 网络层(2.网际协议IP)
热门文章
- 单片机简易计算机设计实物,单片机设计的带余数的简易计算器
- 遥感式雷达监测水位流速设备
- dell服务器开机蓝屏无限重启,戴尔电脑不停蓝屏重启怎么办
- 教你如何将 Excel 中的数据按模板批量生成 Word、Excel、PPT、PDF 以及 Txt 类型的文本文件
- 关于DiskGenius 克隆分区和系统迁移问题,以及如何解决缺少系统引导、双硬盘双系统引导问题,多个启动项
- xmapp老是端口占用
- 寻路大数据:海量数据与大规模分析
- PS制作简洁漂亮的立体抽丝文字
- 汉印扫描器设置软件_汉印HPRTK180打印机驱动
- 牛头刨床设计matlab生成图片,牛头刨床matlab程序---机械原理课程设计