上篇文章介绍了钉钉机器人消息群发功能,相对比较简单,只需要开个机器人获得推送链接和加签密钥就可以了,利用钉钉第三方平台提供的钉钉API接口,可以和钉钉产生交互,相对比较复杂。需要拥有钉钉的管理员账号。
一、准备工作
登录:
https://www.dingtalk.com/?lwfrom=2019051610283222000
1 | 用管理者账号登陆系统 |
2 | 在应用开发页面,选择企业内部开发 > 小程序,然后单击创建应用。 |
3 | 填写应用的基本信息,然后单击确定创建。 注意 请谨慎选择应用类型和开发方式,应用创建后无法修改。 |
3 | 记住key和密钥 |
4 | 在开发管理页面配置应用部署的相关配置。 调用API接口的服务器IP必须设置白名单,否则会报安全错误 |
5 | 权限管理在权限管理页面设置接口使用权限。 接口权限是以应用维度做授权,鼓励应用使用尽可能多的接口,实现与钉钉核心能力的全面互通。 |
二、生成授权凭证(access_token)
在获取access_token前,需要先获取应用的AppKey和AppSecret:
在使用access_token时,请注意:
access_token的有效期为7200秒(2小时),有效期内重复获取返回相同结果,过期后获取会返回新的access_token。
开发者需要缓存access_token,用于后续接口的调用。当access_token失效或过期时,需要重新获取。因为每个应用的access_token是彼此独立的,所以进行缓存时需要区分应用来进行存储。
不能频繁调用gettoken接口,否则会受到频率拦截
pom.xml加入json转化类
<dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.6</version> </dependency> <!--jackson json转化包--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.3</version> </dependency>
封装tkoen
package com.jyj.soft.comm;
import java.util.Date;
/**
* @class: com.jyj.soft.comm.Token
* @description: token的封装类
* @author: jiangzengkui
* @company: 教育家
* @create: 2020-12-07 20:29
*/
public class Token {
private String appId;//access_token对应的AppId
private String access_token;//访问token
public long expires_in;
private Date crea_time;//创建时间,如果当前时间比创建时间只差少于商量名,则要重新从服务器生成
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getAccess_token() {
return access_token;
}
public void setAccess_token(String access_token) {
this.access_token = access_token;
}
public long getExpires_in() {
return expires_in;
}
public void setExpires_in(long expires_in) {
this.expires_in = expires_in;
}
public Date getCrea_time() {
return crea_time;
}
public void setCrea_time(Date crea_time) {
this.crea_time = crea_time;
}
/**
* 格式化类
* @return
*/
@Override
public String toString() {
return org.apache.commons.lang.builder.ToStringBuilder.reflectionToString(this);
}
}
token工厂类
package com.xbsoft.comm.dingding.token;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiGettokenRequest;
import com.dingtalk.api.response.OapiGettokenResponse;
import com.google.gson.Gson;
import com.taobao.api.ApiException;
import com.xbsoft.comm.util.DateUtil;
import com.xbsoft.comm.util.SysConstant;
import com.xbsoft.comm.util.XBUtil;
public class TokenFactory {
//应用ID
public static final String AgentId="yyyyyyyy";
//应用key
public static final String AppKey="xxxxxxxxxx";
//#应用密钥
public static final String AppSecret="yyyyyyyy";
private static Token token=null;//key为appid
private static TokenFactory factory=null;
private TokenFactory(){
init();
}
public static TokenFactory instanceOf(){
if( factory==null)
factory=new TokenFactory();
return factory;
}
private void init(){
initToken();
}
/**
* 获得token
* @param appId
* @param appSecret
* @return
*/
public Token getTokent(){
if(token==null){
initToken();
return token;
}
if(toeknFailure()){//过期
initToken();
return token;
}
return token;
}
/**
* 从钉钉读取
*/
private void initToken(){
try {
DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
OapiGettokenRequest request = new OapiGettokenRequest();
request.setAppkey(AppKey);
request.setAppsecret(AppSecret);
request.setHttpMethod("GET");
OapiGettokenResponse response = client.execute(request);
String ret=response.getBody();
System.out.println(ret);
Map<String,Object> map=XBUtil.jsonToMap(ret);
Integer errcode=(Integer)map.get("errcode");
String errmsg=(String)map.get("errmsg");
Integer expires_in=(Integer)map.get("expires_in");
String access_token=(String)map.get("access_token");
if(errmsg==null){
errmsg="未知";
}
if(errcode==null || errcode!=0){
throw new java.lang.RuntimeException("获取token出错:"+errmsg);
}
token=new Token();
token.setAccess_token(access_token);
token.setExpires_in(expires_in.longValue());
token.setCrea_time(new Date());
} catch (ApiException e) {
throw new java.lang.RuntimeException("获取token出错:"+e.getErrMsg());
}
}
/**
* 判断token是否失效
* @return
*/
private boolean toeknFailure(){
boolean ret=true;
if(token==null)
return true;
long expires_in=token.getExpires_in();//得到有效时间长度
expires_in=expires_in-SysConstant.refresh_times;//减去提前时间
long jgTime=DateUtil.getDateBetween(new Date(), token.getCrea_time(), DateUtil.seconds);//当前日期和创建token的时间只差
if(expires_in>jgTime){//预期间隔日期大于实际间隔日期
ret=false;
}
return ret;
}
/**
* 刷新token
* @param org_id
*/
public Token refreshToken(String appId,String appSecret){
Token token=null;
return token;
}
public static void tt(){
}
public static void main(String[] args) {
Token token= TokenFactory.instanceOf().getTokent();
System.out.println("token:=="+token);
}
}
四、接口调用流程
钉钉第三方平台提供了大量API,调用这些接口的流程为
如下图所示,在调用钉钉服务端接口前,您需要完成以下准备工作:
-
添加接口调用权限。应用创建后默认只开放登录和消息通知接口的调用权限,您需要根据开发需要,添加对应的接口使用权限。详细信息,请参考添加接口调用权限。
-
获取应用的access_token。access_token相当于是身份凭证。调用接口时,通过access_token来鉴权调用者身份。详细信息,请参考获取access_token。
eg:通过用户注册手机号码获得钉钉的user_id
package com.jyj.soft.comm;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiUserGetByMobileRequest;
import com.dingtalk.api.response.OapiUserGetByMobileResponse;
import com.taobao.api.ApiException;
import java.util.Map;
/**
* @class: com.jyj.soft.comm.UserUtil
* @description: eg:通过用户注册手机号码获得钉钉的user_id
* @author: jiangzengkui
* @company: 教育家
* @create: 2020-12-07 21:04
*/
public class UserUtil {
/**
* 通过手机号码获得钉钉user_id
* @param mobile
* @return
*/
public static String getUserIdByMobile(String mobile){
//获得access_token
String access_token=TokenFactory.instanceOf().getTokent().getAccess_token();
String api_url="https://oapi.dingtalk.com/user/get_by_mobile";
String userId=null;
try {
DingTalkClient client = new DefaultDingTalkClient(api_url);
OapiUserGetByMobileRequest req = new OapiUserGetByMobileRequest();
req.setMobile(mobile);
req.setHttpMethod("GET");
OapiUserGetByMobileResponse rsp = client.execute(req, access_token);
String ret=rsp.getBody();
Map<String,Object> map=JacksonUtil.getInstance().readValue(ret, Map.class);
String errmsg=(String)map.get("errmsg");
int errcode=(Integer)map.get("errcode");
if(errcode!=0){
throw new RuntimeException("通过手机号码获得userid出错:"+errmsg);
}
userId=(String)map.get("userid");
} catch (Exception e) {
throw new RuntimeException("通过手机号码获得userid出错:"+e.getMessage());
}
return userId;
}
public static void main(String args[]){
System.out.println(getUserIdByMobile("13688006635"));
}
}
参考资料
钉钉接口说明文档
https://ding-doc.dingtalk.com/document#/org-dev-guide
钉钉接口调用示例
https://open-dev.dingtalk.com/apiExplorer#/?devType=org&api=/message/corpconversation/asyncsend_v2