Урок 1. Архитектура, средства и языки разработки
Contents
Урок 1. Архитектура, средства и языки разработки#
Цель данного урока:
Познакомить слушателей с архитектурой фреймворка и принципами разработки в нем
Познакомить слушателей с базой данных
Postgresql
.Дать понять какие знания и навыки по работе с языком
sql
потребуются для дальнейшей работыОзнакомить со структурой документации
Postgresql
Дать понять какие знания и навыки по работе c языками
scala
иjexl
потребуются для дальнейшей работыОзнакомить со структурой документации
scala
иjexl
Данный урок предоставляет:
Обзор архитектуры
Основные понятия фреймворка
Основные понятия по работе с базой данных
Упражнения по языку sql
Упражнения по
scala
Упражнения по
jexl
Литературу для самостоятельного изучения
Архитектура системы#
Для изучения смотри:
Общий принцип работы#
Пользователь подключается с помощью браузера к серверу приложения в режиме терминального доступа. Сервер приложения возвращает web страницу с рабочим столом на котором пользователь может открывать экранные формы и просматривать\загружать отчеты.
Протокол терминального доступа позволяет работать через тонкий канал за счет того что пользователю передается только видимая часть данных.
Для предоставления пользователю требуемой бизнес логики, сервер приложения запускает решение, которое состоит из набора модулей. Где модуль это неделимая часть решения. Каждый модуль содержит автономную(классы) и интерактивную(выборки) бизнес логику.
База данных#
О базе данных#
Для работы система Global
использует базу данных PostgreSQL
.
PostgreSQL
- это свободно распространяемая объектно-реляционная система управления базами данных (ORDBMS
), с наиболее богатым sql из открытых СУБД и являющаяся реальной альтернативой коммерческим базам данных.
PostgreSQL
произносится как post-gress-Q-L
(сокр. Postgres
).
Postgres
— это реляционная система управления базами данных (РСУБД). Где данные хранятся в виде строк в таблицах, с возможностью ссылаться на другие таблицы.
Все строки таблицы имеют одинаковый набор именованных столбцов, при этом каждому столбцу назначается определённый тип данных. Хотя порядок столбцов во всех строках фиксирован, важно помнить, что SQL не гарантирует какой-либо порядок строк в таблице (хотя их можно явно отсортировать при выводе).
Все изменения данных в Postgres
проходит по средствам транзакций (логически операция, которая может быть совершена только полностью).
Надежность#
Надежность PostgreSQL
обеспечивается следующими возможностями:
ACID
- Atomicity,Consistency,Isolation,DurabilityAtomicity - Атомарность
Транзакция рассматривается как единая логическая единица, все ее изменения или сохраняются целиком, или полностью откатываютсяConsistency - Согласованность
Транзакция переводит базу данных из одного непротиворечивого состояния (на момент старта транзакции) в другое непротиворечивое состояние (на момент завершения транзакции). Непротиворечивым считается состояние базы, когда выполняются все ограничения физической и логической целостности базы данных, при этом допускается нарушение ограничений целостности в течение транзакции, но на момент завершения все ограничения целостности, как физические, так и логические, должны быть соблюдены.Isolation - Изоляция
Изменения данных при конкурентных транзакциях изолированы друг от друга на основе системы версионностиDurability - Устойчивость
PostgreSQL
заботится о том, что результаты успешных транзакций гарантировано сохраняются на жесткий диск вне зависимости от сбоев аппаратуры.
MVCC
- Multiversion Concurrency Control
Один из механизмов СУБД для обеспечения параллельного доступа к базам данных, заключающийся в предоставлении каждому пользователю так называемого «снимка» базы, обладающего тем свойством, что вносимые пользователем изменения невидимы другим пользователям до момента фиксации транзакции. Этот способ управления позволяет добиться того, что пишущие транзакции не блокируют читающих, и читающие транзакции не блокируют пишущих.WAL
- Write Ahead Logging
Общепринятый механизм протоколирования всех транзакций, что позволяет восстановить систему после возможных сбоев. Основная идея WAL состоит в том, что все изменения должны записываться в файлы на диск только после того, как эти записи журнала, описывающие эти изменения будут и гарантировано записаны на диск. Это позволяет не сбрасывать страницы данных на диск после фиксации каждой транзакции, так как мы знаем и уверены, что сможем всегда восстановить базу данных используя журнал транзакций.PITR
- Point in Time Recovery
Предоставляет возможность восстановления базы данных (используя WAL) на любой момент в прошлом, что позволяет осуществлять непрерывное резервное копирование кластера PostgreSQL. Репликация также повышает надежность PostgreSQL.Integrity
- Целостность
PostgreSQL поддерживает целостность данных на уровне схемы - это внешние ключи (foreign keys), ограничения (constraints).
Производительность#
Postgres
обеспечивает высокую высокую масштабируемость за счет следующих возможностей:
Поддержка индексов
Индексы — это традиционное средство увеличения производительности БД. Используя индекс, сервер баз данных может находить и извлекать нужные строки гораздо быстрее, чем без него. Однако с индексами связана дополнительная нагрузка на СУБД в целом, поэтому применять их следует обдуманно.Postgres
поддерживает:Стандартные индексы
Частичные индексы
Функциональные индексы
Планировщик запросов
Планирует выполнение запроса основывается на стоимости различных планов, учитывая множество факторов таким образом чтобы минимизировать используемые ресурсы сервера.Система блокировок
Блокировка поддерживается на уровне таблиц и записей. Блокировка оптимизирована под конкретную ОС и архитектуру.Кэширование
Управление буферами и кэширование используют развитые алгоритмы для поддержания эффективности использования выделенных ресурсов.Табличные пространства
Tablespaces позволяют гибкое использование дискового пространства для хранения объектов системы.
Классы#
Определяет правила хранения и обработки таблицы базы данных.
Для изучения смотри:
Выборки#
Определяет правило получения, отображение данных и обеспечивает взаимодействие с пользователем Для изучения смотри:
Модуль#
Модуль
это неделимая группа файлов которая может включатся в произвольный прикладной проект.
Бизнес логика разрабатываемая с помощью фреймворка компонуется между прикладными проектами с помощью модулей.
Где:
Прикладной проект
Набор модулей собираемых в конечное решение. Прикладной проект компонует бизнес логику модулей и связывает их между собой посредством инъекций зависимости(плагины, проектные переопределения).Решение
Набор исполняемых файлов и ресурсов разворачиваемый на сервере приложения в рамках одной схемы базы данных.
Для изучения смотри:
Dbeaver#
Dbeaver - свободный кроссплатформенный инструмент разработки базы данных.
Используется для написания и отладки комплексных sql запросов.
SQL#
Декларативный язык запросов, применяемый для создания, модификации и управления данными.
В отличие от процедурных языков, в которых есть условия, циклы и функции, в sql таких конструкций почти нет.
Декларативные выражения представляют собой описание того, что необходимо получить.
По данному описанию планировщик Postgres
строит алгоритмы для получения результата.
Для изучения языка смотрите:
PL/pgSQL#
PL/pgSQL
это процедурное расширение, наследует все пользовательские типы, функции и операторы SQL
.
Язык позволяет:
создавать функции и триггеры
использовать управляющие структуры
выполнять сложные вычисления
Функции PL/pgSQL могут использоваться везде, где допустимы встроенные функции. Например, можно создать функции со сложными вычислениями и условной логикой, а затем использовать их при определении операторов или в индексных выражениях.
Для изучения языка смотрите:
Intellij Idea#
Интегрированная среда разработки для написания исходного кода модулей.
Для изучения смотри:
Конфигуратор#
Системное приложение Конфигуратор
, развернутое в сервере приложения, предназначено для автоматизации и
ускорению выполнения рутинных задач по разработке проекта.
Для изучения смотри:
Язык scala#
Язык разработки используемый для программирования бизнес логики сервера приложения.
Для изучения смотри:
Язык jexl#
Java Expression Language - Язык выражений java Используется для выполнения динамической бизнес логики. Скрипты на jexl не требуют перекомпиляции прикладного проекта, поэтому могут исполняться в сервере приложений в любое время.
Данный язык широко используется в скриптах миграции, а так же в событиях рабочих процессов настраиваемых на проекте.
Для изучения смотри:
Настройка рабочего места#
Подготовка БД для урока#
Примечание
Можно пропустить этот шаг если вы используете курс с опцией virtual-vm
и образ start
Установка postgres#
Для установки postgres
:
Запустите установщик postgres
Примечание
В случае, если вы используете курс с опцией
virtual-vm
дистрибутив находится в каталогиc:\distr
Следуйте указаниям мастера
При установке достаточно выбирать опции по умолчанию.Внимание
Имя служебного пользователя должно быть
postgres
Для загрузки схемы для обучения:
Положите файл с учебной схемой в
c:\distr
Примечание
В случае, если вы используете курс с опцией
virtual-vm
данный шаг можно пропуститьОткройте командный процессор cmd
Перейдите в каталог исполняемых файлов postgres
В случае, установки по умолчанию 14 версии:cd "C:\Program Files\PostgreSQL\14\bin"
Запустите скрипт установки
psql -U postgres -f c:\distr\clubdata.sql -d postgres -x -q
Данный скрипт создаст базу данных
exercises
Установка и настройка Dbeaver#
Для установки:
Запустите установщик Dbeaver
Совет
В случае, если вы используете курс с опцией
virtual-vm
дистрибутив находится в каталогиc:\distr
Следуйте указаниям мастера
При установке достаточно выбирать опции по умолчанию.
Если нет подключения к интернету, настройте драйвер базы данных для автономной работы:
Откройте
Dbeaver
Откройте
Управление драйверами
Пункт менюDatabase > Driver Manager
Найдите драйвер
PostgreSQL
Откройте карточку редактирования
Перейдите на закладку
Libraries
Удалите все ссылки на библиотеки для закачки
Добавьте jar файл c драйвером
Примечание
В случае, если вы используете курс с опцией
virtual-vm
файл находится в каталогиc:\distr
Для создания нового подключения к основной базе:
Создайте новое подключение
Пункт менюDatabase > New connection
Выберите драйвер
PostgreSQL
Если вы устанавливалиpostgres
с настройками по умолчанию, созданное соединение будет работатьПротестируйте соединение
Нажмите кнопкуTest connection
в мастере соединения
Для создания нового подключения к базе exercises
:
Создайте новое подключение
Пункт менюDatabase > New connection
Выберите драйвер
PostgreSQL
Если вы устанавливалиpostgres
с настройками по умолчанию, созданное соединение будет работатьЗадайте базу подключения
exercises
Протестируйте соединение
Нажмите кнопкуTest connection
в мастере соединения
Стандартная настройка#
Для стандартной настройки рабочего места воспользуйтесь инструкцией Руководство разработчика: Начало работы с фреймворком # Настройка рабочего места
Совет
С инструкцией по установке Global3FrameworkStarterKit можно ознакомится в приложении данного урока
Запуск сервера приложения в режиме отладки#
После настройки рабочего места и сборки проекта можно запустить локальный сервер приложений в режиме отладки.
Выберите в списке стартовых конфигураций Global3se
и нажмите на кнопуку Debug (Shift+F9)
.
При первом запуске IDEA попросит уточнить настройки отладочной конфигурации. В поле -cp (ClassPath) необходимо указать модуль с наименьшим количеством зависимостей, обычно выбирают модуль проекта с окончанием App
.
Подробнее об отладке можно узнать по ссылке.
Запуск конфигуратора#
Внимание
Раздел находится в разработке.
Откройте в браузере http://localhost:8080/
Раскройте
Настройки подключения
и установите признакКонфигуратор
Для входа используйте
логин
admin,пароль
admin
Создание модуля#
Внимание
Раздел находится в разработке.
Откройте конфигуратор
Откройте список модулей, выполнив операцию на главной панели приложения.
В списке модулей выполните операцию
Создать новый модуль
В мастере укажите системное имя модуля
lbr
, наименованиеБиблиотека
Подключите модули:
btk, bs, bts, rpt
и завершите работу мастера, выполнив операциюВыбор
Учебная схема для работы с sql#
Схема для практики и упражнений состоит из набора данных для недавно созданного загородного клуба с перечнем участников. Данные содержат:
Участников клуба
Теннисные корты(объекты)
Историю бронирования этих объектов
Внимание
Не воспринимайте набор как пример хорошего дизайна. Этот набор данных разработан исключительно для поддержки упражнений. Схема базы данных имеет ряд недостатков.
Схема:
-- Участники
CREATE TABLE cd.members
( --Идентификатор
--memid = 0 служебная запись, для всех гостей
memid integer NOT NULL,
--Фамилия
surname character varying(200) NOT NULL,
--Имя
firstname character varying(200) NOT NULL,
--Адрес
address character varying(300) NOT NULL,
--Почтовый код
zipcode integer NOT NULL,
--Телефон
telephone character varying(20) NOT NULL,
--memid участника который рекомендовал текущего участника
recommendedby integer,
--Дата вступления
joindate timestamp NOT NULL,
CONSTRAINT members_pk PRIMARY KEY (memid),
CONSTRAINT fk_members_recommendedby FOREIGN KEY (recommendedby)
REFERENCES cd.members(memid) ON DELETE SET NULL
);
-- Объекты
CREATE TABLE cd.facilities
(
--Идентификатор
facid integer NOT NULL,
--Наименование
name character varying(100) NOT NULL,
--Стоимость слота(bookings.slots) для участника
membercost numeric NOT NULL,
--Стоимость слота(bookings.slots) для гостя( memid = 0 )
guestcost numeric NOT NULL,
--Первоначальные затраты
initialoutlay numeric NOT NULL,
--Затраты на ежемесячное обслуживание
monthlymaintenance numeric NOT NULL,
CONSTRAINT facilities_pk PRIMARY KEY (facid)
);
-- История заказов
CREATE TABLE cd.bookings
(
--Идентификатор
bookid integer NOT NULL,
--Ссылка на объекты
facid integer NOT NULL,
--Ссылка на участников
memid integer NOT NULL,
--Время начала использования объекта
starttime timestamp NOT NULL,
--Интервал использования объекта, выражается слотами, 1 слот - полчаса
slots integer NOT NULL,
CONSTRAINT bookings_pk PRIMARY KEY (bookid),
CONSTRAINT fk_bookings_facid FOREIGN KEY (facid) REFERENCES cd.facilities(facid),
CONSTRAINT fk_bookings_memid FOREIGN KEY (memid) REFERENCES cd.members(memid)
);
Практика работы с sql#
Просмотр учебной схемы#
В навигаторе базы данных(см. пункт меню Windows > Database Navigator
):
Перейдите к учебной схеме
exercises \ Databases \ exercises \ Schemas \ cd
В контекстном меню выберите
View schema
В открывшимся окне перейдите на закладку
ER diagram
Выполнение запроса#
Создайте новый запрос
Для этого выберите пункт менюSql Editor > New Sql Script
. При этом откроется окно для ввода sqlУстановите активное соединение
exercises
Для этого выберете пункт менюSql Editor > Set Active Connection
В окне ввода sql введите
select * from cd.facilities;
Выполните sql
Для этого выберите пункт менюSql Editor > Execute Sql Statement
Посмотрите план запроса
Для этого выберите пункт менюSql Editor > Explain Execution Plan
Совет
Понимания плана запроса позволяет принять решение о необходимости дальнейшей оптимизации. Для более подробной информации смотрите оптимизация производительности в документации PostgreSql
Результат:
|facid|name |membercost|guestcost|initialoutlay|monthlymaintenance|
|-----|---------------|----------|---------|-------------|------------------|
|0 |Tennis Court 1 |5 |25 |10,000 |200 |
|1 |Tennis Court 2 |5 |25 |8,000 |200 |
|2 |Badminton Court|0 |15.5 |4,000 |50 |
|3 |Table Tennis |0 |5 |320 |10 |
|4 |Massage Room 1 |35 |80 |4,000 |3,000 |
|5 |Massage Room 2 |35 |80 |4,000 |3,000 |
|6 |Squash Court |3.5 |17.5 |5,000 |80 |
|7 |Snooker Table |0 |5 |450 |15 |
|8 |Pool Table |0 |5 |400 |15 |
Упражнения по языку sql#
Простое соединение таблиц#
Напишите запрос получения списка времени начала использования объекта для участников с именем и фамилией „David Farrell“
Совет
Смотрите соединённые таблицы в документации PostgreSql
Результат:
|starttime |
|-----------------------|
|2012-09-18 09:00:00.000|
|2012-09-18 13:30:00.000|
|2012-09-18 17:30:00.000|
|2012-09-18 20:00:00.000|
|2012-09-19 09:30:00.000|
|2012-09-19 12:00:00.000|
|2012-09-19 15:00:00.000|
|2012-09-20 11:30:00.000|
|2012-09-20 14:00:00.000|
|2012-09-20 15:30:00.000|
|2012-09-21 10:30:00.000|
|2012-09-21 14:00:00.000|
|2012-09-22 08:30:00.000|
|2012-09-22 17:00:00.000|
|2012-09-23 08:30:00.000|
|2012-09-23 17:30:00.000|
|2012-09-23 19:00:00.000|
|2012-09-24 08:00:00.000|
|2012-09-24 12:30:00.000|
|2012-09-24 16:30:00.000|
|2012-09-25 15:30:00.000|
|2012-09-25 17:00:00.000|
|2012-09-26 13:00:00.000|
|2012-09-26 17:00:00.000|
|2012-09-27 08:00:00.000|
|2012-09-28 09:30:00.000|
|2012-09-28 11:30:00.000|
|2012-09-28 13:00:00.000|
|2012-09-29 10:30:00.000|
|2012-09-29 13:30:00.000|
|2012-09-29 14:30:00.000|
|2012-09-29 16:00:00.000|
|2012-09-29 17:30:00.000|
|2012-09-30 14:30:00.000|
Подзапросы#
Создайте запрос, возвращающий список заказов на день 14.09.2012 которые будет стоить участнику (или гостью) более 30 у.е. Добавьте в вывод:
Имя объекта
Имя, фамилия участника
Информация должна быть выведена одной колонкойСтоимость
Отсортируйте вывод по убыванию. Используйте подзапрос для выбора данных и запрос для сортировки, это позволит уменьшить текстовое дублирование.
Примечание
Гость имеет отличную от участника стоимость(Стоимость учитывается на 1 слот, который равняется получасу). Идентификатор гостевого пользователя всегда 0.
Совет
Смотрите:
Функции в документации PostgreSql.
Для расчета стоимости используйте атрибуты:
bookings.slots
facilities.guestcost
facilities.membercost
Результат:
|member |facility |cost|
|---------------|--------------|----|
|GUEST GUEST |Massage Room 2|320 |
|GUEST GUEST |Massage Room 1|160 |
|GUEST GUEST |Massage Room 1|160 |
|GUEST GUEST |Massage Room 1|160 |
|GUEST GUEST |Tennis Court 2|150 |
|Jemima Farrell |Massage Room 1|140 |
|GUEST GUEST |Tennis Court 1|75 |
|GUEST GUEST |Tennis Court 2|75 |
|GUEST GUEST |Tennis Court 1|75 |
|Matthew Genting|Massage Room 1|70 |
|Florence Bader |Massage Room 2|70 |
|GUEST GUEST |Squash Court |70 |
|Jemima Farrell |Massage Room 1|70 |
|Ponder Stibbons|Massage Room 1|70 |
|Burton Tracy |Massage Room 1|70 |
|Jack Smith |Massage Room 1|70 |
|GUEST GUEST |Squash Court |35 |
|GUEST GUEST |Squash Court |35 |
Агрегация#
Создайте запрос возвращающий список количества слотов заказанных каждый месяц в 2012. Колонки списка:
Идентификатор объекта
Номер месяца
Количество слотов
Отсортируйте результат по идентификатору и номеру месяца.
Результат:
|facid|month|Total Slots|
|-----|-----|-----------|
|0 |7 |270 |
|0 |8 |459 |
|0 |9 |591 |
|1 |7 |207 |
|1 |8 |483 |
|1 |9 |588 |
|2 |7 |180 |
|2 |8 |459 |
|2 |9 |570 |
|3 |7 |104 |
|3 |8 |304 |
|3 |9 |422 |
|4 |7 |264 |
|4 |8 |492 |
|4 |9 |648 |
|5 |7 |24 |
|5 |8 |82 |
|5 |9 |122 |
|6 |7 |164 |
|6 |8 |400 |
|6 |9 |540 |
|7 |7 |156 |
|7 |8 |326 |
|7 |9 |426 |
|8 |7 |117 |
|8 |8 |322 |
|8 |9 |471 |
Оконные функции#
Найдите три лучших объекта, приносящих доход
Совет
Смотрите оконные функции в документации PostgreSql
Результат:
|name |rank|
|--------------|----|
|Massage Room 1|1 |
|Massage Room 2|2 |
|Tennis Court 2|3 |
Рекурсия#
Найдите восходящую цепочку рекомендаций для участника(A) с идентификатором 27 : то есть участника(B), который рекомендовал участника A и участника(C) который рекомендовал участника (B) и так далее.
Верните идентификатор участника, имя и фамилию. Порядок по убыванию идентификатора участника.
Совет
Смотрите рекурсивные запросы в документации PostgreSql
Результат:
|recommender|firstname|surname|
|-----------|---------|-------|
|20 |Matthew |Genting|
|5 |Gerald |Butters|
|1 |Darren |Smith |
Json#
Напишите запрос возвращающий одну строку(используя агрегацию) содержащую json массив для первых 5 записей по членам клуба.
Записи в массиве должны быть отсортированы по идентификатору члена клуба.
Указывайте формат даты явным образом(to_char(joindate, 'DD.MM.YYYY HH24:MI:SS')
), чтобы избежать зависимостей от настроек базы данных.
{"members":[
{"memid":0,"surname":"GUEST","firstname":"GUEST","address":"GUEST","zipcode":0,"telephone":"(000) 000-0000","recommendedby":null,"joindate":"01.07.2012 00:00:00"},
{"memid":1,"surname":"Smith","firstname":"Darren","address":"8 Bloomsbury Close, Boston","zipcode":4321,"telephone":"555-555-5555","recommendedby":null,"joindate":"02.07.2012 12:02:05"},
{"memid":2,"surname":"Smith","firstname":"Tracy","address":"8 Bloomsbury Close, New York","zipcode":4321,"telephone":"555-555-5555","recommendedby":null,"joindate":"02.07.2012 12:08:23"},
{"memid":3,"surname":"Rownam","firstname":"Tim","address":"23 Highway Way, Boston","zipcode":23423,"telephone":"(844) 693-0723","recommendedby":null,"joindate":"03.07.2012 09:32:15"},
{"memid":4,"surname":"Joplette","firstname":"Janice","address":"20 Crossing Road, New York","zipcode":234,"telephone":"(833) 942-4710","recommendedby":1,"joindate":"03.07.2012 10:25:05"}
]}
Практика работы с scala#
Создание класса с тестами#
Перейдите в окно проекта
Выберете целевой модуль
Перейдите в папку с исходными кодами
[module_name]/src/test/scala
Совет
Создать недостающую папку можно из контекстного меню в idea
New > Directory
Создайте пакет
ru.bitec.app.[module_name]
Создайте тестовый класс
class Lesson1Test extends LangFunSuite{ test("HelloWorld"){ println("hello world") } }
Совет
Запустить тест можно из контекстного меню, для этого:
Переведите курсор на декларацию функции
В контекстном меню выполните операцию „Debug“ Подробнее смотрите выполнение тестов в руководстве idea.
Для дополнительной информации смотрите также библиотеку unit тестирования: scalatest
Примечание
Существуют два специализированных базовых класса для тестовых случаев:
LangFunSuite
Используется для тестов которые не нуждаются в контроллерах бизнес логики.Данные тесты не могут использовать
Api
,Pkg
, и не имеют подключения к базе данных по умолчанию.ApiTest
В данном тексте доступен контекст автономной бизнес логики, тестовые случаи могут использоватьApi
,Pkg
объекты. При этом запуск теста становится медленней из за необходимости инициализировать контекст.
Объявление null типов#
Смотри: Руководство разработчика: языки разработки # scala типы
Пример объявления null типов показан в следующей тестовой функции:
test("NullTypes"){
val nvNumber = "1.3".nn
val nvNullNumber = None.nn
val nvDate = "21.11.2003 00:00:00".nd
val nvNullString = None.nn
val nvEmptyString = "".ns
assert(nvNullString != nvEmptyString)
assert((nvNumber + 1.nn) === "2.3".nn)
assert((nvNullNumber + 1.nn).isNull)
assert( (nvDate+1.day).asNDate() === "22.11.2003".nd)
}
Null типы являются доменным аналогом scala типа опций(Option
), они используются для более компактной записи выражений.
Пример использования null типов и option:
//Null типы
val a1 = 1.nn
val b1 = None.nn
assert(
(a1+b1).isNull
)
//Option
val a2 = Some(1)
val b2: Option[Int] = None
assert(
(for(a<-a2;b<-b2) yield a+b).isEmpty
)
Работа с коллекциями#
Совет
Для более подробной информации по работе с коллекциями смотрите:
ArrayBuffer#
ArrayBuffer
используется тогда, когда нужна изменяемая индексированная последовательность общего назначения.
Поскольку ArrayBuffer
индексирован, произвольный доступ к элементам выполняется быстро.
val nums = ArrayBuffer(1, 2, 3) // ArrayBuffer(1, 2, 3)
nums += 4 // ArrayBuffer(1, 2, 3, 4)
nums ++= List(5, 6)
Совет
Если есть возможность(добавление идет только в конец) используйте ArrayBuffer
вместо ListBuffer
,
так как это экономит оперативную память и процессорное время.
Массив#
Массив содержит фиксированный набор элементов, массивы удобно применять в константных последовательностях так как они потребляют минимальное количество оперативной памяти, и обладаю высоким быстродействием при переборе значений.
val numbers = Array(1, 2, 3, 4)
Совет
Если вы неуверены в том какую коллекцию выбрать используйте массив.
Набор#
Наборы не содержат одинаковых элементов.
//Эквивалентно Set(1, 2)
val set = Set(1, 1, 2)
Кортеж#
Кортеж объединяет простые логические элементы коллекции без использования классов.
//Создание кортежа
val ingredient = ("Sugar", 25)
//Распаковка кортежа
val (name, quantity) = ingredient
val ingredients = Array(ingredient)
//Распаковка в анонимной функции
ingredients.foreach{case (name, quantity) =>
println(s"$name:$quantity")
}
//Распаковка из опции
ingredients.headOption match {
case Some((name3, quantity3))=>
case _ =>
}
Кортежи часто используются при работе с картами для комбинации (key,value)
Совет
Более подробно смотрите кортежи
Карты#
Карты используются для организации структуры позволяющей быстро получить значение по ключу.
val map = Map("foo" -> "bar")
Опция#
Опция представляет собой контейнер, который хранит какое-то значение или не хранит ничего совсем.
Опция часто используется как результат работы метода который может ничего не вернуть к примеру:
val numbers = Map("one" -> 1, "two" -> 2)
numbers.get("two") match {
case Some(v)=>
case _ => AppException("Ошибка в коде".ns).raise()
}
Комбинаторы#
Комбинаторы позволяют выполнять операции преобразования и обхода коллекций. Пример работы с коллекциями:
//Обявление массива номеров
val numbers = Array(1.nn, 2.nn, 3.nn, 4.nn)
//Преобразования массива номеров в массив строк
val strings = numbers.map(_.toString())
// Объявление карты
val map = Map("steve" -> 100.nn, "bob" -> 101.nn, "joe" -> 201.nn)
// Печать элементов массива
strings.foreach{v =>
println(v)
}
//Печать элементов карты
//Выражение case ( k,v ) преобразовывает входящий кортеж
//в переменные k,v
map.foreach{case ( k,v )=>
println(s"$k:$v")
}
//Фильтрация номеров
val someNumbers = numbers.filter(_ >= 3.nn)
//Группировка номеров по 2 элемента в группу
val groupedNumbers = numbers.grouped(2).toArray
//Поиск номера
val num = numbers.find(_ === 2.nn).getOrElse(None.nn)
//Сортировка номеров по убыванию
val sortedNumbers = numbers.sortBy(_.desc)
//Сумирование номеров с лева на право
//Первый аргумент задает начальное значение
val sum = numbers.foldLeft(0.nn)(_+_)
//Преобразование коллекции в строку через запятую и вывод на экран
println(sortedNumbers.mkString(","))
Json#
Загрузка json в модель:
"""{
"values":[
{"id":1},
{"id":2},
{"id":1},
{"id":3}
]
}""".ns.jsonToValue(classOf[Data])
Модель Data
должна быть объявлена внешними классами:
/*
*Класс, типизирующий какую либо строку(из базы данных, или массива json) с полем id.
*Может быть несколько полей с разными типами.
*/
class Rows{
var id: NNumber = _
}
/*
*Класс предоставляющий модель данных.
*/
class Data{
val values: Array[Rows] = Array.empty
}
Примечание
Модель Data
необходимо так как коллекции в java не хранят информации о вложенных объектах, соответственно
выражение classOf[Array[Member]]
не может предоставить достаточной информации для типизированной десериализации.
Упражнения по scala#
Создание функции#
Создайте функцию прибавляющую 1 час к дате.
Создание класса#
Создайте scala класс для хранения данных по членам клуба, назовите атрибуты класса в соответствии с примером на json:
{
"memid":0,
"surname":"GUEST",
"firstname":"GUEST",
"address":"GUEST",
"zipcode":0,
"telephone":"(000) 000-0000",
"recommendedby":null,
"joindate":"01.07.2012 00:00:00"
}
Загрузка классов из json#
Загрузите json в модель скала классов:
{"members":[
{"memid":0,"surname":"GUEST","firstname":"GUEST","address":"GUEST","zipcode":0,"telephone":"(000) 000-0000","recommendedby":null,"joindate":"01.07.2012 00:00:00"},
{"memid":1,"surname":"Smith","firstname":"Darren","address":"8 Bloomsbury Close, Boston","zipcode":4321,"telephone":"555-555-5555","recommendedby":null,"joindate":"02.07.2012 12:02:05"},
{"memid":2,"surname":"Smith","firstname":"Tracy","address":"8 Bloomsbury Close, New York","zipcode":4321,"telephone":"555-555-5555","recommendedby":null,"joindate":"02.07.2012 12:08:23"},
{"memid":3,"surname":"Rownam","firstname":"Tim","address":"23 Highway Way, Boston","zipcode":23423,"telephone":"(844) 693-0723","recommendedby":null,"joindate":"03.07.2012 09:32:15"},
{"memid":4,"surname":"Joplette","firstname":"Janice","address":"20 Crossing Road, New York","zipcode":234,"telephone":"(833) 942-4710","recommendedby":1,"joindate":"03.07.2012 10:25:05"}
]}
Описание модели данных:
data
Используется для типизации модели данныхmembers
Типизированный массив участниковMember
УчастникСовет
Для участника вы можете использовать класс созданные в предыдущем задании.
Поиск последнего участника#
Напишите выражение возвращающее члена клуба который присоединился к клубу последним.
В качестве входных данных используйте результат полученный в задании Загрузка классов из json
Для определение последнего присоединившегося необходимо использовать поле joindate
Совет
Смотрите методы доступные для работы с коллекциями
Сортировка при помощи операции#
Напишите scala функцию сравнивающую двух членов клуба по выражению member1.memid < member2.memid
.
Отсортируйте членов клуба с помощью данной функции.
Совет
Смотрите методы доступные для работы с коллекциями
Практика работа с jexl#
Выполнение произвольного jexl.#
val jexl = new JexlBuilder().permissions(JexlPermissions.UNRESTRICTED).create()
/**
* Выполнение jexl выражения
* @param jexlString строка с jexl выражением
* @param jexlContext контекст jexl,
где контекст это набор переменных и функций, доступных в выражении.
* @return результат выполнения jexl
*/
def evaluateJexl(jexlString: String, jexlContext: MapContext): AnyRef = {
val e = jexl.createExpression(jexlString)
val o = e.evaluate(jexlContext)
o
}
test("eval_jexl") {
//Контекст выполнения содержит переменные доступные jexl выражению
//в момент выполнения
val jc = new MapContext()
//Задает переменную a в контексте выполнения
jc.set("a",1)
//Задает переменную b в контексте выполнения
jc.set("b",2)
assert(evaluateJexl("a + b", jc) == 3)
}
Совет
Для дополнительной информации по синтаксису jexl смотрите справку по синтаксису jexl.
Для понимания типов используемых в выражении смотрите Арифметику jexl
Упражнения по jexl#
Функция сравнения на jexl#
Напишите scala функцию которая используя выражения jexl сравнит двух участников по выражению member1.memid < member2.memid
Примечание
Для чтения свойства скала класса в jexl необходимо к имени свойства добавить скобки.
m1.memid()
Сортировка через jexl#
Напишите сортировку списка участников через jexl выражение member1.memid > member2.memid