当前位置: 首页 > 工具软件 > JIRA-Client > 使用案例 >

使用Java client对接jira api

乌甫
2023-12-01

通过java程序,实现在jira上增删改查项目、issue等操作。

一、使用curl的方式直接调用jira api(非本文重点)

参考资料:https://docs.atlassian.com/software/jira/docs/api/REST/7.7.1/#api/2

上面记录了各种操作的需要调用的url 以及请求类型。
使用方式就像这样:

public static String getIssue(String issueKey) throws IOException {
        String command = "curl -D- -u " + user + ":" + pwd
                + " -X GET -H \"Content-Type: application/json\" \"" + uri
                + "/rest/api/2/issue/" + issueKey + "\"";

        String issueSt = executeShell(command);
        return issueSt;
    }

    public static String getProject(String projectKey) throws IOException{
        String command = "curl -D- -u " + user + ":" + pwd
                + " -X GET -H \"Content-Type: application/json\" \"" + uri
                + "/rest/api/2/project/" + projectKey + "\"";

        String projectSt = executeShell(command);
        return projectSt;
    }

相当于直接在命令执行命令:

curl --request GET \
  --url '/rest/api/2/project/{projectIdOrKey}' \
  --user 'email@example.com:<api_token>' \
  --header 'Accept: application/json'

这种方式网上有类似的工具类,但是使用起来感觉不是很方便,尤其是一些创建更新操作,需要很多参数,这种拼装的方式很容易出错,好在jira提供了java版的客户端。

二、使用jira-rest-java-client操作jira

1、引入依赖
  <properties>
    <jira-client.version>5.1.6</jira-client.version>
    <alibaba-fastjson.version>1.2.68</alibaba-fastjson.version>
    <atlassian-fugue.version>4.7.2</atlassian-fugue.version>
    <guava.version>26.0-jre</guava.version>
  </properties>

  <!--jira java-->
      <dependency>
        <groupId>com.atlassian.jira</groupId>
        <artifactId>jira-rest-java-client-core</artifactId>
        <version>${jira-client.version}</version>
      </dependency>
      <dependency>
        <groupId>io.atlassian.fugue</groupId>
        <artifactId>fugue</artifactId>
        <version>${atlassian-fugue.version}</version>
      </dependency>
      <!--  http client-->
      <dependency>
        <groupId>com.mashape.unirest</groupId>
        <artifactId>unirest-java</artifactId>
        <version>1.4.9</version>
      </dependency>
      <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>${alibaba-fastjson.version}</version>
      </dependency>

      <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>${guava.version}</version>
      </dependency>
2、基本操作

通过java client使用起来也很简单
先通过jira地址,用户名,密码创建要给JiraRestClient。

private static JiraRestClient loginJira(String url,String userName,String pwd){
        AsynchronousJiraRestClientFactory asynchronousJiraRestClientFactory = new AsynchronousJiraRestClientFactory();
        JiraRestClient jiraRestClient = asynchronousJiraRestClientFactory.createWithBasicHttpAuthentication(URI.create(url), userName,pwd);
        return jiraRestClient;
    }

这个client里面有操作jira的各种客户端

public interface JiraRestClient extends Closeable {
    /**
     * @return com.atlassian.jira.rest.client.api for performing operations on selected issue
     */
    IssueRestClient getIssueClient();

    /**
     * @return the com.atlassian.jira.rest.client.api handling session information
     */
    SessionRestClient getSessionClient();

    //后面的省略了
    /**
     * Destroys this instance of JIRA Rest Client.
     *
     * @throws IOException if there is a problem closing this client.
     */
    void close() throws IOException;
}

上代码(简单的自测代码,还没有做到当工具类适用),部分注意点都写了注释
官方参考文档:
https://developer.atlassian.com/cloud/jira/platform/rest/v2/

package com.stwl.jira.util;

import com.alibaba.fastjson.JSON;
import com.atlassian.jira.rest.client.api.JiraRestClient;
import com.atlassian.jira.rest.client.api.domain.*;
import com.atlassian.jira.rest.client.api.domain.input.*;
import com.atlassian.jira.rest.client.internal.async.AsynchronousJiraRestClientFactory;
import com.google.common.collect.Lists;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;

