企业微信上是这样介绍的。不过经本人的研究测试,该工作流引擎的功能是比较有限的。
首先只有移动端才能发起,流程的定义是必须在企业微信控制台中定义,而且不支持条件分支,适用于比较简单的应用场景,请假之类的。而且审批界面数据展示自定义程度很低。
文档链接:
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产生。所有接口在通信时都需要携带此信息用于验证接口的访问权限
文档链接
https://work.weixin.qq.com/api/doc#90000/90135/90269
1.通过config接口注入权限验证配置。查看
2.通过agentConfig注入应用的权限。查看
3.调用审批流程引擎JS-API(如下文请求示例)。
菜鸟教程(runoob.com)
注意:调试前端页面必须用企业微信客户端,pc版均不支持。
@Api(value="企业微信相关信息获取",description = "企业微信相关信息获取")
@RequestMapping("/weichat-config")
@Controller
public class WeiChatConfigController {
@Autowired
ApprovalPrecessService approvalPrecessService;
@ApiOperation(value = "获取前端登录时需要的签名信息",notes = "获取前端登录时需要的签名信息",httpMethod = "GET")
@RequestMapping(value = "/getSignature",method = RequestMethod.GET)
@ResponseBody
public RestResult 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;
@Autowired
private WeichatService weichatService;
@Override
public 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);
}
@Override
public 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();
//企业的jsTickt
String jsTickt = CallWxUtil.getJsTicket(accessToken);
//应用的jsTickt
String 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
获取jsticket 参考文档
https://work.weixin.qq.com/api/doc#10029/获取应用的jsapi_ticket
其中jsticket是签名的重要参数,和access_token一样具有时效性,建议缓存处理。
文档参考: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 {
@Autowired
private WeiChatCallbackService weiChatCallbackService;
//第一次get请求验证
@GetMapping(value = "/callBack")
@ResponseBody
public String verifyURL(String msg_signature, String timestamp, String nonce, String echostr) {
return weiChatCallbackService.verifyURL(msg_signature,timestamp,nonce,echostr);
}
//接受post请求消息推送
@PostMapping("/callBack")
@ResponseBody
public 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);
}
@Override
public 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 "无";
}
@Override
public 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 版即可
这里使用移动端app测试,必须让项目处于公网可信域名下。笔者是通过内网穿透到自己买的域名上,具体可以自己学习研究。
同时在工作台配置
在企业微信上打开前端页面
点击提交