基于Java的钉钉SDK开发--⽐官⽅SDK还好⽤的钉钉SDK
更好的排版可以看这个
钉钉官⽅的SDK对钉钉API提供了简单的封装,但官⽅的SDK使⽤起来较为臃肿,并且最重要的是官⽅SDK仅仅是封装了API,对于accessToken的维护以及消息回调处理等等都没有封装,在项⽬中⼤规模使⽤⽐较⿇烦,因此萌⽣了对钉钉官⽅SDK进⾏全⾯重构的想法钉钉官⽅SDK存在的⼀些问题或不⾜
我们在使⽤官⽅SDK的过程中发现官⽅SDK存在⼀些⽐较蛋疼的问题:
1. accessToken需要⾃⼰来维护,SDK并不维护,那么在实际使⽤中就要做好accessToken的过期处理、多线程刷新时保证刷新是正确
2. 除了⾃⼰维护accessToken外,基本上每次调⽤都需要将accessToken作为参数传⼊,没有⾃动化的将固定参数补齐
3. 消息回调的加解密并不包含在SDK中,需要⾃⼰整合进来
4. 对不同消息如何处理应该在SDK层⾯来解决掉,这样业务层⾯就只需要关⼼具体的处理逻辑即可,但SDK并不包含这些
5. 不⽀持HTTP代理,当代码部署在内⽹后没办法直接和钉钉API交互,需要借助代理来完成交互,但SDK并不⽀持代理且由于第6点的
原因想优化SDK却不好下⼿优化
6. SDK封装⽅式⽐较蛋疼,底层⼜是⽤到了淘宝的SDK,不是很容易来修改
7. 当然还有其他的⼩问题,⽐如调⽤SDK⽅法时并不知道需要传哪些参数所以需要对照着开发⽂档才能发起调⽤等等。
基于以上的原因,官⽅SDK不满⾜我们的实际场景太多了,⽤起来太蛋疼了,主要是:
1. 不维护accessToken
2. 没有加解密
3. 没有消息路由
4. 不⽀持代理
5. 对照开发⽂档才能使⽤
我们是完全抛弃了钉钉官⽅SDK,从零搭建出了⼀套Java版本的钉钉SDK,并且已经开源出来了,可见,希望⼤家能多多点点Star、Fork,跪谢。
⽐官⽅SDK还好⽤的钉钉SDK
⾃认为DtJava(钉钉 Java SDK)对开发者更加友好,使⽤起来⽐官⽅SDK好⽤多了。
基本的API调⽤封装
下⾯简单⽐较下官⽅SDK和DtJava之间的调⽤⽅式。
⾸先是官⽅SDK的调⽤⽅式:
DingTalkClient client = new DefaultDingTalkClient("oapi.dingtalk/user/get");
OapiUserGetRequest req = new OapiUserGetRequest();
req.setUserid("userid1");
req.setHttpMethod("GET");
sdkOapiUserGetResponse rsp = ute(req, accessToken);
整个调⽤过程就是
1. 初始化⼀个DingTalkClient出来,初始化的同时指定API的URL地址是啥
2. 初始化请求参数,并设置好参数与请求⽅式
3. 获取accessToken,在这⼀步中还要处理好过期刷新的问题
4. 发起请求
在这个调⽤过程中,完全没必要这样来使⽤,我们可以将API的地址、参数、请求全部封装起来,整体对外暴露成⼀个⽅法,再进⼀步封装可以将accessToken封装进⽅法中。
这样封装之后基本上类似DtJava的调⽤⽅式:
DtUser user = UserService().getById(userId);
⼀⾏代码便⾜够了,当然在这个背后整体的调⽤逻辑是
1. 获取到对应的API地址
2. 拼接设置参数
3. 获取accessToken,包含了过期处理等等逻辑
4. 发起请求
5. 解析响应并封装成对应的Bean
全部的逻辑都被封装起来,具体的封装细节⼤家可以到(求Star求魔怔了),对开发者⽽⾔就是⼀个⽅法的调⽤即可,⽐官⽅SDK友好的多。
回调消息处理
除了基本的API调⽤外,钉钉的开放平台还有⼀个很重要的部分就是事件回调,在通讯录同步等等场景中回调发挥着重要的作⽤。但官⽅SDK并没有涉⾜到这⼀部分,对于开发者⽽⾔需要⾃⼰去整合加解密的流程以及对不同消息的处理逻辑。但好在官⽅已经将这部分的代码举例出来了:
public Map<String, String> callBack(HttpServletRequest request,
@RequestParam(value = "msg_signature", required = false) String msg_signature,
@RequestParam(value = "timestamp", required = false) String timeStamp,
@RequestParam(value = "nonce", required = false) String nonce,
@RequestBody(required = false) JSONObject json) {
try {
// 1. 从http请求中获取加解密参数
// 2. 使⽤加解密类型
// Constant.OWNER_KEY 说明:
// 1、开发者后台配置的订阅事件为应⽤级事件推送,
//      此时OWNER_KEY为应⽤的APP_KEY(企业内部应⽤)或SUITE_KEY(三⽅应⽤)。
// 2、调⽤订阅事件接⼝订阅的事件为企业级事件推送,
/
/      此时OWNER_KEY为:企业的CORP_ID(企业内部应⽤)或SUITE_KEY(三⽅应⽤)。
// 其中的DingCallBackCrypto参见github/open-dingtalk/dingtalk-callback-Crypto
DingCallbackCrypto callbackCrypto = new DingCallbackCrypto(Constant.AES_TOKEN, Constant.AES_KEY, Constant.OWNER_KEY);
String encryptMsg = String("encrypt");
String decryptMsg = DecryptMsg(msg_signature, timeStamp, nonce, encryptMsg);
// 3. 反序列化回调事件json数据
JSONObject eventJson = JSON.parseObject(decryptMsg);
String eventType = String("EventType");
// 4. 根据EventType分类处理
if ("check_url".equals(eventType)) {
// 测试回调url的正确性
bizLogger.info("测试回调url的正确性");
} else if ("user_add_org".equals(eventType)) {
// 处理通讯录⽤户增加事件
bizLogger.info("发⽣了:" + eventType + "事件");
} else {
// 添加其他已注册的
bizLogger.info("发⽣了:" + eventType + "事件");
}
// 5. 返回success的加密数据
Map<String, String> successMap = EncryptedMap("success");
return successMap;
} catch (DingTalkEncryptException e) {
e.printStackTrace();
}
return null;
}
通过官⽅⽰例,开发者已经基本上能够完成消息回调的处理。
但这仅仅是能够完成回调消息处理,我相信随着业务发展会出现很多的if...,在后续的开发维护中就变得⽐较⿇烦了,当然⼤家都会想办法将这⾥优化掉,DtJava也同样做了这个优化的⼯作。
在DtJava中,消息通过消息路由器来完成不同消息的处理。
// 消息路由器
DtMessageRouter newRouter = new DtMessageRouter(dtService);
// 通讯录⽤户增加事件
newRouter.rule().async(false).eventType("user_add_org").actUserAddHandler).end();
// 默认,记录所有事件的⽇志
newRouter.rule().async(true).handler(this.logHandler).end();
return newRouter;
消息路由器DtMessageRouter主要是从eventType来匹配不同的handler,降低系统复杂度,更多的内容可以查看Wiki,这⾥不再介绍了。
在最后再放⼀下地址:,还望⼤家能够多多Star。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。