import com.stwl.jira.model.TransitionStatusEnum;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 
 * @date 2020/4/26 9:19
 */
public class JiraUtils2 {
    private static final Logger logger = LoggerFactory.getLogger(JiraUtils2.class);
    private static final String url = "http://my.jira.com:8080";
    static String user = "user" ;
    static String pwd ="pwd.";

    private static final String PROJECT_KEY = "ADTEST";

    public static void main(String[] args) throws UnirestException, FileNotFoundException {
          getIssue("ADTEST-3");
//        getIssue("OAGJXT-1");
//        createIssue( "新创建issue描述", "新创建issue主题");
//       updateIssue("ADTEST-2");
//        deleteIssue("ADTEST-1");
//        changeStatus("ADTEST-1");
//        addCommon("ADTEST-1");
//        getProject(PROJECT_KEY);
//        createSubTask("创建子任务描述", "创建子任务主题","ADTEST-2");
//        getIssueAllTypes();
//        addAttachment("ADTEST-2", "D:/项目文件/test.txt");
//        ProjectInfo projectInfo = ProjectInfo.Builder.projectInfo().setName("").build();
 

    }

     /**
     * 通过issueKey获取issue
     * @param issueKey
     * @return
     */
    public static Issue getIssue(String issueKey) {
        JiraRestClient restClient = loginJira(url, user, pwd);
        Issue issue = restClient.getIssueClient().getIssue(issueKey).claim();
        logger.info(JSON.toJSONString(issue));
        return issue;

    }


    /**
     * 创建issue:description ,summary,projectKey,issueType,是必须要有的
     * @param map
     */
    public static void createIssue(Map<String,Object> map) throws IOException {
        JiraRestClient restClient = loginJira(url, user, pwd);
        IssueInputBuilder builder = new IssueInputBuilder();
        builder.setDescription(map.get(IssueFieldId.DESCRIPTION_FIELD.id).toString());
        builder.setSummary(map.get(IssueFieldId.SUMMARY_FIELD.id).toString());
        builder.setProjectKey(PROJECT_KEY);
        builder.setFieldInput(new FieldInput(IssueFieldId.ISSUE_TYPE_FIELD, ComplexIssueInputFieldValue.with("name", "任务")));
        builder.setFieldInput(new FieldInput(IssueFieldId.PRIORITY_FIELD, ComplexIssueInputFieldValue.with("name", "不重要不紧急")));
//如果还需要一些其他信息,可以按照上面的build继续构造,想要知道IssueFieldId对应哪些数据,
//我们可以通过getIssue()方法获取一个issue有哪些数据,然后对照着构建。

        IssueInput issueInput = builder.build();
        try {
            BasicIssue issue = restClient.getIssueClient().createIssue(issueInput).claim();
            logger.info(JSON.toJSONString(issue));
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            restClient.close();
        }
    }

/**
     * 创建子任务 
     * @param description
     * @param summary
     * @param parentIssueKey
     */
    public static void createSubTask(String description,String summary,String parentIssueKey){
        JiraRestClient restClient = loginJira(url, user, pwd);
        IssueInputBuilder builder = new IssueInputBuilder();
        builder.setDescription(description);
        builder.setSummary(summary);
        builder.setProjectKey(PROJECT_KEY);
        builder.setFieldInput(new FieldInput(IssueFieldId.ISSUE_TYPE_FIELD, ComplexIssueInputFieldValue.with("name", "子任务")));
        builder.setFieldInput(new FieldInput(IssueFieldId.PRIORITY_FIELD, ComplexIssueInputFieldValue.with("name", "不重要不紧急")));
        //创建子任务需要指定父任务的issuekey
        builder.setFieldInput(new FieldInput("parent", ComplexIssueInputFieldValue.with("key", parentIssueKey)));

        IssueInput issueInput = builder.build();
        BasicIssue issue = restClient.getIssueClient().createIssue(issueInput).claim();
        logger.info(JSON.toJSONString(issue));
      
    }

