Gymterview
middle

Как создать Servlet Module в плагине?

Servlet Module позволяет создавать веб-страницы внутри Jira с собственным UI, используется для административных панелей, конфигурационных страниц плагина, отчётов.

Объявление и реализация

Пример
<servlet key="config-servlet" class="com.example.plugin.servlet.ConfigServlet">
    <url-pattern>/my-plugin/config</url-pattern>
</servlet>
Код ConfigServlet
@Named
public class ConfigServlet extends HttpServlet {

    private final TemplateRenderer templateRenderer;
    private final JiraAuthenticationContext authContext;
    private final PermissionManager permissionManager;
    private final TaskConfigService configService;

    @Inject
    public ConfigServlet(@ComponentImport TemplateRenderer templateRenderer,
                         @ComponentImport JiraAuthenticationContext authContext,
                         @ComponentImport PermissionManager permissionManager,
                         TaskConfigService configService) {
        this.templateRenderer = templateRenderer;
        this.authContext = authContext;
        this.permissionManager = permissionManager;
        this.configService = configService;
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws IOException {
        ApplicationUser user = authContext.getLoggedInUser();
        if (user == null) {
            resp.sendRedirect("/login.jsp");
            return;
        }

        if (!permissionManager.hasPermission(GlobalPermissionKey.ADMINISTER, user)) {
            resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Admin access required");
            return;
        }

        Map<String, Object> context = new HashMap<>();
        context.put("configs", configService.findAll());
        context.put("currentUser", user.getDisplayName());

        resp.setContentType("text/html;charset=UTF-8");
        templateRenderer.render("templates/config-page.vm", context, resp.getWriter());
    }
}

Velocity-шаблон

templates/config-page.vm
<html>
<head>
    <title>Конфигурация плагина</title>
    <meta name="decorator" content="atl.admin"/>
    $webResourceManager.requireResource("com.example.my-plugin:my-resources")
</head>
<body>
    <h2>Настройки плагина</h2>

    <form method="post" class="aui">
        <div class="field-group">
            <label for="projectKey">Проект:</label>
            <input type="text" id="projectKey" name="projectKey" class="text"/>
        </div>
        <div class="buttons-container">
            <input type="submit" value="Сохранить" class="aui-button aui-button-primary"/>
        </div>
    </form>

    <h3>Существующие конфигурации</h3>
    <table class="aui">
        <thead>
            <tr><th>ID</th><th>Проект</th><th>Статус</th></tr>
        </thead>
        <tbody>
            #foreach($config in $configs)
            <tr>
                <td>$config.getID()</td>
                <td>$config.getProjectKey()</td>
                <td>#if($config.isEnabled()) Активна #else Отключена #end</td>
            </tr>
            #end
        </tbody>
    </table>
</body>
</html>

URL доступа: https://jira.company.com/plugins/servlet/my-plugin/config

Частые ошибки

  • Забыть декоратор atl.admin — страница отображается без навигации Jira
  • XSS-уязвимости — не экранировать пользовательский ввод. Используйте $!{htmlUtil.htmlEncode($value)}
  • Не проверять права доступа — сервлет доступен любому аутентифицированному пользователю
  • Использование ComponentAccessor вместо DI — антипаттерн, затрудняет тестирование

Как используется в 2026

  • Servlet Module остаётся актуальным для административных страниц плагинов
  • Тренд: минимум серверного рендеринга, максимум SPA (React/Vue) + REST API плагина
  • AUI (Atlassian UI) — по-прежнему рекомендованная UI-библиотека для DC

На собеседовании: покажите знание Velocity-шаблонов и декораторов (atl.admin). Обязательно упомяните $webResourceManager.requireResource(...) для подключения CSS/JS. Главная ошибка — не проверять права и не экранировать вывод.