Java對接企業(yè)微信審批回調(diào)
一、需求說明
用Java程序?qū)悠髽I(yè)微信的審批流程,獲取審批數(shù)據(jù)數(shù)據(jù),例如:報銷費用金額
二、操作步驟
2.1、分析需求
根據(jù)需求分析其實也不知道該怎么去做對接,通過不斷試錯,發(fā)現(xiàn)不需要對接第三方應(yīng)用,也就是不需要進(jìn)入服務(wù)商后臺頁面,只需要在自建應(yīng)用是做好配置即可。
具體參考:https://developer.work.weixin.qq.com/document/path/90665
2.2、搭建 自建應(yīng)用
前言
這里先介紹一下關(guān)鍵參數(shù)從哪里取,具體詳見官方文檔:https://developer.work.weixin.qq.com/document/path/90665#corpid
corpid,每個企業(yè)都擁有唯一的corpid,獲取此信息可在管理后臺“我的企業(yè)”-“企業(yè)信息”下查看“企業(yè)ID”(需要有管理員權(quán)限)

Token、EncodingAESKey:是在自建應(yīng)用-API接受消息中隨機(jī)獲取的到時候進(jìn)行保存即可,具體見下圖

secret
secret是企業(yè)應(yīng)用里面用于保障數(shù)據(jù)安全的“鑰匙”,每一個應(yīng)用都有一個獨立的訪問密鑰,為了保證數(shù)據(jù)的安全,secret務(wù)必不能泄漏。secret查看方法:
在管理后臺->“應(yīng)用管理”->“應(yīng)用”->“自建”,點進(jìn)某個應(yīng)用,即可看到。
2.2.1、創(chuàng)建 自建應(yīng)用


注: 選擇可見范圍根據(jù)業(yè)務(wù)需求進(jìn)行選擇,如果是針對全公司的業(yè)務(wù),則需要選全公司,不然會獲取不到數(shù)據(jù)進(jìn)行報錯
2.2.3、配置接收消息即回調(diào)地址