 /**
     * 更新issue
     * @param issueKey,下面需要更新的数据现在代码里是写死了,真正用的时候以参数的形式传进去
     */
    public static void updateIssue(String issueKey) {
        JiraRestClient restClient = loginJira(url, user, pwd);

        IssueInputBuilder builder = new IssueInputBuilder();
        //设置项目key然后才能修改
        builder.setProjectKey(PROJECT_KEY);
//        builder.setDescription("通过java更新issue描述");
        //优先级
        builder.setFieldInput(new FieldInput("priority", ComplexIssueInputFieldValue.with("name", "不重要不紧急")));
        //经办人
//        builder.setFieldInput(new FieldInput("assignee", ComplexIssueInputFieldValue.with("name", "liuwei01")));
        restClient.getIssueClient().updateIssue(issueKey, builder.build()).claim();
    }

    /**
     * 改变工作状态:如果接受任务--开始任务--完成任务
     * 接受任务必须要哪些参数都可以通过jira页面查看,他要你必填哪些信息。和我们通过接口调用是一致的
     * @param issueKey
     */
    public static void changeStatus(String issueKey) {
        JiraRestClient restClient = loginJira(url, user, pwd);
        Issue issue = getIssue(issueKey);
         //查询进度转变
        Iterable<Transition> transitions = restClient.getIssueClient().getTransitions(issue).claim();
        logger.info(JSON.toJSONString(transitions));

        List<FieldInput> fieldInputList = new ArrayList<>();
        //接受任务
//        fieldInputList.add(new FieldInput("customfield_10200", "2020-04-26"));
//        fieldInputList.add(new FieldInput("customfield_10201", 4));
        //实际工作量
        fieldInputList.add(new FieldInput("customfield_10202", 4));
        //完成度
//        fieldInputList.add(new FieldInput("customfield_10203", "-1"));
//这里需要注意的是issue返回的信息里面有很多customfield_10203这样类型的字段,
//具体含义需要我们去尝试、猜测,我总结了部分字段的含义,搞了个枚举,在后面贴出

        TransitionInput transitionInput = new TransitionInput(TransitionStatusEnum.SOLUTION_TASK.getCode(), fieldInputList);
        restClient.getIssueClient().transition(issue, transitionInput).claim();
    }

