Главная страница
Навигация по странице:

  • 2.5 API-Приложение

  • Маршрутизация

  • Сериализация и десериализация JSON.

  • Внедрение зависимостей.

  • 2.6 Исполнитель задач

  • ВР.pdf. Реферат Магистерская


    Скачать 3.61 Mb.
    НазваниеРеферат Магистерская
    Дата02.03.2023
    Размер3.61 Mb.
    Формат файлаpdf
    Имя файлаВР.pdf.pdf
    ТипРеферат
    #965620
    страница2 из 3
    1   2   3
    2.4 Схема база данных
    Схема базы данных создавалась на основе модели предметной области.
    Использовались шаблоны проектирования «Single Table Inheritance» и
    «Association Table Mapping» для отображения классов в таблицы.
    Рисунок 2.4.1 — Схема базы данных
    22

    2.5 API-Приложение
    Перейдем к
    более подробному рассмотрению устройства
    API-Приложения. Для начала определимся с его областью ответственности и функционалом. API-Приложение должно:
    ● Предоставлять REST API для использования одностраничным приложением;
    ● Аутентифицировать и авторизовывать пользователей;
    ● Манипулировать данными в СУБД, соблюдая все ограничения;
    ● Ставить задачи для отложенного выполнения;
    ● Отправлять задачу на выполнение при наступлении определенного времени.
    Диаграмма компонентов приведена на рисунке 2.5.1.
    Рисунок 2.5.1 — Компоненты API-Приложения
    23

    REST Контроллеры представляют собой пакет с классами, содержащими публичные API методы, диаграмма классов которого представлена на рисунке
    2.5.2.
    Рисунок 2.5.2 — Диаграмма классов REST контроллеров
    Исходя из нефункциональных требований для реализации REST
    интерфейса был использован фреймворк для веб приложений Play. Play
    Framework — это каркас разработки с открытым кодом, написанный на Scala и
    Java, использует паттерн проектирования Model-View-Controller (MVC),
    подходит для создания как классических веб-сайтов, так и для создания REST
    API. Рассмотрим составляющие фреймворка, которые использовались в этой работе.
    24

    Маршрутизация​. Play Framework поддерживает обработку входящих
    HTTP запросов и вызов методов контроллеров, в зависимости от пути в запросе. Соответствия между путём и методом контроллера описываются в специальном формате, пример приведен ниже.
    PUT /admin/users/:id controllers.admin.UserController.update(id: Long)
    Это означает, что PUT запрос по пути ​
    /admin/users/:id должен вызывать метод ​
    update ​
    у класса ​
    UserController ​
    лежащего в пакете ​
    controllers.admin
    Сериализация и десериализация JSON. ​Каркас имеет встроенный функционал для автоматической конвертации объектов в JSON и конвертации
    JSON в объекты. Это необходимо потому что, в REST API для передачи состояния объектов используется именно формат JSON.
    Внедрение зависимостей. ​Поддерживается внедрение зависимостей по стандарту JSR 330 . В качестве реализации используется библиотека Google
    5
    Guice.
    Продолжим разбор функционала,
    рассмотрим реализацию аутентификации и авторизации пользователей. Необходимым требованием к приложению является поддержка входа через учетную запись Google. Так как ввод логина и пароля напрямую на странице сервиса не соответствует принятым нормам безопасности, было решено использовать протокол OAuth2
    для авторизации получения доступа к основной информации о Google аккаунте пользователя. Далее, с помощью вызова в Google API получается уникальный идентификатор пользователя, который и используется для аутентификации.
    После успешной аутентификации API Приложение генерирует токен,
    который надо передавать с каждым последующим запросом. Для генерации токена был выбран стандарт JWT. Json Web Token — это открытый спецификаци для аутентификации в веб приложениях. Токены создаются сервером, подписываются секретным ключом и передаются клиенту, который в
    5
    JSR-330 — спецификация внедрения зависимостей для языка Java
    25
    дальнейшем использует данный токен для подтверждения своей личности.
    Система включает в токен идентификатор пользователя Google, время жизни токена и подпись, сгенерированную с использованием секретного ключа. Это позволяет отказаться от хранилища сессий и от состояния, что, в дальнейшем,
    облегчит горизонтальное масштабирование путем увеличения количества запущенных приложений.
    Рисунок 2.5.3 — Аутентификация пользователя
    26

    Авторизация в приложении реализована по ролям. Существует две роли
    — администратор и пользователь.
    Для авторизации, аутентификации, генерации и проверки токена была использована библиотека Silhouette.
    Следующий компонент подсистемы — это манипулирование данными в
    БД. Для этого был использован паттерн Data Access Object. На каждую сущность было создано по классу, ответственному за чтение, создание,
    обновление и удаления этой сущности в БД.
    Рисунок 2.5.4 — Классы в пакете model.dao
    Написание SQL запросов напрямую в коде не является подходящем решением, так как такие запросы не проверяются компилятором и могут стать причиной ошибки. Поэтому для написания запросов был использован Slick.
    Slick — библиотека для работы с БД для языка Scala, позволяющая писать запросы так, будто работа ведется с Scala коллекциями, расположенными в
    27
    памяти. Помимо этого Slick поддерживает отображение результата запроса в объекты.
    Для использования Slick необходимо:
    1. Указать параметры подключения в файле конфигурации
    2. Объявить схему. Выглядит это следующим образом:
    Здесь объявляется класс

    Competence

    и отображение
    CompetenceTable​
    , в котором содержится информация о названии таблицы и именах и типах столбцов.
    3. Написать запрос.
    Запросы на вставку пишутся так:
    На получение данных так:
    Подобные запросы автоматически преобразуются в SQL, и посылаются в СУБД с использованием JDBC
    6
    Перейдем к планированию и выполнению отложенных задач. В системе существуют действия, которые необходимо выполнять в фоне в определенное время, например отправка писем-уведомлений, генерация отчетов после события оценки. Непосредственно выполнением этих задач занимается отдельная подсистема, которая будет рассмотрена отдельно. Сейчас же
    6
    JDBC — платформенно независимый промышленный стандарт взаимодействия Java-приложений с различными СУБД
    28
    разберемся в деталях того, как именно планируется выполнение задач, и как они вызываются в нужно время.
    Для этого используется Quartz — библиотека с открытым исходным кодом, позволяющая создавать задания, которые необходимо выполнить в определенный момент времени.
    Перед использованием необходимо сконфигурировать хранилище для заданий, в данном случае задания будут храниться в основной БД. Все задания должны реализовывать интерфейс Job. Также в каждое задание передается контекст, содержащий в себе идентификатор события оценки и прочую необходимую информацию.
    Рисунок 2.5.5 — Диаграмма классов задач
    При срабатывании задача отправляет сообщение в очередь, которое будет прочитано Executor`ом и выполнено.
    29

    2.6 Исполнитель задач
    Для функционирования системы необходимо выполнять ряд фоновых задач, таких как подготовка события, отправка уведомлений, формирование отчета. Так как выполнение задач — это фоновый процесс, которые может занимать некоторое количество времени, было решено выделить их выполнение в отдельное приложение. Это позволяет системе быть более гибкой, устойчивой к перезапуску и отказам, позволяет, в случае надобности,
    выполнять горизонтальное масштабирование, путем увеличения количества запущенных исполнителей.
    Основные компоненты приведены ниже:
    Рисунок 2.6.1 — Компоненты исполнителя задач
    Приложение получает команды на выполнение через RabbitMQ.
    RabbitMQ — это программный брокер сообщений на основе стандарта AMQP .
    7
    Создан на основе системы Open Telecom Platform, написан на языке Erlang, в
    7
    AMQP — (Advanced Message Queuing Protocol) открытый протокол для передачи сообщений между компонентами системы
    30
    качестве системы управления базой данных для хранения сообщений использует Mnesia. Использование RabbitMQ в проекте даёт следующие преимущества:

    В случае некорректного завершения работы сервера, данные в очереди не теряются. При последующем запуске обработка продолжается с того места, где был обрыв;

    Если результат обработки не удовлетворяет, задачу можно послать в очередь повторно, например, при сбое или ошибке выполнения;

    Количество хранимых в очереди сообщений не ограничено;

    API Приложение и Исполнитель задач могут быть развернуты на различных серверах;

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

    Producer (поставщик) — программа, отправляющая сообщения;

    Exchange (точка обмена) — получает сообщения от поставщика и отправляет эти сообщения в очередь;

    Queue (очередь) — буфер, хранящий сообщение;

    Consumer (подписчик) — программа, принимающая сообщения из очереди.
    Поставщик никогда не отправляет сообщения напрямую в очередь.
    Фактически, довольно часто поставщик не знает, дошло ли его сообщение до конкретной очереди. Вместо этого поставщик отправляет сообщение в точку обмена. Точки обмена бывают нескольких типов, в данном случае используется direct — все присылаемые сообщения перенаправляются в одну очередь,
    определяемую значением routing key у сообщения. Routing key есть у каждого
    31
    сообщения, он задается поставщиком. Итоговая схема представлена на рисунке
    2.6.2
    Рисунок 2.6.2 — Конфигурация обменников и очередей
    В случае, если Исполнитель по какой-то причине не может выполнить задачу (например, отсутствует доступ к интернету) задача возвращается обратно в очередь, и может быть прочитана снова, после перезапуска
    Исполнителя. Также задача автоматически возвращается в очередь если приложение завершилось во время выполнения. И чтобы мы могли быть уверены в отсутствии потерянных сообщений, RabbitMQ поддерживает подтверждение сообщений. Подтверждение (ack) отправляется подписчиком для информирования RabbitMQ о том, что полученное сообщение было обработано и RabbitMQ может его удалить. Если подписчик прекратил работу и не отправил подтверждение, RabbitMQ поймет, что сообщение не было обработано.
    Для обработки сообщений отсутствует тайм-аут. RabbitMQ вернет сообщение обратно в очередь только если соединение с подписчиком будет закрыто, поэтому нет никаких ограничений на время обработки сообщения.
    Помимо этого подписчик может вернуть сообщение в очередь, отправив в
    RabbitMQ отказ (reject).
    Далее рассмотрим основные компоненты Исполнителя. Первым делом задачи на выполнение поступают в распределитель. Задачи передаются в очередь в сериализованном виде, и распределитель должен произвести десериализацию, а затем передать ее подходящему обработчику. Для того,
    чтобы распределителю не нужно было знать об обработчиках и типах
    32
    сообщений,
    которые они поддерживают,
    был применен подход,
    представленный на рисунке 2.6.3. Его суть заключается в следующем: каждый обработчик должен реализовывать интерфейс ​
    JobHandler​
    , имеющий два метода ​
    supports и ​
    handle​
    . Метод ​
    supports должен возвращать истину в том случае, если обработчик поддерживает задачу. Метод ​
    handle непосредственно выполняет действия, необходимые для обработки сообщения конкретного типа.
    Рисунок 2.6.3 — Диаграмма классов исполнителей задач
    На рисунке 2.6.4 приведена диаграмма последовательности обработки поступающих сообщений. При создании экземпляра класса ​
    Dispatcher происходит регистрация функции обратного вызовы
    (callback)
    в
    RabbitConsumer​
    , которая является входной точкой для обработки сообщений.
    Dispatcher содержит ссылку на коллекцию экземпляров ​
    JobHandler​
    . При поступлении сообщения для каждого из них производится проверка,
    поддерживает ли обработчик сообщение. Если такой обработчик найден, то сообщение передается ему, иначе сообщение отправляется обратно в очередь.
    Также сообщение будет возвращено в очередь в случае возникновения исключения (exception).
    33

    Рисунок 2.6.4 — Последовательность обработки сообщения
    Перейдем к рассмотрению генерации уведомлений. Одним из требований к
    системе является отправка уведомлений на почту оценивающим пользователям и аудиторам. Для того, чтобы подготовленный текст можно было переиспользовать многократно, но при этом письма содержали в себе актуальную информацию, было решено применить систему шаблонов. Так как редактирование шаблонов уведомлений доступно администратору, и должно быть ему понятно, был использован шаблонизатор с минимальным количеством логики и с простейшим синтаксисом — Mustache. Шаблонизатор способен генерировать итоговый текст из шаблона, используя некий контекст.
    Контекст — это набор переменных, значения которых будут использованы для генерации. Шаблон представляет собой текст, содержащий в себе специальные синтаксические конструкции, позволяющие вставлять в него значения переменных, а также включать/исключать некоторые части в зависимости от
    34
    значения переменных. В качестве реализации использована библиотека Scalate.
    Пример шаблона приведен ниже.
    Добрый день, {{user.full_name}}
    Вы принимаете участие в оценке "{{event.name}}", которая продлится с {{event.start}} до {{event.end}}
    Вам необходимо оценить своих коллег в следующих проектах:
    {{#projects}}
    * Проект "{{name}}"
    {{/projects}}
    Для участия перейдите по ссылке: https://assessment-system-url.com/events/{{event.id}}
    Отправка писем реализована по протоколу SMTP, в качестве посредника выступает Amazon SES . Этот сервис необходим, так как иначе рассылка
    8
    большого количества писем ведет к их попаданию в спам.
    Следующий компонент Исполнителя задач — это Обработчик начала события оценки. Он необходим для создания всех записей, используемых для отображения вопросов пользователю и для сохранения ответов.
    8
    Amazon Simple Email Service — платформа отправки и получения электронной почты для использования в бизнесе и разработке ПО
    35

    Рисунок 2.6.5 — Сущности для хранения ответов
    На рисунке 2.6.5 приведена информация о моменте времени, в который создаются экземпляры классов, необходимых для оценки. В этом обработчике создаются экземпляры следующих классов:
    ● Вкладка;
    ● Ответы для пользователя;
    ● Ответы по форме.
    Для каждого проекта, в котором пользователь является оценивающим,
    создается вкладка. Для всех пользователей из всех отношений проекта создаются ответы для пользователя, содержащие в себе ответы по форме. На рисунке 2.6.6 приведен пример того, каким образом это может быть представлено интерфейсе.
    36

    Рисунок 2.6.6 — Пример интерфейса для ответа на вопросы в событии
    Такой подход позволяет отвязать текущие и завершенные события от изменений в оргструктуре(в группах, проектах, отношениях). То есть изменения этих сущностей не повлияет на набор пользователей и вопросы в прошедших и текущих событиях оценки.
    Перейдем к процессу формирования отчетов. Одной из важнейших функций системы является просмотр результатов оценки аудитором. Результат оценивания должен содержать всю информацию об ответах, как в детальном,
    так и агрегированном виде. Это необходимо для того, чтобы аудитор мог надлежащим образом проанализировать текущую обстановку в организации,
    особенности взаимоотношений между сотрудниками, сильные и слабые места каждого из них. Согласно требованиям, отчет должен формироваться в виде электронной таблицы и загружаться на сервис Google Drive. Доступ к файлам для аудиторов должен предоставляться автоматически. Таким образом, задача состоит в том, чтобы каким-то образом формировать файл электронной таблицы с результатами и загружать его на Drive.
    Для каждого события оценки система должна создавать отдельную директорию, содержащую по одному файлу с результатом на каждого оцениваемого, каждый файл должен содержать следующие элементы:
    37

    ● отчет по компетенциям — усредненное значение каждой компетенции,
    используемой в
    вопросах формы,
    отдельно необходимо считать значения самооценки, если эта опция включена, и оценок, полученных от других людей, результат представлен как в виде таблице, так и в виде круговой диаграммы;
    ● коэффициент согласованности ответов — величина, показывающая уровень однообразности мнений о человеке;
    ● история изменений компетенций, в виде таблицы и графика;
    ● агрегированные ответы на вопросы о человеке, сколько голосов было отдано за тот или иной варианты ответа;
    ● детальный ответы на вопросы, содержащие в себе информацию по каждому отвечающему.
    Для оценки согласованности ответов используется коэффициент конкордации Кендалла ​W​. Значение коэффициента конкордации может находится в диапазоне от 0 до 1. Если ​W​=0, считается, что мнения экспертов не согласованы. Если ​W​=1, то оценки экспертов полностью согласованы. На рисунке 2.6.7 приведен вывод формулы, по которой рассчитывается это значение. Где:
    n​ — число компетенций;
    k​ — число оценивающих;
    r
    ij
    — ранг i–ой компетенции определённая j–ым оценивающим;
    d
    i
    — сумма рангов i–ой компетенции по всем оценивающим;
    W​ — коэффициент конкордации Кендалла.
    38

    Рисунок 2.6.7 — Вывод формулы для расчета коэффициента конкордации Кендалла
    Расчет коэффициента производился с помощью библиотеки Apache
    Commons Math. Для большей наглядности, перед отображением значение коэффициента умножается на 10.
    Рассмотрим возможные способы работы с электронными таблицами из языка программирования Scala. Существует много библиотек для выполнения этой задачи, обратим подробное внимание на две из них, кардинально отличающиеся подходом. Первая из них — это Apache POI. Apache POI
    является самой популярной библиотекой для работы с файлами MS Office в экосистеме Java. Она предоставляет интерфейс для чтения и записи офисных файлов. Рассмотрим подробнее формирование файлов электронных таблиц с помощью этой библиотеки. Подход является полностью императивным,
    программисту доступны самые низкоуровневые API для манипулирования элементами в документе. Например, для того, чтобы записать значение в первую ячейку, программист должен сделать следующее
    Workbook book = new HSSFWorkbook();
    Sheet sheet = book.createSheet("Название листа");
    Row row = sheet.createRow(0);
    Cell name = row.createCell(0); name.setCellValue("Значение ячейки А1");
    39

    Можно видеть, что в распоряжении разработчика есть самые базовые методы. Реализация формирования сложных документов с таким подходом неудобна, а абсолютные индексы могут стать причиной ошибки при рефакторинге. Помимо этого, смотря на код, крайне сложно понять, каким образом будет выглядеть итоговый документ. По этим причинам библиотека не подходит, необходим инструмент с более высоким уровнем абстракций для формирования необходимых структур в документе.
    Следующий инструмент — это Jxls. Jxls внутри использует Apache POI
    для формирования отчетов, но разработчик освобожден от низкоуровневой работы с документом. Для создания электронной таблицы с данными необходимы две вещи — шаблон, сам являющийся электронной таблицей и контекст с данными. По своей идее данная библиотека похожа на шаблонизаторы для языка HTML, но работает с электронными таблицами.
    Шаблон содержит в себе управляющие теги в ячейках, и при формировании отчета библиотека подставляет вместо тегов соответствующие значения из контекста. Пример шаблона представлен на рисунке 2.6.8.
    Рисунок 2.6.8 — Создание шаблона для jxls
    40

    Шаблоны можно редактировать в специализированных офисных программах, таких как Microsoft Excel или Libre Office Calc. Для того, чтобы сгенерировать результат, библиотеке нужно передать сам шаблон и контекст.
    Контекст — это объект, содержащий в себе поля, которые будут использоваться для отображения.
    Поддерживается неограниченная вложенность объектов, списки, пары ключ-значение (Map).
    List employees = getData();
    InputStream template = getTemplate();
    OutputStream result = new FileOutputStream("result.xls");
    Context context = new Context(); context.putVar("employees", employees);
    JxlsHelper.getInstance().processTemplate(is, os, context);
    Такой подход работы с таблицами крайне удобен, но имеет один существенный недостаток. Шаблоны хранятся в системе контроля версий в виде двоичных файлов, из чего вытекает невозможность генерации списка изменений при коммите и невозможность разрешения конфликтов в случае их возникновения. Кроме того, отсутствует возможность проверять теги внутри шаблона на корректность. В случае рефакторинга, изменения названия переменных, проект будет собран успешно, но в процессе работы документы будут создаваться некорректно. Тесты также не могут помочь, так как в библиотеке отсутствует функционал валидации тегов, в случае неправильного названия или опечатки соответствующий блок просто не будет выведен в результирующий документ. Помимо этого в процессе работы были встречены различные проблемы с отображением полученных документов в программах,
    отличных от Microsoft Excel. Так как было необходимо отображать документы онлайн с помощью Google Sheets , это стало критическим недостатком.
    9
    Так как существующие библиотеки по тем или иным причинам не подходили,
    было решено реализовывать собственную.
    Основные функциональные возможности, которые хотелось бы поддерживать, это:
    9
    Google Sheets — бесплатный онлайн сервис для просмотра и редактирования электронных таблиц
    41

    ● декларативный подход, позволяющий программисту меньше уделять внимания низкоуровневым деталям и уменьшающий вероятность ошибок;
    ● набор высокоуровневых абстракций, таких как таблица, список;
    ● поддержка стилей, таких как цвет и толщина границ, стиль шрифта,
    фоновый цвет ячейки;
    ● независимость от реализации электронных таблиц. Библиотека должна поддерживать различные модули,
    занимающиеся непосредственно генерацией таблиц. То есть используя один и тот же код структуры документа должна быть возможность формировать как Excel файлы, так и вызовы в Google Sheets API.
    Принимая во внимания необходимые функциональные возможности,
    была представлена разработана концепция, удовлетворяющая требованиям. На рисунке 2.6.9 представлено, из каких частей состоит состоит библиотека и каким образом эти части взаимодействуют. Прямоугольник со скругленными углами — это данные, передаваемые в некоем формате. Простые прямоугольники — обработчики. Стрелки — потоки данных между обработчиками.
    Рисунок 2.6.9 — Потоки данных библиотеки
    Такой подход позволяет разделить шаблон, данные и конкретный генератор, используемый для формирования. По своей идее это напоминает шаблон проектирования двухэтапное представление (Two Step View).
    42

    Рассмотрим способ формирования шаблона. Для этого был разработан
    DSL (или предметно-ориентированный язык), с поддержкой всех базовых конструкций.
    Document[ExportDTO] result = Document.create(doc => { doc.page("Пользователи", page => { page.label(l => { l.text("Список пользователей") l.style(s => s.align(Alignment.CENTER))
    }) page.table(_.getUsers, usersTable => { usersTable.column(_.getFirstName) usersTable.column(_.getLastName)
    })
    })
    })
    DSL основан на использовании лямбда-выражений. Лямбда выражение —
    это специальный синтаксис для определения функциональных объектов. В
    языке
    Scala запись лямбда выражений выглядит так:
    (аргументы)=>выражение.

    Существует особый синтаксис для лямбда-выражений, содержащих в себе вызов метода у объекта. Такую запись:
    user=>user.getFirstName​
    можно кратко записать как ​
    _.getFirstName.
    Диаграмма классов интерфейсов, доступных для пользователя этой библиотеки представлена на рисунке 2.6.10.
    43

    Рисунок 2.6.10 — Диаграмма классов для создания DSL
    Каждый из этих интерфейсов имеет свою реализацию, и каждая эта реализация унаследована от базового интерфейса ​
    VisitableDslElement​,
    имеющего один метод — ​
    visit(DslElementVisitor visitor).

    Такой подход позволяет легко обрабатывать созданное дерево объектов, создавать новые классы таких объектов и различные обработчики. Перейдем к преобразованию шаблона в промежуточную структуру. Для этого было введено две абстракции — контейнер и ячейка. Контейнер может содержать ячейки и другие контейнеры, а также имеет направление, в котором добавляются новые элементы. Фактически это является реализацией паттерна проектирования
    «Компоновщик».
    44

    Рисунок 2.6.10 — Диаграмма классов для промежуточной структуры
    После этого структуру необходимо преобразовать в список действий, для этого необходимо вызвать метод ​
    getActions ​
    у корневого элемента, передав начальную позицию отрисовки в качестве параметра. Метод будет последовательно вызван у всех элементов контейнера и вернет полный список действий,
    необходимых для отрисовки таблицы.
    Диаграммы последовательности для классов ​
    Cell ​
    и ​
    StackPanel приведены на рисунках
    2.6.11, 2.6.12.
    45

    Рисунок 2.6.11 — Диаграмма последовательности класса Cell
    46

    Рисунок 2.6.12 — Диаграмма последовательности класса StackPanel
    47

    Диаграмма классов для действий приведена на рисунке 2.6.13.
    Рисунок 2.6.13 — Диаграмма классов действий
    После того, как список действий получен, можно преобразовывать каждое из них в низкоуровневые вызовы в сторонние библиотеки, например, с помощью Apache POI. В данном случае преобразование производится напрямую в вызовы Google API для модификации данных в таблице.
    Помимо текста и таблиц было необходимо добавить поддержку вывода диаграмм и изображений. Диаграммы можно отрисовывать двумя путями:
    ● использовать инструменты встроенные в средство редактирования и просмотра электронных таблиц;
    ● генерировать их заранее и вставлять в виде обычного изображения.
    В данной работе был выбран второй подход, так как он позволяет сделать внешний вид диаграмм независимым от формата экспорта, дает возможность использовать типы диаграмм, неподдерживаемые офисным приложением. Этот подход имеет и минус, существенный в общем случае, но являющийся неважным в этом приложении — диаграммы не будут обновляться при
    48
    обновлении данных в таблице. Это не является проблемой, так как редактирование полученных отчетов не является необходимостью.
    Существует большое количество библиотек генерации диаграмм для языков Java и Scala. Из них была выбрана библиотека XChart, так как она имеет все необходимые функции, бесплатна, с открытыми исходными кодами и активно поддерживается разработчиками. Чтобы вывести график разработчику необходимо выполнить следующие действия:
    RadarChart chart = new RadarChartBuilder().width(800).height(600).title("График компетенций").build chart.setVariableLabels(Array("Инициативность", "Интерес к работе",
    "Исполнительность", "Командная работа")) chart.addSeries("Среднее", Array(0.8, 0.7, 0.4, 0.5)) chart.addSeries("Самооценка", Array(0.6, 0.9, 0.6, 0.7)) val byteArrayOutputStream = new ByteArrayOutputStream()
    BitmapEncoder.saveBitmap(chart, byteArrayOutputStream,
    BitmapEncoder.BitmapFormat.PNG) val bytes = byteArrayOutputStream.toByteArray
    Этот код создает новую круговую диаграмму в формате PNG, результат сохраняется в массив байт для дальнейшего использования.
    Рисунок 2.6.14 — Пример круговой диаграммы
    49

    1   2   3


    написать администратору сайта