其中回調(diào)URL的配置需要寫對應(yīng)的回調(diào)方法,具體可以參考:Demo(https://developer.work.weixin.qq.com/devtool/introduce?id=10128),這里建議使用XML格式,因為獲取審批流程中的參數(shù)都是XML格式。具體見下圖:

// 這個方法是進(jìn)行回調(diào)驗證的。下面還有一個同樣的方法差別僅是將GET換為POST方法,用于接收信息的。
@RequestMapping(value = "/callback/data",method = RequestMethod.GET) public void connect(HttpServletRequest request, HttpServletResponse response){ //當(dāng)你提交以上信息時,企業(yè)號將發(fā)送GET請求到填寫的URL上,GET請求攜帶四個參數(shù),企業(yè)在獲取時需要做urldecode處理,否則會驗證不成功 // 微信加密簽名 String msg_signature = request.getParameter("msg_signature"); // 時間戳 String timestamp = request.getParameter("timestamp"); // 隨機(jī)數(shù) String nonce = request.getParameter("nonce"); // 隨機(jī)字符串 String echoStr = request.getParameter("echostr"); //回調(diào)key值 String sEchoStr = null; String contacts_token = PropertiesUtil.getProperty("contacts_token"); String contacts_encodingaeskey = PropertiesUtil.getProperty("contacts_encodingaeskey"); String corpId = PropertiesUtil.getProperty("corpid"); try { PrintWriter out = response.getWriter(); WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(contacts_token,contacts_encodingaeskey,corpId); sEchoStr = wxcpt.VerifyURL(msg_signature,timestamp,nonce,echoStr); if(StringUtils.isBlank(sEchoStr)){ logger.error("URL驗證失敗"); } out.write(sEchoStr); out.flush(); }catch (Exception e){ logger.error("企業(yè)微信回調(diào)url驗證錯誤",e); } }
2.2.4、配置IP白名單
多個IP用英文分號進(jìn)行區(qū)分

2.2.5、在審批應(yīng)用中配置回調(diào)通知


2.2.6、寫程序獲取審批流程數(shù)據(jù)
走完前面流程后,再部署上下面的代碼后,就可以了。當(dāng)有要監(jiān)控回調(diào)的審批數(shù)據(jù)后,就會調(diào)用下面的方法,拿到審批數(shù)據(jù)。
具體里面會用到三個知識點。
1、會用到官方接口文檔中:開發(fā)指南-回調(diào)配置-3.2 支持Http Post請求接收業(yè)務(wù)數(shù)據(jù),詳見:https://developer.work.weixin.qq.com/document/path/90930#32-%E6%94%AF%E6%8C%81http-post%E8%AF%B7%E6%B1%82%E6%8E%A5%E6%94%B6%E4%B8%9A%E5%8A%A1%E6%95%B0%E6%8D%AE
2、會用到官方接口文檔中:開發(fā)指南-獲取access_token,詳見:https://developer.work.weixin.qq.com/document/path/91039
3、會用到官方接口文檔中:審批-獲取審批申請詳情,詳見:https://developer.work.weixin.qq.com/document/path/91983
@RequestMapping(value = "/callback/data",method = RequestMethod.POST)
public void acceptMessage(HttpServletRequest request, RedirectAttributes attributes, HttpSession session){
System.out.println("————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————");
logger.debug("企業(yè)微信信息交互");
// 微信加密簽名
String sMsgSignature = request.getParameter("msg_signature");
// 時間戳
String sTimestamp = request.getParameter("timestamp");
// 隨機(jī)數(shù)
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();
// 創(chuàng)建一個 StringBuilder 對象來存儲請求內(nèi)容
StringBuilder xmlContent = new StringBuilder();
// 使用 BufferedReader 讀取輸入流內(nèi)容
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
xmlContent.append(line);
}
// 關(guān)閉輸入流和讀取器
inputStream.close();
reader.close();
// 輸出請求內(nèi)容
System.out.println("請求 XML 內(nèi)容:" + xmlContent.toString());
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>";
if(!sReqData.contains("wwc892952bc0c83b95")){
//不是該應(yīng)用
System.out.println("錯誤提交應(yīng)用數(shù)據(jù)");
System.out.println("————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————");
}else{
String contacts_token = "xxx";
String corpId = "xxxx";
String contacts_encodingaeskey = "xxxx";
WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(contacts_token,contacts_encodingaeskey,corpId);
String sMsg = wxcpt.DecryptMsg(sMsgSignature, sTimestamp, sNonce, sReqData);
System.out.println("after decrypt msg: " + sMsg);
// TODO: 解析出明文xml標(biāo)簽的內(nèi)容進(jìn)行處理
// 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();
NodeList nodelist1 = root.getElementsByTagName("SpNo");
// 獲取審批編號
String SpNo = nodelist1.item(0).getTextContent();
System.out.println("審批編號為:" + SpNo);
NodeList SpStatus_Node = root.getElementsByTagName("SpStatus");
// 申請單狀態(tài):1-審批中;2-已通過;3-已駁回;4-已撤銷;6-通過后撤銷;7-已刪除;10-已支付
String SpStatus = SpStatus_Node.item(0).getTextContent();
if("2".equals(SpStatus)){
// 當(dāng)狀態(tài)為2-已通過時進(jìn)行存儲
//先判斷該審批編號是否已存
//獲取accesstoken
String accessUrl = "https://qyapi.weixin.qq.com/cgi-bin/gettoken";
String corpid = "xxxxx";
String corpsecret = "xxxx";
accessUrl=accessUrl+"?corpid="+corpid+"&corpsecret="+corpsecret;
System.out.println("請求access_token請求參數(shù):"+accessUrl);
String result = HttpUtil.get(accessUrl);
JSONObject resultJson = JSON.parseObject(result);
System.out.println("請求access_token返回結(jié)果:"+resultJson);
String access_token = resultJson.getString("access_token");
String getapprovalUrl = "https://qyapi.weixin.qq.com/cgi-bin/oa/getapprovaldetail?access_token="+access_token;
JSONObject params = new JSONObject();
params.put("sp_no", SpNo);
System.out.println("請求獲取審批詳情接口請求參數(shù):"+params);
String post_result = HttpUtil.post(getapprovalUrl, params.toJSONString());
JSONObject postJson = JSON.parseObject(post_result);
System.out.println("請求獲取審批詳情接口返回結(jié)果:"+postJson);
System.out.println("————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————");
}
}
}catch (Exception e){
logger.error("企業(yè)微信消息交互錯誤",e);
}
}
三、總結(jié)
個人感覺企微的開發(fā)文檔寫的特別垃圾,繞來繞去的很不清晰。希望自己整理后后面再看的時候有些幫助。

浙公網(wǎng)安備 33010602011771號