Создание сервлета CRUD задач Jira и поиск задач

Применимость

Этот учебник применяется к Jira 7.0.0 и более поздним версиям.

Уровень опыта

Intermediate. Вы должны были пройти хотя бы один учебник для начинающих, прежде чем работать с этим учебником. См. Список учебников для разработчиков.

Время завершения:

Для завершения этого урока вам потребуется около 1 часа.

 

Обзор учебника

В этом руководстве вы найдете инструкции по разработке приложения, которое может выполнять операции CRUD в проекте Jira. В учебнике вы создадите сервлет, который представляет страницу в Jira, где пользователи могут:

  • Создать задачу.
  • Изменить задачу.
  • Удалить задачу.

В дополнение к CRUD-операциям, этот учебник демонстрирует, как использовать модуль сервлета для выполнения простого списка задач с интерфейсами IssueService и SearchService.

Завершенное приложение будет состоять из следующих компонентов:

  1. Java-классы, инкапсулирующие логику приложения.
  2. Ресурсы для отображения пользовательского интерфейса приложения.
  3. Дескриптор приложения (то есть XML-файл), чтобы включить модуль плагина в приложении Atlassian.

Когда вы закончите, все эти компоненты будут упакованы в один JAR-файл.

Об этих инструкциях

Вы можете использовать любую поддерживаемую комбинацию операционной системы и IDE для создания этого приложения. Эти инструкции были написаны с использованием macOS Sierra и IntelliJ IDEA 2017.3. Если вы используете другую операционную систему или комбинацию IDE, вы должны использовать эквивалентные операции для своей конкретной среды.

Этот учебник был последний раз проверен с помощью Jira 7.7.1 с использованием Atlassian Plugin SDK 6.3.10.

Прежде чем вы начнете

Чтобы завершить этот учебник, вам необходимо знать следующее:

  1. Основы разработки Java: классы, интерфейсы, методы, использование компилятора и т. д.
  2. Как создать проект Atlassian plugin с помощью Atlassian Plugin SDK.
  3. Основы администрации Jira.

Источник приложения

Мы рекомендуем вам проработать этот учебник. Если вы хотите пропустить или проверить свою работу, когда закончите, вы можете найти исходный код приложения на Atlassian Bitbucket.

 

Чтобы клонировать репозиторий, выполните следующую команду:


git clone https://bitbucket.org/atlassian_tutorial/tutorial-jira-simple-issue-crud

Кроме того, вы можете загрузить исходный код в виде ZIP-архива.

Шаг 1. Создайте проект приложения

На этом этапе вы будете использовать две команды atlas для создания кода-заглушки для вашего приложения. atlas-команды являются частью Atlasian Plugin SDK и автоматизируют большую часть разработки приложений для вас.

  1. Настройте SDK Atlassian Plugin и создайте проект, если вы этого еще не сделали.
  2. Откройте терминал и перейдите в каталог, в котором вы хотите сохранить код приложения.
  3. Чтобы создать исходные файлы проекта и исходный код приложения Jira, выполните следующую команду:

atlas-create-jira-plugin

  1. Чтобы определить приложение, введите следующую информацию.

group-id

com.example.plugins.tutorial

artifact-id

tutorial-jira-simple-issue-crud

version

1.0-SNAPSHOT

package

com.example.plugins.tutorial

  1. Подтвердите свои записи при появлении запроса.
  2. Перейдите в каталог, созданный с помощью SDK.

cd tutorial-jira-simple-issue-crud

  1. Удалите автоматически созданные тестовые каталоги.

rm -rf ./src/test/java
rm -rf ./src/test/resources/

  1. Удалите ненужные файлы классов Java.

