JIRA对接钉钉群机器人-实现任务的指派通知

时间:2024-01-27 22:08:27

一、前提

Jira Software、钉钉群、RESTful服务、LDAP服务

二、流程图

 

 

 

三、对接步骤

1、创建项目群,把相关人员拉入群

2、钉钉群的智能群助手里添加自定义机器人

 

 

3、设置机器人,安全设置里建议勾选IP地址段,将RESTful服务所在的机器IP填入

 

4、注意创建完成后的Webhook地址,RESTful服务用这个地址发送通知消息,后面步骤要用上

5、RESTful服务新增一个POST接口,并部署到服务器

 1 @ApiOperation(value = "JIRA网络钩子")
 2 @PostMapping("/jiraWebHook")
 3 @ResponseBody
 4 public Result<Boolean> jiraWebHook(HttpServletRequest request) {
 5     BufferedReader br = null;
 6     String str, wholeStr = "";
 7     try {
 8         br = request.getReader();
 9 
10         while ((str = br.readLine()) != null) {
11             wholeStr += str;
12         }
13         log.info("jiraWebHook body: {}", wholeStr);
14     } catch (Exception e) {
15         log.error("jiraWebHook error", e);
16     } finally {
17         if (br != null) {
18             try {
19                 br.close();
20             } catch (Exception e) {
21             }
22         }
23     }
24     return Result.success(JiraWebHookUtil.hook(JSONObject.parseObject(wholeStr, JiraPostData.class)));
25 }
View Code
  1 @Slf4j
  2 public class JiraWebHookUtil {
  3 
  4     private static final String DING_TALK_ROBOT_URL = "https://oapi.dingtalk.com/robot/send" +
  5             "?access_token=xxxxxx";
  6     private static final String JIRA_BASE_URL = "http://xxx.xxx.xxx.xxx:38080/browse/";
  7     private static RestTemplate restTemplate = new RestTemplate();
  8 
  9     public static boolean hook(JiraPostData postData){
 10         try {
 11             if(postData != null){
 12                 if(StringUtils.equals(postData.getWebhookEvent(), "jira:issue_updated")){
 13                     //更新事件
 14                     List<Item> items = postData.getChangelog().getItems();
 15                     String toUserId = Strings.EMPTY;
 16                     String fromUserId = Strings.EMPTY;
 17                     for(Item item : items){
 18                         if(StringUtils.equals(item.getField(), "assignee")){
 19                             toUserId = item.getTo();
 20                             fromUserId = item.getFrom();
 21                             break;
 22                         }
 23                     }
 24                     if(StringUtils.isNotBlank(toUserId) && StringUtils.isNotBlank(fromUserId)){
 25                         String toMobile = getUserMobile(toUserId);
 26                         String fromMobile = getUserMobile(fromUserId);
 27                         if(StringUtils.isNotBlank(toMobile) && StringUtils.isNotBlank(fromMobile)){
 28                             String issueKey = postData.getIssue().getKey();
 29                             String issueSummary = postData.getIssue().getFields().getSummary();
 30                             DingTalkMarkdownMessage msg = new DingTalkMarkdownMessage();
 31                             msg.setMsgtype("markdown");
 32                             Markdown markdown = new Markdown();
 33                             markdown.setTitle(postData.getIssue().getKey());
 34                             markdown.setText("### @" + fromMobile + " 【转移任务给】@" + toMobile
 35                                     + "\n>任务编号:[" + issueKey + "](" + JIRA_BASE_URL + issueKey + ")"
 36                                     + "  \n任务标题:" + issueSummary);
 37                             msg.setMarkdown(markdown);
 38                             At at = new At();
 39                             at.setAtMobiles(Arrays.asList(toMobile, fromMobile));
 40                             msg.setAt(at);
 41                             return sendMsgToDingTalk(JSONObject.toJSONString(msg));
 42                         }
 43                     }
 44                 }else if(StringUtils.equals(postData.getWebhookEvent(), "jira:issue_created")){
 45                     //创建事件
 46                     String fromUserId = postData.getUser().getKey();
 47                     String toUserId = postData.getIssue().getFields().getAssignee().getKey();
 48                     if(StringUtils.isNotBlank(toUserId) && StringUtils.isNotBlank(fromUserId)){
 49                         String toMobile = getUserMobile(toUserId);
 50                         String fromMobile = getUserMobile(fromUserId);
 51                         if(StringUtils.isNotBlank(toMobile) && StringUtils.isNotBlank(fromMobile)){
 52                             String issueKey = postData.getIssue().getKey();
 53                             String issueSummary = postData.getIssue().getFields().getSummary();
 54                             DingTalkMarkdownMessage msg = new DingTalkMarkdownMessage();
 55                             msg.setMsgtype("markdown");
 56                             Markdown markdown = new Markdown();
 57                             markdown.setTitle(postData.getIssue().getKey());
 58                             markdown.setText("### @" + fromMobile + " 【指派任务给】@" + toMobile
 59                                     + "\n>任务编号:[" + issueKey + "](" + JIRA_BASE_URL + issueKey + ")"
 60                                     + "  \n任务标题:" + issueSummary);
 61                             msg.setMarkdown(markdown);
 62                             At at = new At();
 63                             at.setAtMobiles(Arrays.asList(toMobile, fromMobile));
 64                             msg.setAt(at);
 65                             return sendMsgToDingTalk(JSONObject.toJSONString(msg));
 66                         }
 67                     }
 68                 }
 69             }
 70 
 71         }catch (Exception e) {
 72             log.error("触发JIRA网络钩子失败", e);
 73         }
 74         return false;
 75     }
 76 
 77     private static boolean sendMsgToDingTalk(String msg){
 78         JSONObject postData = JSONObject.parseObject(msg);
 79         JSONObject result = restTemplate.postForObject(DING_TALK_ROBOT_URL, postData, JSONObject.class);
 80         if(result != null
 81                 && result.getIntValue("errcode") == 0
 82                 && StringUtils.equals(result.getString("errmsg"), "ok")){
 83             return true;
 84         }
 85         return false;
 86     }
 87 
 88     private static String getUserMobile(String userId){
 89         String mobile = Strings.EMPTY;
 90 
 91         Hashtable<String, String> env = new Hashtable<String, String>();
 92         env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
 93         env.put(Context.PROVIDER_URL, "ldap://xxxxxx:389");
 94         env.put(Context.SECURITY_AUTHENTICATION, "simple");
 95         env.put(Context.SECURITY_PRINCIPAL, "cn=xxx,dc=xxx,dc=xxx,dc=com");
 96         env.put(Context.SECURITY_CREDENTIALS, "xxxxxx");
 97         DirContext ctx = null;
 98         try{
 99             ctx = new InitialDirContext(env);
100         }catch(Exception e){
101             log.error("连接LDAP失败", e);
102         }
103 
104         // 设置过滤条件
105         String filter = "(&(objectClass=top)(objectClass=inetOrgPerson)(cn=" + userId + "))";
106         // 限制要查询的字段内容
107         String[] attrPersonArray = {"cn", "mobile"};
108         SearchControls searchControls = new SearchControls();
109         searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
110         // 设置将被返回的Attribute
111         searchControls.setReturningAttributes(attrPersonArray);
112         // 三个参数分别为:
113         // 上下文;
114         // 要搜索的属性,如果为空或 null,则返回目标上下文中的所有对象;
115         // 控制搜索的搜索控件,如果为 null,则使用默认的搜索控件
116         try {
117             NamingEnumeration<SearchResult> answer = ctx.search(
118                     "ou=People,dc=xxx,dc=xxx,dc=xxx", filter, searchControls);
119             // 输出查到的数据
120             while (answer.hasMore()) {
121                 SearchResult result = answer.next();
122                 Attribute attr = result.getAttributes().get("mobile");
123                 mobile = attr.get().toString();
124                 break;
125             }
126         }catch (Exception e){
127             log.error("查询LDAP用户信息失败", e);
128         }
129         return mobile;
130     }
131 
132 }
View Code

6、Jira Software配置网络钩子,使用第5步的接口地址

 

四、验证效果