    /**
     * 增加注释 评论
     * @param issueKey
     */
    public static void addCommon(String issueKey) {
        JiraRestClient restClient = loginJira(url, user, pwd);
        Comment comment = Comment.valueOf("one more time");
        Issue issue = getIssue(issueKey);
        URI uri = issue.getCommentsUri();
        logger.info(uri.toString());
        restClient.getIssueClient().addComment(uri,comment);
        try {
            restClient.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
 /**
     * 获取项目信息
     * @param projectKey
     */
    public static void getProject(String projectKey) {
        JiraRestClient restClient = loginJira(url, user, pwd);
        Project project = restClient.getProjectClient().getProject(projectKey).claim();
        logger.info(JSON.toJSONString(project));
    }

 /**
     * 创建项目 这个在 getProjectClient()里面居然没有创建方法。就只能使用发送http请求的形式了。
     * @param description 描述
     * @param name  项目名
     * @param key 项目的key。自己设置
     * @param user 用户名 搞一个有创建项目权限的账号
     * @param pwd  密码
     * @param projectTypeKey 有效值:software, service_desk, business
     */
    public static void createProject(String description,String name,String key,
                                     String user,String pwd,String projectTypeKey) throws IOException{
        Map<String, Object> map = new HashMap<>();
        map.put("description",description);
        map.put("name",name);
        map.put("key", key);
        map.put("projectTypeKey",projectTypeKey);
        map.put("lead","chenjing");
        try {
        //下面这个Unirest也是参考官方文档使用的,其实内部封装是apache httpclient,简化了使用
            HttpResponse<JsonNode> response = Unirest.post(url + "/rest/api/2/project")
                    .basicAuth(user, pwd)
                    .header("Accept", "application/json")
                    .header("Content-Type", "application/json")
                    .body(JSON.toJSONString(map))
                    .asJson();
            System.out.println(response.getBody());
        } catch (UnirestException e) {
            e.printStackTrace();
        }
    }

 /**
     * 通过projectKey删除 项目
     * @param projectKey
     * @param user
     * @param pwd
     * @throws UnirestException
     */
    public static void deleteProject(String projectKey, String user, String pwd) throws UnirestException {
        HttpResponse<String> response = Unirest.delete(url + "/rest/api/2/project/" + projectKey)
                .basicAuth(user, pwd)
                .asString();
        logger.info(response.getBody());
    }

  

    /**
     * 上传附件
     */
  /*  public static void addAttachment(String issueKey,String filePath) throws FileNotFoundException {
        Issue issue = getIssue(issueKey);
        JiraRestClient restClient = loginJira(url, user, pwd);
        File file = new File(filePath);
        FileInputStream inputStream = new FileInputStream(file);
        restClient.getIssueClient().addAttachment(issue.getAttachmentsUri(),inputStream, file.getName());
    }*/

    public static String getIssueAllTypes() throws UnirestException {
        HttpResponse<JsonNode> response = Unirest.get(url+"/rest/api/2/issuetype")
                .basicAuth(user, pwd)
                .header("Accept", "application/json")
                .asJson();
        System.out.println(response.getBody());

        return response.getBody().toString();
    }

/**
     * 删除issue,需要权限
     * @param issueKey
     */
    public static void deleteIssue(String issueKey) {
        JiraRestClient restClient = loginJira(url, user, pwd);
        restClient.getIssueClient().deleteIssue(issueKey,true);
    }
    private static JiraRestClient loginJira(String url,String userName,String pwd){
        AsynchronousJiraRestClientFactory asynchronousJiraRestClientFactory = new AsynchronousJiraRestClientFactory();
        JiraRestClient jiraRestClient = asynchronousJiraRestClientFactory.createWithBasicHttpAuthentication(URI.create(url), userName,pwd);
        return jiraRestClient;
    }
}

附上一个枚举

package com.stwl.jira.model;

/**
 * @author 
 * @date 2020/4/26 15:38
 */
public enum TransitionStatusEnum {
    ACCEPT_TASK(11, "接受任务"),
    REFUSE_TASK(51, "拒绝任务"),
    START_TASK(21, "开始任务"),
    SOLUTION_TASK(31, "解决任务"),
    AFTER_ACCEPT_HANG_UP_TASK(71, "接受任务后挂起任务"),
    AFTER_START_HANG_UP_TASK(91, "开始任务后挂起任务"),
    RESTART_TASK(81, "重新开始任务"),
    ;

    private Integer code;
    private String desc;

    TransitionStatusEnum(Integer code, String desc) {
        this.code = code;
        this.desc = desc;
    }

    public Integer getCode() {
        return code;
    }

    public String getDesc() {
        return desc;
    }

}

附上一个issueinfo类:

package com.stwl.jira.model;

/**
 * @author 
 * @date 2020/4/26 13:25
 */
public class IssueInfo {

    /**
     * 任务标题
     */
    private String summary;

    /**
     * 描述
     */
    private String description;

    /**
     * issue key
     */
    private String key;

    /**
     * 优先级  紧急重要、紧急不重要、重要不紧急、不重要不紧急 name属性
     */
    private String priority;

    /**
     * 状态 新建,处理中,已完成
     */
    private String status;

    /**
     * 解决结果
     */
    private String resolution;

    /**
     * 经办人 通过name属性设置经办人
     */
    private String assignee;

    /**
     * 报告人
     */
    private String reporter;

    /**
     * 开始日期
     */
    private String customfield_10200;

    /**
     * 预计工时 整形
     */
    private String customfield_10201;

    /**
     * 完成度
     */
    private String customfield_10203;

    /**
     * 实际工作量
     */
    private String customfield_10202;
}

 类似资料: