本人在单位做了一个简单的HR招聘管理系统,后续扩展打算将此系统与公司管理系统——钉钉 相结合,于是从钉钉官网的开放API出发,对钉钉的对接有了一个简单的了解。
根据人事的需求场景,本人需要用到钉钉API的功能主要有:
授权:获取access_token
信息:员工信息、组织机构信息、入职人员添加
功能:消息通知、审批
将公司钉钉所有员工信息同步到HR招聘管理系统,以组织机构展示花名册,同时在HR招聘管理系统里修改员工信息,修改时与钉钉上的员工信息保持同步,也满足修改组织机构信息,人员部门变更等相关功能。
注:此功能,我在数据库中未存储任何数据,展示钉钉API接口获取的数据,通过钉钉API接口修改数据。
登录钉钉管理后台,创建应用
创建成功后,进入应用详情页,找到appKey和appSecret
注:大部分接口的调用都依赖于access_token,而access_token有效期为7200秒,有效期内重复获取返回相同结果,并自动续期。
可以将access_token放入缓存,减少接口调用频率。
请求说明:
返回说明:
请求说明:
返回说明:
请求说明:
参数说明:
返回说明:
请求说明:
参数说明:
返回说明:
请求说明:
返回说明:
请求说明:
返回说明:
HR招聘管理系统中,可以以钉钉消息推送的方式提前提醒相应面试官进行准备,面试结束后,也会提醒相关人员进行审核,并会发起相应的审核流程对应聘人员进行审核。
请求说明:
参数说明:
名称 | 类型 | 是否必须 | 示例值 | 描述 |
---|---|---|---|---|
agent_id | Number | 必须 | 1234 | 企业自建应用是微应用agentId,第三方应用是通过获取授权企业的应用信息接口/service/get_agent获取到的agentId |
userid_list | String | 可选(userid_list,dept_id_list, to_all_user必须有一个不能为空) | zhangsan,lisi | 接收者的用户userid列表,最大列表长度:20 |
dept_id_list | String | 可选 | 123,456 | 接收者的部门id列表,最大列表长度:20, 接收者是部门id下(包括子部门下)的所有用户 |
to_all_user | Boolean | 可选 | false | 是否发送给企业全部用户(ISV不能设置true) |
msg | json对象 | 必须 | {"msgtype":"text","text":{"content":"消息内容"}} | 消息内容,具体见“消息类型与数据格式”。最长不超过2048个字节 |
返回说明:
请求说明:
参数说明:
返回说明:
HR招聘管理系统以钉钉方式进行扫码登录(第三方登录),然后以钉钉的角色进行权限管理,
例如:HR主管:可以查看所有信息
Java主管:可以查看Java面试人员的信息,以及Java试题的维护等相关功能
方法一:直接使用钉钉提供的扫码登录页面
方法二:网站将钉钉登录二维码内嵌到自己页面中
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiDepartmentListRequest;
import com.dingtalk.api.request.OapiGettokenRequest;
import com.dingtalk.api.request.OapiMessageCorpconversationAsyncsendV2Request;
import com.dingtalk.api.request.OapiUserSimplelistRequest;
import com.dingtalk.api.response.OapiDepartmentListResponse;
import com.dingtalk.api.response.OapiGettokenResponse;
import com.dingtalk.api.response.OapiMessageCorpconversationAsyncsendV2Response;
import com.dingtalk.api.response.OapiUserSimplelistResponse;
import com.taobao.api.ApiException;
import com.xxx.ding.util.LocalCacheClient;
public class DingUtil {
private final static String APPKEY ="";
private final static String APPSECRET="";
private final static Long AGENTID = 0L;
//获取token
public static String getToken (){
Object object = LocalCacheClient.get("access_token");
if(object != null){
return object.toString();
}
DefaultDingTalkClient client = new
DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
OapiGettokenRequest request = new OapiGettokenRequest();
request.setAppkey(APPKEY);
request.setAppsecret(APPSECRET);
request.setHttpMethod("GET");
try {
OapiGettokenResponse response = client.execute(request);
LocalCacheClient.set("access_token", response.getAccessToken(),7200*1000);
return response.getAccessToken();
} catch (ApiException e) {
e.printStackTrace();
}
return null;
}
//获取部门列表
public static Object getDepartment(){
DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/department/list");
OapiDepartmentListRequest request = new OapiDepartmentListRequest();
//获取根部门下所有部门列表 根部门的部门id为1
request.setId("1");
request.setHttpMethod("GET");
try {
OapiDepartmentListResponse response = client.execute(request, DingUtil.getToken());
return response;
} catch (ApiException e) {
e.printStackTrace();
}
return null;
}
//获取部门下的所有用户列表
public static Object getDepartmentUser(Long departmentId){
DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/user/simplelist");
OapiUserSimplelistRequest request = new OapiUserSimplelistRequest();
request.setDepartmentId(departmentId);
request.setOffset(0L);
request.setSize(10L);
request.setHttpMethod("GET");
try {
OapiUserSimplelistResponse response = client.execute(request, DingUtil.getToken());
return response;
} catch (ApiException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
//给用户推送消息(文字消息)
public static Object pushUser(String userIds,String content){
DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2");
OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request();
request.setUseridList(userIds);
request.setAgentId(AGENTID);
request.setToAllUser(false);
OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg();
msg.setMsgtype("text");
msg.setText(new OapiMessageCorpconversationAsyncsendV2Request.Text());
msg.getText().setContent(content);
request.setMsg(msg);
try {
OapiMessageCorpconversationAsyncsendV2Response response = client.execute(request,DingUtil.getToken());
return response;
} catch (ApiException e) {
e.printStackTrace();
}
return null;
}
}
package com.xxx.ding.util;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class LocalCacheClient {
// 缓存map
private static Map cacheMap = new HashMap();
// 缓存有效期map
private static Map expireTimeMap = new HashMap();
/**
* 获取指定的value,如果key不存在或者已过期,则返回null
* @param key
* @return
*/
public static Object get(String key) {
if (!cacheMap.containsKey(key)) {
return null;
}
if (expireTimeMap.containsKey(key)) {
if (expireTimeMap.get(key) < System.currentTimeMillis()) { // 缓存失效,已过期
return null;
}
}
return cacheMap.get(key);
}
/**
* @param key
* @param
* @return
*/
public static T getT(String key) {
Object obj = get(key);
return obj == null ? null : (T) obj;
}
/**
* 设置value(不过期)
* @param key
* @param value
*/
public static void set(String key, Object value) {
cacheMap.put(key, value);
}
/**
* 设置value
* @param key
* @param value
* @param millSeconds 过期时间(毫秒)
*/
public static void set(final String key, Object value, int millSeconds) {
final long expireTime = System.currentTimeMillis() + millSeconds;
cacheMap.put(key, value);
expireTimeMap.put(key, expireTime);
if (cacheMap.size() > 2) { // 清除过期数据
new Thread(new Runnable() {
public void run() {
// 此处若使用foreach进行循环遍历,删除过期数据,会抛出java.util.ConcurrentModificationException异常
Iterator> iterator = cacheMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry entry = iterator.next();
if (expireTimeMap.containsKey(entry.getKey())) {
long expireTime = expireTimeMap.get(key);
if (System.currentTimeMillis() > expireTime) {
iterator.remove();
expireTimeMap.remove(entry.getKey());
}
}
}
}
}).start();
}
}
/**
* key是否存在
* @param key
* @return
*/
public static boolean isExist(String key) {
return cacheMap.containsKey(key);
}
}
首先 下载钉钉的jar包,导入项目中。(可以自行根据API文档通过httpclient进行接口调用,然后自己获取返回信息进行序列化)
其次 完善必备参数APPKEY、APPSECRET、AGENTID
最后 token要进行缓存 不要每次调用 有限制(存入本地缓存即可,此项目中LocalCacheClient类作为缓存处理,项目中如果有redis等存储数据库也可以使用)
流程梳理 由于钉钉并没有直接获取所有用户信息的接口,所以需要通过接口获取全部部门信息,
然后再调用接口获取该部门下所有的用户信息,最后可以根据用户id进行消息推送
(消息推送的种类很多,不在此一一列举,API文档中有详细说明)