Фильтрация и сортировка данных #
Использование параметров запроса #
Презентацию можно посмотреть по ссылке.
Видео-запись на Rutube.
Проблема отображения большого объёма данных #
В рамках данной работы рассмотрим типичные сценарии работы с большими наборами данных. Ключевая особенность заключается в том, что невозможно предоставлять пользователю сразу большой набор данных:
- Большой объём данных долго обрабатывает система (как на сервере, так и на клиенте), что делает работу пользователя с системой неудобной.
- Пользователю неудобно работать с очень большими документами.
- Системы хотят самостоятельно обрабатывать свои данные и не делиться этими данными с другими системами.
Для быстрого предоставления данных применяется подход с частичным отображением информации, постраничный вывод. Для решения проблемы нахождения информации реализуется фильтрация элементов по различным критериям.
Сценарий фильтрации, сортировки #
При выполнении фильтрации серверу необходимо предоставить возможности пользователю по передаче параметров, по которым необходимо выполнить извлечение данных из хранилища. Рассмотрим базовый вариант, который предоставляет нам сам протокол HTTP, — передача данных в параметрах URI в рамках GET-запроса.
Решение задач фильтрации и сортировки не должно изменять внутреннее состояние приложения, а влиять только на передаваемые пользователю данные. Работа одного пользователя не должна влиять на работу других пользователей.
Ввиду отсутствия у пользователя возможности узнать параметры GET-запроса путём взаимодействии с сервером, ему необходимо предоставить документацию, в которой будут указаны параметры и ожидаемые значения.
Параметры в запросе URI могут быть:
- Обязательными. В случае отсутствия параметра серверу будет корректно ответить сообщением с кодом 400, BAD REQUEST, с указанием ошибки пользователя.
- Необязательными. В случае отсутствия параметра сервер назначит данному параметру значение по умолчанию. Без документации пользователь не сможет найти названия параметров.
Рассмотрим принципиальную последовательность действий, которые позволят пользователю выполнить фильтрацию или сортировку отображаемых данных:
sequenceDiagram
autonumber
participant client as HTTP-клиент
participant serv as Сервер
client ->> serv : Выполняет GET-запрос
с параметрами в URI
alt Параметры некорректные
serv ->> client : HTTP-ответ, 400, с сообщением об ошибке
else
serv ->> client : HTTP-ответ, 200, с результатами ответа
end
На сервере при получении корректных параметров производится выборка и сортировка данных согласно переданным данным.
Работа со строкой запроса #
В рамках URI, который передаётся от клиента к серверу, можно передать набор
именованных параметров в строке
запроса.
Строка запроса отделяется от пути знаком ?
, затем идут пары параметров в
формате название=значение
, разделённые символом &
. Рассмотрим следующий
пример:
http://localhost:9000/objects?shape=triangles&min-area=90
Запрос от клиента происходит по протоколу HTTP по пути /objects
к серверу
localhost:9000
. Данному пути передаются два параметра:
- параметр
shape
со значениемtriangles
; - параметр
min-area
со значением90
.
В рамках одной строки запроса может быть передано несколько параметров с одинаковым названием. Эта возможность обычно используется для передачи информации из HTML-форм. Важно понять, что набор параметров невозможно свести к ассоциативному массиву с уникальными ключами.
Классы Uri и Parameters #
Библиотека http4k предоставляет удобный класс для работы с URI-идентификаторами,
Uri.
Все объекты класса Request предоставляют свойство uri
, в котором находятся
данные запроса от пользователя. Объекты класса Uri можно также создать
самостоятельно из строки с помощью метода Uri.of(value: String): Uri
:
val uri = Uri.of("https://lms.crafted.su/tech-notes/")
Для работы со строкой запроса класс Uri предоставляет средства, отражённые в списке ниже.
- Свойство
query
для низкоуровневого доступа к строке, пришедшей от пользователя. - Функция
queries(): Parameters
позволяет получить доступ к списку параметров для получения значений параметров. - Функция
query(name: String, value: String?): Uri
добавляет ещё один параметр к запросу. При применении данной функции создаётся новый объект класса Uri, в значение свойстваquery
которого записывается строка с добавленным параметром. Оригинальный объект не изменяется. - Функция
removeQuery(name: String): Uri
удаляет все вхождения параметров с данным названием. - Функция
fun query(query: String): Uri
позволяет заменить целиком строку запроса на новую. Результатом работы функции является новый объект Uri, включающий новую строку запроса. Оригинальный объект класса Uri не изменяется.
Parameters является псевдонимом для списка параметров:
typealias Parameters = List<Parameter>
Для получения значений из данного списка можно воспользоваться средствами, описанными в списке ниже.
- Функция
Parameters.findSingle(name: String): String?
позволяет выполнить поиск первого значения для параметра с указанным названием. - Функция
Parameters.findMultiple(name: String): List<String?>
позволяет найти все значения для параметра с указанным названием. - Функция
Parameters.toParametersMap(): Map<String, List<String?>>
позволяет преобразовать параметры в ассоциативный массив, где для каждого названия (строки) будет указан список переданных значений.
Сценарий постраничного вывода #
Постраничная выдача данных необходима для обеспечения следующих целей:
- Оперативное предоставление данных пользователю. Небольшой набор данных быстрее сформировать на сервере. Небольшой набор данных легче передать по сети.
- Предоставляется возможность для получения всех данных, только частями.
- Сервер контролирует доступ к конкретным элементам.
Рассмотрим базовый сценарий реализации постраничного вывода.
sequenceDiagram autonumber participant client as Client participant serv as Сервер client ->> serv : GET-запрос без параметров serv ->> client : Ответ с данными первой страницы client ->> serv : GET-запрос с параметрами на вторую страницу serv ->> client : Ответ с данными второй страницы
Ключевые особенности подхода:
- У маршрута для отображения документа появляется необязательный параметр — номер страницы.
- По умолчанию номер страницы равен единице (или нулю в зависимости от удобства дальнейшей обработки).
Постраничный вывод хорошо согласуется с фильтрацией данных. При получении одновременно параметров фильтрации и постраничного вывода сначала выполняется фильтрация, а затем по оставшимся данным уже выполняется выделение данных для указанной страницы. Обратный порядок действий приведёт к получению разреженных данных, по которым невозможно определить окончание данных в списке.
Задача № 1. Получение списка треугольников, отфильтрованного по цвету границы #
Реализуйте в приложении получение списка треугольников, отфильтрованного по
цвету границы. Пользователь должен выполнять GET-запрос по пути /v1/list-color
Цвет границы передаётся в качестве параметра border-color
. Возможными
значениями являются цвета треугольника: BLACK, WHITE, RED, GREEN, BLUE, YELLOW,
CYAN, MAGENTA, SILVER, GRAY, MAROON, OLIVE, DARKGREEN, PURPLE TEAL.
Если пользователь не указал параметр, то сервер должен ответить с кодом 400, BAD REQUEST, с JSON-документом следующего содержимого:
{
"error": "Некорректный цвет. Для параметра border-color ожидается цвет, но получено значение «color»"
}
В случае корректного параметра сервер должен возвратить ответ с кодом 200, OK, содержащий JSON-документ следующей структуры:
[
{
"Id": "66ade672-2301-4408-9471-8a17aa883d65",
"SideA": 1,
"SideB": 2,
"SideC": 3
},
{
"Id": "782418f0-86d3-4de0-8450-05e2e1083766",
"SideA": 395,
"SideB": 165,
"SideC": 408
}
]
Список упорядочен по возрастанию даты и времени регистрации и идентификатору.
В случае отсутствия треугольников, удовлетворяющих критерию, должен возвращаться пустой список.
Поход к реализации:
- Реализуйте новую операцию по извлечению данных из хранилища. Операция в качестве аргумента должна принимать цвет границы треугольника. Результатом работы должен быть список треугольников, совпадающий с параметрами фильтрации.
- Реализуйте компонент для формирования JSON-документа на основании списка треугольников, который будет соответствовать заданию.
- Реализуйте HTTP-обработчик, который будет обрабатывать маршрут по получению
данных. Передайте в конструктор ссылку на операцию по извлечению данных. В
рамках обработчика реализуйте:
- Проверьте параметры URI-запроса на наличие параметра фильтрации, а также его значение. В случае ошибки сформируйте ответ с кодом 400.
- С помощью операции извлеките данные из хранилища.
- Сформируйте JSON-документ со списком треугольников на основании полученных данных от пользователя, верните его в качестве данных ответа с кодом 200.
- Свяжите обработчик HTTP-запроса с маршрутом
/v1/list-color
. - Удостоверьтесь, что приложение корректно обрабатывает параметр фильтрации.
Задача № 2. Отображение данных для постраничного вывода #
Модифицируйте приложение для отображения списка треугольников. Реализуйте
постраничный вывод информации о треугольниках по маршруту /v1/list-triangles
Данный маршрут должен принимать два следующих параметра в URI-запросе:
page
, номер страницы. Необязательный параметр. Значение по умолчанию 1. Корректным является любое положительное целое число.records-per-page
, количество элементов на странице. Значение по умолчанию 10. Корректным является один из вариантов:5
,10
,20
,50
.
Если пользователь не передал ни одному параметру данные, тогда каждому из них должно быть установлено значение по умолчанию.
Если пользователь передал некорректное значение любому из параметров, то приложение должно ответить с кодом 400, BAD REQUEST. В качестве тела ответа должен быть помещён JSON-документ следующей структуры:
{
"error": "Некорректное значение параметра page. Ожидается натуральное число, но получено -1"
}
Содержимое поля error должно содержать строку, которая описывает проблемы в переданных параметрах.
Если пользователь передал корректные значения данным параметрам, то приложение должно их использовать при формировании ответа.
Предлагаемый подход к решению задачи:
- Доработайте операцию по получению треугольников. Она должна принимать номер страницы и количество элементов на данной странице. Эти параметры должны учитываться при формировании возвращаемого списка треугольников.
- Доработайте обработчик HTTP-запроса для отображения списка треугольников.
Добавьте в него обработку необязательных параметров
page
иrecords-per-page
.- В случае некорректного значения обработчик должен вернуть ответ с кодом 400.
- В случае отсутствия параметров им должны быть назначены значения по умолчанию.
- Полученные параметры необходимо передать операции по извлечению списка треугольников.
- Проверьте, что приложение стало обрабатывать параметры запроса согласно заданию.
Задача № 3. Добавление постраничного вывода в фильтрованный список #
Добавьте обработку параметров page
и records-per-page
для отображения списка
треугольников, отфильтрованных по цвету границы, /v1/list-color
. После
изменения данный маршрут должен обрабатывать три параметра:
border-color
, цвет границы.page
, номер страницы.records-per-page
, количество элементов на странице.
Поведение последних двух параметров описано в задаче № 2.
При реализации операции по фильтрации списка треугольников и отображения данных на указанной странице, сначала необходимо выполнить фильтрацию по критерию, а после уже выборку данных для страницы.
Задача № 4. Реализация всех запросов для треугольника #
Откройте спецификацию на приложение-треугольник по ссылке .
Ознакомьтесь с рекомендациями по чтению документации на Rutube.
Доработайте логику приложения согласно спецификации. Проверить работу приложения можно в системе https://lms-self-assesment.crafted.su/.