1.申请账号登操作直接看文档去申请就ok了,管理员身份登录,创建微应用
地址:https://oa.dingtalk.com/index.htm#/login
2.免登授权
CORP_ID :企业id,CORP_SECRET:企业秘钥,agentid:应用标识id
注:corp_id ,corp_secret 和 agentid 是免登必备参数,也是开发微应用和必要参数。
一:获取access_token
/**
* 在此方法中,为了避免频繁获取access_token,
* 在距离上一次获取access_token时间在两个小时之内的情况,
* 将直接从持久化存储中读取access_token
*
* 因为access_token和jsapi_ticket期时间都是7200秒
* 所以在获取access_token的同时也去获取了jsapi_ticket
* 注:jsapi_ticket是在前端页面JSAPI做权限验证配置的时候需要使用的
* 具体信息请查看开发者文档--权限验证配置
*/
public static String getAccessToken(String path) throws OApiException {
long curTime = System.currentTimeMillis();
JSONObject accessTokenValue = (JSONObject) FileUtils.getValue("accesstoken", Env.CORP_ID,path);
String accToken = "";
String jsTicket = "";
JSONObject jsontemp = new JSONObject();
if (accessTokenValue == null || curTime - accessTokenValue.getLong("begin_time") >= cacheTime) {
try
{
ServiceFactory serviceFactory = ServiceFactory.getInstance();
CorpConnectionService corpConnectionService = serviceFactory.getOpenService(CorpConnectionService.class);
accToken = corpConnectionService.getCorpToken(Env.CORP_ID, Env.CORP_SECRET);
// save accessToken
JSONObject jsonAccess = new JSONObject();
jsontemp.clear();
jsontemp.put("access_token", accToken);
jsontemp.put("begin_time", curTime);
jsonAccess.put(Env.CORP_ID, jsontemp);
FileUtils.write2File(jsonAccess, "accesstoken",path);
if(accToken.length() > 0){
JsapiService jsapiService = serviceFactory.getOpenService(JsapiService.class);
JsapiTicket JsapiTicket = jsapiService.getJsapiTicket(accToken, "jsapi");
jsTicket = JsapiTicket.getTicket();
JSONObject jsonTicket = new JSONObject();
jsontemp.clear();
jsontemp.put("ticket", jsTicket);
jsontemp.put("begin_time", curTime);
jsonTicket.put(Env.CORP_ID, jsontemp);
FileUtils.write2File(jsonTicket, "jsticket",path);
}
} catch (SdkInitException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ServiceException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ServiceNotExistException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
return accessTokenValue.getString("access_token");
}
return accToken;
}
二:获取jsapi_ticket
/**
* 正常的情况下,jsapi_ticket的有效期为7200秒,所以开发者需要在某个地方设计一个定时器,定期去更新jsapi_ticket
*/
public static String getJsapiTicket(String accessToken,String path) throws OApiException {
JSONObject jsTicketValue = (JSONObject) FileUtils.getValue("jsticket", Env.CORP_ID,path);
long curTime = System.currentTimeMillis();
String jsTicket = "";
if (jsTicketValue == null || curTime -
jsTicketValue.getLong("begin_time") >= cacheTime) {
ServiceFactory serviceFactory;
try {
serviceFactory = ServiceFactory.getInstance();
JsapiService jsapiService = serviceFactory.getOpenService(JsapiService.class);
JsapiTicket JsapiTicket = jsapiService.getJsapiTicket(accessToken, "jsapi");
jsTicket = JsapiTicket.getTicket();
JSONObject jsonTicket = new JSONObject();
JSONObject jsontemp = new JSONObject();
jsontemp.clear();
jsontemp.put("ticket", jsTicket);
jsontemp.put("begin_time", curTime);
jsonTicket.put(Env.CORP_ID, jsontemp);
FileUtils.write2File(jsonTicket, "jsticket", path);
} catch (SdkInitException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ServiceException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ServiceNotExistException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return jsTicket;
} else {
return jsTicketValue.getString("ticket");
}
}
四:计算签名信息
public static String sign(String ticket, String nonceStr, long timeStamp, String url) throws OApiException {
String plain = "jsapi_ticket=" + ticket + "&noncestr=" + nonceStr + "×tamp=" + String.valueOf(timeStamp)
+ "&url=" + url;
try {
MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
sha1.reset();
sha1.update(plain.getBytes("UTF-8"));
return bytesToHex(sha1.digest());
} catch (NoSuchAlgorithmException e) {
throw new OApiResultException(e.getMessage());
} catch (UnsupportedEncodingException e) {
throw new OApiResultException(e.getMessage());
}
}
private static String bytesToHex(byte[] hash) {
Formatter formatter = new Formatter();
for (byte b : hash) {
formatter.format("%02x", b);
}
String result = formatter.toString();
formatter.close();
return result;
}
五:获取权限信息的方法,以备获取权限的接口调用,获取到权限信息放到js里验证
public static String getConfig(HttpServletRequest request) {
String urlString = request.getRequestURL().toString();
String queryString = request.getQueryString();
String queryStringEncode = null;
String url;
if (queryString != null) {
queryStringEncode = URLDecoder.decode(queryString);
url = urlString + "?" + queryStringEncode;
} else {
url = urlString;
}
String nonceStr = "abcdefg";
long timeStamp = System.currentTimeMillis() / 1000;
String signedUrl = url;
String accessToken = null;
String ticket = null;
String signature = null;
String agentid = null;
try {
String path = request.getServletContext().getRealPath("/");
accessToken = AuthHelper.getAccessToken(path);
ticket = AuthHelper.getJsapiTicket(accessToken,path);
signature = AuthHelper.sign(ticket, nonceStr, timeStamp, signedUrl);
agentid = "xxxxxxxx";
} catch (OApiException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String configValue = "{jsticket:'" + ticket + "',signature:'" + signature + "',nonceStr:'" + nonceStr + "',timeStamp:'"
+ timeStamp + "',corpId:'" + Env.CORP_ID + "',agentid:'" + agentid+ "'}";
return configValue;
}
注:以上代码钉钉demo文档里有,需要引入钉钉的lib包,lib包在demo里。
六:controller层写接口供js里调用
@Controller
@RequestMapping("api/authHelperApi/")
public class AuthHelperController {
@RequestMapping("getAuth")
@ResponseBody
public String getAuth(HttpServletRequest request){
//AuthHelper 就是上面方法的类
return AuthHelper.getConfig(request);
}
}
七:在加载的首页index.html页面,获取权限信息,放到js里验证使用。
需要引入钉钉的js文件:http://g.alicdn.com/ilw/ding/0.7.3/scripts/dingtalk.js
注:以上js要放在head里引入,保证首先加载。
定义的全局变量_config,放到demo.js里验证使用。
dd.runtime.permission.requestAuthCode({
corpId : _config.corpId,
onSuccess : function(info) {
$.ajax({
url:'/DingTask/api/ding/userInfo?code=' + info.code + '&corpid='
+ _config.corpId,
type : 'GET',
success : function(userId) {
if (userId != null && userId != ""){
userId = userId.replace("\"","");
var storage=window.localStorage;
//写入缓存
storage["userId"] = userId;
}
},
error : function(xhr, errorType, error) {
alert(errorType + ', ' + error);
}
});
},
onFail : function(err) {
alert('fail: ' + JSON.stringify(err));
}
});
通过code和corp_id 获取用户信息,我是获取userId,把userId存入前端缓存,以备其他页面和接口使用。
var storage=window.localStorage;
//写入缓存
storage["userId"] = userId;
以上是写缓存的方法,非常好用。
如:在需要的页面取userId,
从缓存取userId
var storage=window.localStorage;
var id = storage.userId;
获取userId的接口:
@RequestMapping(value = "userInfo", method = RequestMethod.GET)
@ResponseBody
public String userInfo(HttpServletRequest request, HttpServletResponse response) throws IOException {
// TODO Auto-generated method stub
String code = request.getParameter("code");
String corpId = request.getParameter("corpid");
String userId = null;
try {
response.setContentType("text/html; charset=utf-8");
String path = request.getServletContext().getRealPath("/");
String accessToken = AuthHelper.getAccessToken(path);
userId = UserHelper.getUserInfo(accessToken, code).getUserid();
/*CorpUserDetail user = (CorpUserDetail) UserHelper.getUser(accessToken, userId);
DdAdmin user1 = adminService.selectByUserId(user.getUserid());
request.getSession().setAttribute("userInfo", user);
request.getSession().setAttribute("user", user1);*/
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
/*response.getWriter().append(e.getMessage());*/
}
if (userId != null && userId != ""){
return userId;
}else {
return "";
}
}
至此免登并获取userId(或者其他的数据)就结束了。
3. 消息推送
我需要发送的oa消息,其他类型消息可以参照文档:
https://open-doc.dingtalk.com/microapp/serverapi2/pgoxpy
需要引入jar包:taobao-sdk-java-auto_1479188381469-20181204.jar ,以下是代码,在需要发送消息的接口里直接调用即可。
public static boolean send(HttpServletRequest req, String title, String useridList, List forms, String author) {
DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2");
OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request();
request.setUseridList(useridList);
request.setAgentId(208740242L);
request.setToAllUser(false);
OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg();msg.setOa(new OapiMessageCorpconversationAsyncsendV2Request.OA());
msg.getOa().setHead(new OapiMessageCorpconversationAsyncsendV2Request.Head());
msg.getOa().getHead().setText("我的任务");
msg.getOa().getHead().setBgcolor("FFBBBBBB");
msg.getOa().setBody(new OapiMessageCorpconversationAsyncsendV2Request.Body());
msg.getOa().getBody().setTitle(title);
msg.getOa().getBody().setForm(forms);
msg.getOa().getBody().setAuthor(author);
msg.setMsgtype("oa");
request.setMsg(msg);
String path = req.getServletContext().getRealPath("/");
String token = null;
try {
token = getAccessToken(path);
} catch (OApiException e) {
e.printStackTrace();
}
OapiMessageCorpconversationAsyncsendV2Response response = null;
try {
response = client.execute(request,token);
} catch (ApiException e) {
e.printStackTrace();
}
if (response != null){
return true;
}else {
return false;
}
}
ps:
解决:检查sign ,签名方法里 url是否为当前请求页面的url,98%出现此问题的原因都是url错误,如果错误,可以把请求的页面url动态加到sign方法里请求。
2.使用钉钉jsAPI里的方法,我使用的一个获取钉钉里组织列表选人的方法,如下:
ps:有的是需要dd.config()的,有的则不需要,如果需要,必须鉴权通过才可以调用。
在js里给html页面需要选择人的地方,给个点击事件,调用此方法,即可跳出钉钉组织架构选人的页面。
dd.ready(function() { dd.biz.contact.complexPicker({ title: "选择责任人", //标题 corpId: _config.corpId, //企业的corpId multiple: false, //是否多选 limitTips: "超出了", //超过限定人数返回提示 maxUsers: 1000, //最大可选人数 pickedUsers: [], //已选用户 pickedDepartments: [], //已选部门 disabledUsers: [], //不可选用户 disabledDepartments: [], //不可选部门 requiredUsers: [], //必选用户(不可取消选中状态) requiredDepartments: [], //必选部门(不可取消选中状态) appId: _config.corpId, //微应用的Id permissionType: "GLOBAL", //选人权限,目前只有GLOBAL这个参数 responseUserOnly: false, //返回人,或者返回人和部门 startWithDepartmentId: 0, // 0表示从企业最上层开始,IOS不支持该字段 onSuccess: function (result) { $("#accepter").html(result.users[0].name); $("#accepterId").html(result.users[0].emplId); queryStr = "&assignedTo=" + result.users[0].emplId; //tableList(queryStr); if(id == '1111'){ queryStr = "?assignedTo=" + result.users[0].emplId; } $.ajax({ url: ajaxUrl + queryStr, type:'post', dataType:'json', success:function(data){ var tr; if (data == null || data == ""){ tr = '' + "" + ' ' + '' + "" + ' ' + '' + "" + ' ' + '' + "" + ' '; $("#tableList").html('' + tr + ' ') }else { $("#tableList").html(''); for (var i in data) { tr = '' + data[i].assignedToName + ' ' + '' + data[i].notCount + ' ' + '' + data[i].overDueCount + ' ' + '' + data[i].onDueCount + ' '; $("#tableList").append('' + tr + ' ') } } } }) }, onFail: function (err) { var jsonData = JSON.stringify(err);// 转成JSON格式 alert(jsonData) } }); });