rm -rf ./src/main/java/com/example/plugins/tutorial/*

  1. Импортируйте проект в свою избранную среду IDE.

 

Шаг 2. Просмотрите и настройте (по желанию) сгенерированный код

Это хорошая идея, чтобы ознакомиться с кодом приложения заглушки. На этом этапе мы проверим значение версии и настроим созданный класс заглушки.

Добавить метаданные приложения к POM

POM (то есть файл определения объектной модели проекта) расположен в корне вашего проекта и объявляет зависимости проекта и другую информацию.

На этом этапе вы добавите некоторые метаданные о своем приложении и вашей компании или организации в POM.

  1. Перейдите в корневую папку и откройте файл pom.xml.
  2. Добавьте название организации или организации и URL вашего веб-сайта в элемент organization:

<organization>
    <name>Example Company</name>
    <url>http://www.example.com/</url>
</organization>

  1. Обновите элемент description:


<description> Этот плагин демонстрирует, как выполнять основные операции CRUD по проблемам JIRA с использованием интерфейса IssueService и SearchService через модуль сервлета. </ description>

  1. Сохраните файл.

Просмотрите созданный дескриптор приложения

Ваш код заглушки содержит файл дескриптора приложения atlassian-plugin.xml. Это XML-файл, который идентифицирует приложение для хоста приложения (то есть для Jira) и определяет требуемые функциональные возможности приложения.

  1. В своей среде IDE перейдите к src / main / resources и откройте файл дескриптора.

Вы должны увидеть что-то вроде этого (комментарии удалены):


<?xml version="1.0" encoding="UTF-8"?>
<atlassian-plugin key="${atlassian.plugin.key}" name="${project.name}" plugins-version="2">
  <plugin-info>
    <description>${project.description}</description>
    <version>${project.version}</version>
    <vendor name="${project.organization.name}" url="${project.organization.url}"/>
    <param name="plugin-icon">images/pluginIcon.png</param>
    <param name="plugin-logo">images/pluginLogo.png</param>
  </plugin-info>
  <resource type="i18n" name="i18n" location="tutorial-jira-simple-issue-crud"/>
  <web-resource key="tutorial-jira-simple-issue-crud-resources" name="tutorial-jira-simple-issue-crud Web Resources">
    <dependency>com.atlassian.auiplugin:ajs</dependency>
    <resource type="download" name="tutorial-jira-simple-issue-crud.css" location="/css/tutorial-jira-simple-issue-crud.css"/>
    <resource type="download" name="tutorial-jira-simple-issue-crud.js" location="/js/tutorial-jira-simple-issue-crud.js"/>
    <resource type="download" name="images/" location="/images"/>
    <context>tutorial-jira-simple-issue-crud</context>
  </web-resource>
</atlassian-plugin>

На последующих этапах мы будем использовать генератор модуля плагинов (т. е. другую команду atlas-) для генерации кода-заглушки для дополнительных модулей, требуемых приложением.

Шаг 3. Добавьте модуль сервлета

  1. Откройте окно терминала и перейдите в корневую папку приложения, где находится pom.xml.
  2. Выполните следующую команду:

atlas-create-jira-plugin-module

  1. Выберите параметр Servlet.
  2. При появлении запроса добавьте следующую информацию.

 

New Classname

Новое имя класса

IssueCRUD

Package Name

Имя пакета

com.example.plugins.tutorial.servlet

Show Advanced Setup

Показать расширенную настройку

N

  1. Выберите N для добавления другого модуля плагина.

 

Просмотрите изменения, сделанные генератором

Генератор добавил в ваше приложение следующие элементы:

  • Класс Java IssueCRUD.
  • Модуль servlet в ваш дескриптор приложения.
  • Требуемые зависимости Maven (в вашем POM).

Если вы откроете файл atlassian-plugin.xml в своей среде IDE, вы увидите следующую информацию о модуле, добавленную генератором:


<servlet name="Issue CRUD" i18n-name-key="issue-crud.name" key="issue-crud" class="com.example.plugins.tutorial.servlet.IssueCRUD">
    <description key="issue-crud.description">The Issue CRUD Plugin</description>
    <url-pattern>/issuecrud</url-pattern>
  </servlet>

Если вы откроете файл pom.xml в своей среде IDE, в разделе dependencies вы увидите следующие новые записи:


<dependencies>
...
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.4</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.6.6</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.1.1</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-all</artifactId>
        <version>1.8.5</version>
        <scope>test</scope>
    </dependency>
...
<dependencies>

Шаг 4. Добавьте модули управления Velocity и пользователями

По умолчанию модуль сервлета не сконфигурирован для использования шаблонов Velocity (предпочтительный механизм шаблонов Atlassian для сервлетов). Давайте создадим Velocity, чтобы мы не писали HTML внутри нашего кода сервлета. Мы будем использовать Atlassian Spring Scanner для импорта TemplateRenderer, который импортирует средство визуализации Velocity. Чтобы добавить этот компонент, выполните следующие действия:

  1. В корне вашего проекта откройте файл pom.xml.
  2. Найдите раздел dependencies и вставьте следующее:

<dependency>
  <groupId>com.atlassian.templaterenderer</groupId>
  <artifactId>atlassian-template-renderer-api</artifactId>
  <version>2.0.0</version>
  <scope>provided</scope>
</dependency>

  1. Сохраните файл.

Шаг 5. Создайте приложение и сделайте небольшой тест.

На данный момент вы на самом деле не написали Java-код. Вы можете, однако, запустить Jira и увидеть ваше приложение с его сервером в действии. На этом этапе вы запустите Jira, создите проект, который вы будете использовать позже, и проверите сервлет.

  1. Убедитесь, что вы сохранили все свои изменения кода до этой точки.
  2. Откройте окно терминала и перейдите в корневую папку приложения, где находится файл pom.xml.
  3. Выполните следующую команду:

atlas-run

Эта команда создает код приложения, запускает экземпляр Jira и устанавливает в нем ваше приложение. Это может занять несколько минут. Когда процесс завершится, вы увидите много строк состояния на вашем экране с чем-то вроде следующего:


[INFO] jira started successfully in 71s at http://localhost:2990/jira
[INFO] Type CTRL-D to shutdown gracefully
[INFO] Type CTRL-C to exit

Обратите внимание на URL-адрес экземпляра Jira.

  1. Перейдите в локальный экземпляр Jira в вашем браузере (URL-адрес указан в выводе терминала).
  2. Войдите в систему, используя admin / admin по умолчанию.

При первом запуске экземпляра Jira появляется мастер создания проекта.

  1. Создайте новый пустой проект под названием «TUTORIAL» с ключевым словом «TUTORIAL». Нам понадобится это позже.

 

 

Чтобы сосредоточиться на кодировании IssueCRUD, мы полагаемся на жестко закодированные идентификаторы проектов в нашем приложении. Важно, чтобы проект Jira имел имя и ключ «TUTORIAL». Если новый мастер проекта не отображается, обязательно создайте проект с этими значениями.

  1. Чтобы открыть сервлет, перейдите в localhost: 2990 / jira / plugins / servlet / issuecrud в вашем браузере.Вы должны увидеть сообщение «Hello World» в окне браузера. Чтобы узнать, где указан путь / issuecrud, перейдите в src / main / resources, откройте файл atlassian-plugin.xml и найдите модуль servlet. Он включает элемент <url-pattern>, который идентифицирует этот путь.
  2. Оставьте Jira запущенной в браузере.

Шаг 6. Создание шаблонов Velocity

Нам нужны шаблоны Velocity для создания, редактирования и списка задач.

  1. Откройте новое окно терминала и перейдите к src / main / resources.
  2. Создайте подкаталог с именем templates.
  3. Создайте новый файл с именем edit.vm, затем добавьте следующий контент:

<html>
<head>
    <title>Edit Issue — Issue CRUD Tutorial</title>
    <meta name="decorator" content="atl.general">
</head>
<body class="page-type-admin">
<div class="content-container">
 
    <div class="content-body">
        <h1>Edit issue $issue.getKey()</h1>
 
        #if ($errors.size()>0)
            <div class="aui-message error shadowed">
                #foreach($error in $errors)
                    <p class="title">
                        <span class="aui-icon icon-error"></span>
                        <strong>$error</strong>
                    </p>
                #end
            </div>
            <!-- .aui-message -->
        #end
 
        <div class="create-issue-panel">
 
            <form method="post" id="h" action="issuecrud" class="aui">
                <input type="hidden" name="edit" value="y">
                <input type="hidden" name="key" value="$issue.getKey()">
                <div class="field-group">
                    <label for="h-fsummary">
                        Summary
                        <span class="aui-icon icon-required"></span>
                        <span class="content">required</span>
                    </label>
                    <input id="h-fsummary" class="text long-field" type="text" name="summary" value="$issue.getSummary()">
                </div>
                <div class="field-group">
                    <label for="h-fdescription">
                        Description
                        <span class="aui-icon icon-required"></span>
                        <span class="content">required</span>
                    </label>
                    <textarea id="h-fdescription" name="description">$issue.getDescription()</textarea>
                </div>
                <div class="buttons">
                    <input class="button" type="submit" value="Update">
                    <a href="issuecrud">Cancel</a>
                </div>
            </form>
        </div>
    </div>
</div>
</body>
</html>

  1. Создайте файл с именем list.vm, затем добавьте следующий контент:

<html>
<head>
    <title>All Tutorial Issues — Issue CRUD Tutorial</title>
    <meta name="decorator" content="atl.general">
    <script>
        AJS.$(document).ready(function() {
            jQuery('.delete-issue').click(function() {
                console.log('deleting');
                var self = jQuery(this);
                jQuery.ajax({
                    type: "delete",
                    url: "issuecrud?key=" + self.data("key"),
                    success: function(data) {
                        console.log('dom', self, data);
                        self.parent().parent().remove();
                    },
                    error: function() {
                        console.log('error', arguments);
                    }
                });
                return false;
            });
        });
    </script>
</head>
<body class="page-type-admin">
<div class="content-container">
 
    <div class="content-body">
        <h1>You've Got #if($issues.size()==0)<span style="color:red">NO</span>#end Issues!</h1>
 
        #if ($errors.size()>0)
            <div class="aui-message error shadowed">
                #foreach($error in $errors)
                    <p class="title">
                        <span class="aui-icon icon-error"></span>
                        <strong>$error</strong>                     </p>                 #end             </div>             <!-- .aui-message -->         #end           #if ($issues.size() > 0)             <div class="issues">                 <table class="aui">                     <thead>                     <tr>                         <th>Key</th>                         <th>Summary</th>                         <th>Description</th>                         <th>Assignee</th>                         <th>Reporter</th>                         <th></th>                     </tr>                     </thead>                     <tbody>                         #foreach( $issue in $issues )                         <tr>                             <td>$issue.getKey()</td>                             <td>$issue.getSummary()</td>                             <td>                                 #if($issue.getDescription())                             $issue.getDescription()                         #end                             </td>                             <td>                                 $issue.getAssignee().getName()                             </td>                             <td>                                 $issue.getReporter().getName()                             </td>                             <td>                                 <a href="issuecrud?edit=y&key=$issue.getKey()">Edit</a>                                  <a href="#" class="delete-issue" data-key="$issue.getKey()">Delete</a>                             </td>                         </tr>                         #end                     </tbody>                 </table>             </div>         #end         <form method="get" action="issuecrud" class="aui">             <input type="hidden" name="new" value="y">             <input type="submit" class="button" value="Create new issue">         </form>     </div> </div> </body> </html>

  1. Создайте файл с именем new.vm, затем добавьте следующий контент:

<html>
<head>
    <title>Create Issue — Issue CRUD Tutorial</title>
    <meta name="decorator" content="atl.general">
</head>
<body class="page-type-admin">
<div class="content-container">
 
    <div class="content-body">
        <h1>Create issue</h1>
        <div class="create-issue-panel">
 
            <form method="post" id="h" action="issuecrud" class="aui">
                <div class="field-group">
                    <label for="h-fsummary">
                        Summary
                        <span class="aui-icon icon-required"></span>
                        <span class="content">required</span>
                    </label>
                    <input id="h-fsummary" class="text long-field" type="text" name="summary">
                </div>
                <div class="field-group">
                    <label for="h-fdescription">
                        Description
                        <span class="aui-icon icon-required"></span>
                        <span class="content">required</span>
                    </label>
                    <textarea id="h-fdescription" name="description"></textarea>
                </div>
                <div class="buttons">
                    <input class="button" type="submit" value="Create">
                    <a href="issuecrud">Cancel</a>
                </div>
            </form>
        </div>
    </div>
 
</div>
</body>
</html>

Вот как мы будем использовать файлы:

  • list.vm, чтобы отобразить список доступных задач.
  • edit.vm для редактирования выбранной задачи.
  • new.vm для создания простой формы создания задачи.

Теперь вы готовы написать Java-код.

 

Шаг 7. Напишите свои Java-классы

На этом этапе вы обновите код сервлета, чтобы отобразить что-то более интересное, чем «Hello World». Все работы в этом разделе будут находиться в файле IssueCRUD.java, который находится здесь:

/src/main/java/com/example/plugins/tutorial/servlet/

Настройка сервлета

Давайте сконфигурируем наш основной сервлет.

  1. Откройте файл IssueCRUD.java.
  2. Замените существующий раздел импорта (без нарушения определения пакета), чтобы он выглядел следующим образом:

import com.atlassian.jira.bc.issue.IssueService;
import com.atlassian.jira.bc.issue.search.SearchService;
import com.atlassian.jira.bc.project.ProjectService;
import com.atlassian.jira.config.ConstantsManager;
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.issue.IssueInputParameters;
import com.atlassian.jira.issue.MutableIssue;
import com.atlassian.jira.issue.issuetype.IssueType;
import com.atlassian.jira.issue.search.SearchException;
import com.atlassian.jira.issue.search.SearchResults;
import com.atlassian.jira.web.bean.PagerFilter;
import com.atlassian.plugin.spring.scanner.annotation.component.Scanned;
import com.atlassian.plugin.spring.scanner.annotation.imports.JiraImport;
import com.atlassian.query.Query;
import com.atlassian.templaterenderer.TemplateRenderer;
import com.atlassian.jira.jql.builder.JqlClauseBuilder;
import com.atlassian.jira.jql.builder.JqlQueryBuilder;
import com.atlassian.jira.project.Project;
import com.atlassian.jira.security.JiraAuthenticationContext;
import com.atlassian.jira.user.ApplicationUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

  1. Поместите @Scanned аннотацию в класс IssueCRUD и создайте конструктор.

@Scanned
public class IssueCRUD extends HttpServlet {
    private static final Logger log = LoggerFactory.getLogger(IssueCRUD.class);
 
    @JiraImport
    private IssueService issueService;
    @JiraImport
    private ProjectService projectService;
    @JiraImport
    private SearchService searchService;
    @JiraImport
    private TemplateRenderer templateRenderer;
    @JiraImport
    private JiraAuthenticationContext authenticationContext;
    @JiraImport
    private ConstantsManager constantsManager;
 
    private static final String LIST_ISSUES_TEMPLATE = "/templates/list.vm";
    private static final String NEW_ISSUE_TEMPLATE = "/templates/new.vm";
    private static final String EDIT_ISSUE_TEMPLATE = "/templates/edit.vm";
 
    public IssueCRUD(IssueService issueService, ProjectService projectService,
                     SearchService searchService,
                     TemplateRenderer templateRenderer,
                     JiraAuthenticationContext authenticationContext,
                     ConstantsManager constantsManager) {
        this.issueService = issueService;
        this.projectService = projectService;
        this.searchService = searchService;
        this.templateRenderer = templateRenderer;
        this.authenticationContext = authenticationContext;
        this.constantsManager = constantsManager;
    }

Аннотации @JiraImport инструктируют Atlassian Spring Scanner импортировать указанные интерфейсные сервисы Atlassian из хост-приложения и вставлять их в наш объект сервлета. @Scanned аннотация используется для обозначения класса для Atlassian Spring Scanner.

Обработка запроса GET ( список задач, новая задача,  редактирование задачи)

После подключения сервисов Jira API, необходимых для приложения, мы можем начать работу с обработчиками запросов(request).

  1. Замените существующий метод doGet. Этот новый метод создает страницу, которая в зависимости от действия пользователя перечисляет все задачи, создает новые задачи и обновляет существующие задачи.

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        String action = Optional.ofNullable(req.getParameter("actionType")).orElse("");
 
        Map<String, Object> context = new HashMap<>();
        resp.setContentType("text/html;charset=utf-8");
        switch (action) {
            case "new":
                templateRenderer.render(NEW_ISSUE_TEMPLATE, context, resp.getWriter());
                break;
            case "edit":
                IssueService.IssueResult issueResult = issueService.getIssue(authenticationContext.getLoggedInUser(),
                        req.getParameter("key"));
                context.put("issue", issueResult.getIssue());
                templateRenderer.render(EDIT_ISSUE_TEMPLATE, context, resp.getWriter());
                break;
            default:
                List<Issue> issues = getIssues();
                context.put("issues", issues);
                templateRenderer.render(LIST_ISSUES_TEMPLATE, context, resp.getWriter());
        }
 
    }

Если вы внимательно посмотрите, доступ к этой задаче выполняется с помощью IssueService. Нам также понадобится метод создания списка Jiras.

  1. Добавьте метод getIssues, который будет искать проблемы, относящиеся к проекту «TUTORIAL».

private List<Issue> getIssues() {  
       ApplicationUser user = authenticationContext.getLoggedInUser();
       JqlClauseBuilder jqlClauseBuilder = JqlQueryBuilder.newClauseBuilder();
       Query query = jqlClauseBuilder.project("TUTORIAL").buildQuery();
       PagerFilter pagerFilter = PagerFilter.getUnlimitedFilter();
 
       SearchResults searchResults = null;
       try {
           searchResults = searchService.search(user, query, pagerFilter);
           e.printStackTrace();
       }
       return searchResults != null ? searchResults.getIssues() : null;
   }

Если мы хотим получить список задач для нашего проекта, мы обращаемся к SearchService с указанным предложением JQL.

Параметр запроса(request), который получает сервлет, определяет, какую страницу отображать:

  • Если параметр actionType edit, сервлет отображает шаблон edit.vm.
  • Если параметр actionType является new, сервлет отображает шаблон new.vm.
  • Если параметр не передан, сервлет отображает шаблон list.vm.

Обработка запроса POST (создание задачи  и обновление задачи)

Теперь, когда мы можем отобразить запрос GET, давайте сосредоточимся на создании и обновлении задачи. Это происходит в запросе POST и обрабатывается в нашем коде методом doPost. Мы также создадим методы handleIssueEdit и handleIssueCreation для разделения логики. Обратите внимание, что код предполагает строгий код  ключа проекта «TUTORIAL».


    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String actionType = req.getParameter("actionType");  
        switch (actionType) {
           case "edit":
               handleIssueEdit(req, resp);
               break;
           case "new":
               handleIssueCreation(req, resp);
               break;
           default:
               resp.sendError(HttpServletResponse.SC_NOT_FOUND);
        }
    }
 
 
    private void handleIssueEdit(HttpServletRequest req, HttpServletResponse resp) throws IOException {
 
        ApplicationUser user = authenticationContext.getLoggedInUser();
 
        Map<String, Object> context = new HashMap<>();
 
        IssueInputParameters issueInputParameters = issueService.newIssueInputParameters()
        issueInputParameters.setSummary(req.getParameter("summary"))
                .setDescription(req.getParameter("description"));
 
        MutableIssue issue = issueService.getIssue(user, req.getParameter("key")).getIssue();
 
        IssueService.UpdateValidationResult result =
                issueService.validateUpdate(user, issue.getId(), issueInputParameters);
 
        if (result.getErrorCollection().hasAnyErrors()) {
            context.put("issue", issue);
            context.put("errors", result.getErrorCollection().getErrors());
            resp.setContentType("text/html;charset=utf-8");
            templateRenderer.render(EDIT_ISSUE_TEMPLATE, context, resp.getWriter());
        } else {
            issueService.update(user, result);
            resp.sendRedirect("issuecrud");
        }
    }
 
    private void handleIssueCreation(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        ApplicationUser user = authenticationContext.getLoggedInUser();
 
        Map<String, Object> context = new HashMap<>();
 
        Project project = projectService.getProjectByKey(user, "TUTORIAL").getProject();
 
        if (project == null) {
            context.put("errors", Collections.singletonList("Project doesn't exist"));
            templateRenderer.render(LIST_ISSUES_TEMPLATE, context, resp.getWriter());
            return;
        }
 
        IssueType taskIssueType = constantsManager.getAllIssueTypeObjects().stream().filter(
                issueType -> issueType.getName().equalsIgnoreCase("task")).findFirst().orElse(null);
 
        if(taskIssueType == null) {
            context.put("errors", Collections.singletonList("Can't find Task issue type"));
            templateRenderer.render(LIST_ISSUES_TEMPLATE, context, resp.getWriter());
            return;
        }
 
        IssueInputParameters issueInputParameters = issueService.newIssueInputParameters();
        issueInputParameters.setSummary(req.getParameter("summary"))
                .setDescription(req.getParameter("description"))
                .setAssigneeId(user.getName())
                .setReporterId(user.getName())
                .setProjectId(project.getId())
                .setIssueTypeId(taskIssueType.getId());
 
        IssueService.CreateValidationResult result = issueService.validateCreate(user, issueInputParameters);
 
        if (result.getErrorCollection().hasAnyErrors()) {
            List<Issue> issues = getIssues();
            context.put("issues", issues);
            context.put("errors", result.getErrorCollection().getErrors());
            resp.setContentType("text/html;charset=utf-8");
            templateRenderer.render(LIST_ISSUES_TEMPLATE, context, resp.getWriter());
        } else {
            issueService.create(user, result);
            resp.sendRedirect("issuecrud");
        }
    }

Как и в коде doGet, в doPost мы отделяем создание от обновления, проверяя для параметра запроса actionType.

Для создания и обновления задачи требуется выполнить шаг проверки. Для создания необходимо использовать метод validateCreate для IssueService. Шаг проверки вернет коллекцию ошибок, если есть ошибки с результатами проверки. В этом случае мы передадим их в контекст шаблона, чтобы Velocity мог отобразить их в HTML.

Удалить задачи

Мы можем удалить задачи с помощью нашего приложения.

Чтобы включить удаление задач, добавьте следующий метод:


    @Override
    protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        ApplicationUser user = authenticationContext.getLoggedInUser();
        String respStr;
        IssueService.IssueResult issueResult = issueService.getIssue(user, req.getParameter("key"));
        if (issueResult.isValid()) {
            IssueService.DeleteValidationResult result = issueService.validateDelete(user, issueResult.getIssue().getId());
            if (result.getErrorCollection().hasAnyErrors()) {
               respStr = "{ \"success\": \"false\", error: \"" + result.getErrorCollection().getErrors().get(0) + "\" }";
            } else {
               issueService.delete(user, result);
               respStr = "{ \"success\" : \"true\" }";
            }
        } else {
            respStr = "{ \"success\" : \"false\", error: \"Couldn't find issue\"}";
        }
        resp.setContentType("application/json;charset=utf-8");
        resp.getWriter().write(respStr);
    }

Шаг 8. Создайте приложение и протестируйте его.

Теперь вы готовы протестировать свой классный новый сервлет для создания задач.

  1. Убедитесь, что вы сохранили все свои изменения кода до этой точки.
  2. Откройте окно терминала и перейдите в корневую папку приложения, где находится файл pom.xml.
  3. Если вы оставите Jira, используйте команду atlas-package для запуска QuickReload. Если вы закрыли Jira, используйте команду atlas-run для ее запуска.
  4. В своем браузере перейдите к локальному экземпляру Jira.
  5. Войдите в систему с помощью admin / admin по умолчанию.
  6. Перейдите на страницу сервлета: localhost: 2990 / jira / plugins / servlet / issuecrud.
  7. Нажмите «Создать новую задачу».
  8. Введите некоторые тестовые данные в поля «Резюме» и «Описание».
  9. Нажмите «Создать».Страница сервлета появится снова, на этот раз с новой перечисленной задачей.

 

Поздравляю, вот и все!

Имейте удовольствие!

 

По материалам Atlassian JIRA  Server Developer Creating a Jira issue CRUD servlet and issue search