釘釘開發之業務事件回調

釘釘開發

一、釘釘開發之業務事件回調

簡單的來說:業務事件回調就是 通過向釘釘服務器註冊監聽 一些指定的事件,當用戶在釘釘上操作我們已經監聽的事件,那麼釘釘服務器就會想 我們的服務器 發送通知,我們可以得到監聽事件的詳細信息。
比如:我最近開發遇到的需求,需要獲取用戶審批實例裏面的表單數據,這裏我就用了釘釘的業務事件回調,我想釘釘服務器註冊我需要監聽的事件(這裏我監聽了,審批實例回調和審批任務回調)。當我向釘釘服務器註冊回調接口後,一旦有用戶在 釘釘上發起流程,釘釘服務器就會推動給我,而我這邊也可以獲取用戶發起流程的詳情。

1.註冊業務事件回調接口

①、微應用服務器調用 註冊事件回調接口(post請求)

https://oapi.dingtalk.com/call_back/register_call_back?access_token=ACCESS_TOKEN

請求參數示例:

{
    "call_back_tag": ["user_add_org", "user_modify_org", "user_leave_org"],
    "token": "123456",
    "aes_key": "xxxxxxxxlvdhntotr3x9qhlbytb18zyz5zxxxxxxxxx",
    "url":"http://test001.vaiwan.com/eventreceive"
}
參數 參數類型 必須 說明
access_token String 調用接口憑證
call_back_tag Array[String] 需要監聽的事件類型
token String 加解密需要用到的token,ISV(服務提供商)推薦使用註冊套件時填寫的token,普通企業可以隨機填寫
aes_key String 數據加密密鑰。用於回調數據的加密,長度固定爲43個字符,從a-z, A-Z, 0-9共62個字符中選取,您可以隨機生成,ISV(服務提供商)推薦使用註冊套件時填寫的EncodingAESKey
url String 接收事件回調的url,必須是公網可以訪問的url地址

返回結果:

{
    "errcode": 0,
    "errmsg": "ok"
}

更多 查詢事件回調接口、更新事件回調接口、刪除事件回調接口、獲取回調失敗的結果等接口參考 https://ding-doc.dingtalk.com/doc#/serverapi2/pwz3r5

②.釘釘服務器會向第①步中請求參數 url 的地址推送消息

③.第 ② 和 第③ 都在下面的方法中執行了

例如:下面callback方法爲回調地址,釘釘服務器會返回 signature timestamp nonce 加密後的 json 數據

package com.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import com.config.Constant;
import com.config.URLConstant;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiCallBackDeleteCallBackRequest;
import com.dingtalk.api.request.OapiCallBackGetCallBackRequest;
import com.dingtalk.api.request.OapiCallBackRegisterCallBackRequest;
import com.dingtalk.api.response.OapiCallBackDeleteCallBackResponse;
import com.dingtalk.api.response.OapiCallBackRegisterCallBackResponse;
import com.dingtalk.oapi.lib.aes.DingTalkEncryptor;
import com.dingtalk.oapi.lib.aes.Utils;
import com.util.AccessTokenUtil;
import com.util.MessageUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.Arrays;
import java.util.Map;

/**
 * E應用回調信息處理
 */
@RestController
public class CallbackController {

    private static final Logger bizLogger = LoggerFactory.getLogger("BIZ_CALLBACKCONTROLLER");
    private static final Logger mainLogger = LoggerFactory.getLogger(CallbackController.class);

    /**
     * 創建套件後,驗證回調URL創建有效事件(第一次保存回調URL之前)
     */
    private static final String CHECK_URL = "check_url";

    /**
     * 審批任務回調,更多回調類型 參考 https://ding-doc.dingtalk.com/doc#/serverapi2/skn8ld
     */
    private static final String BPMS_TASK_CHANGE = "bpms_task_change";

    /**
     * 審批實例回調
     */
    private static final String BPMS_INSTANCE_CHANGE = "bpms_instance_change";

    /**
     * 相應釘釘回調時的值
     */
    private static final String CALLBACK_RESPONSE_SUCCESS = "success";
    
    /**
     * 審批模板唯一標識,可以在審批管理後臺的 URL 中找到
     */
    public static final String PROCESS_CODE = "***";


    @RequestMapping(value = "/callback", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, String> callback(@RequestParam(value = "signature", required = false) String signature,
                                        @RequestParam(value = "timestamp", required = false) String timestamp,
                                        @RequestParam(value = "nonce", required = false) String nonce,
                                        @RequestBody(required = false) JSONObject json) {
        String params = " signature:"+signature + " timestamp:"+timestamp +" nonce:"+nonce+" json:"+json;
        try {
            DingTalkEncryptor dingTalkEncryptor = new DingTalkEncryptor(Constant.TOKEN, Constant.ENCODING_AES_KEY,
                Constant.CORP_ID);

            //從post請求的body中獲取回調信息的加密數據進行解密處理
            String encryptMsg = json.getString("encrypt");
            String plainText = dingTalkEncryptor.getDecryptMsg(signature, timestamp, nonce, encryptMsg);
            JSONObject obj = JSON.parseObject(plainText);

            //根據回調數據類型做不同的業務處理
            String eventType = obj.getString("EventType");
            if (BPMS_TASK_CHANGE.equals(eventType)) {
                bizLogger.info("收到審批任務進度更新: " + plainText);
                // 可以根據 PROCESS_CODE 來判斷這是屬於哪個模板發起的流程
                // 參考 https://ding-doc.dingtalk.com/doc#/serverapi2/skn8ld 得到返回的數據做業務
                //todo: 實現審批的業務邏輯,如發消息
            } else if (BPMS_INSTANCE_CHANGE.equals(eventType)) {
                bizLogger.info("收到審批實例狀態更新: " + plainText);
                //todo: 實現審批的業務邏輯,如發消息
                String processInstanceId = obj.getString("processInstanceId");
                if (obj.containsKey("result") && obj.getString("result").equals("agree")) {
                    MessageUtil.sendMessageToOriginator(processInstanceId);
                }
            } else {
                // 其他類型事件處理
            }

            // 返回success的加密信息表示回調處理成功【這是第 三 步,返回加密後的 “success” 給釘釘服務器,讓釘釘服務器知道此次回調成功了。否則釘釘會持續推動消息的回調接口。】
            return dingTalkEncryptor.getEncryptedMap(CALLBACK_RESPONSE_SUCCESS, System.currentTimeMillis(), Utils.getRandomStr(8));
        } catch (Exception e) {
            //失敗的情況,應用的開發者應該通過告警感知,並干預修復
            mainLogger.error("process callback failed!"+params,e);
            return null;
        }

    }

    public static void main(String[] args) throws Exception{
        // 先刪除企業已有的回調
        DingTalkClient client = new DefaultDingTalkClient(URLConstant.DELETE_CALLBACK);
        OapiCallBackDeleteCallBackRequest request = new OapiCallBackDeleteCallBackRequest();
        request.setHttpMethod("GET");
        client.execute(request, AccessTokenUtil.getToken());

        // 重新爲企業註冊回調
        client = new DefaultDingTalkClient(URLConstant.REGISTER_CALLBACK);
        OapiCallBackRegisterCallBackRequest registerRequest = new OapiCallBackRegisterCallBackRequest();
        registerRequest.setUrl(Constant.CALLBACK_URL_HOST + "/callback");
        registerRequest.setAesKey(Constant.ENCODING_AES_KEY);
        registerRequest.setToken(Constant.TOKEN);
        registerRequest.setCallBackTag(Arrays.asList("bpms_instance_change", "bpms_task_change"));
        OapiCallBackRegisterCallBackResponse registerResponse = client.execute(registerRequest,AccessTokenUtil.getToken());
        if (registerResponse.isSuccess()) {
            System.out.println("回調註冊成功了!!!");
        }
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章