java开发钉钉企业内部应用,免登授权+消息推送

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里验证使用。

java开发钉钉企业内部应用,免登授权+消息推送_第1张图片

需要引入钉钉的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的接口:

@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: 

1.出现以下问题:java开发钉钉企业内部应用,免登授权+消息推送_第2张图片

解决:检查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)
        }
    });
});

 

你可能感兴趣的:(java)