Статьи

Pivot: практический пример, часть 3 — веб-запросы

Это третья в серии из пяти статей, в которой рассказывается о реализации простого, но практичного приложения Pivot под названием Stock Tracker . В предыдущей статье обсуждалась обработка событий в Pivot. Этот раздел посвящен «веб-запросам», родным средствам связи Pivot с удаленными службами данных. Следующая статья расскажет о поддержке связывания данных в Pivot.

«Веб-запросы» — это родные средства Pivot для связи с удаленными службами данных. Они предназначены в первую очередь для облегчения взаимодействия со службами REST на основе JSON. Однако они достаточно универсальны для поддержки связи с любым типом HTTP-сервиса, используя любой формат данных.

Например, данные, представленные приложением Stock Tracker, получены из Yahoo! Финансы в виде файла значений, разделенных запятыми (CSV):

"AAPL","APPLE INC",171.06,169.59,172.17,166.00,+2.88,12995693
"AMZN","AMAZON.COM INC",72.54,72.35,73.83,70.52,+1.10,2748930
"EBAY","EBAY INC",27.09,27.35,27.44,27.04,-0.02,3426369

Эти данные возвращаются путем отправки HTTP-запроса GET по адресу http://download.finance.yahoo.com/d/quotes.csv с соответствующим набором аргументов строки запроса. Например, приложение Stock Tracker передает следующие аргументы URL службы:

  • s — разделенный запятыми список биржевых символов, представляющих котировки для извлечения.

  • f — запрошенный формат для результирующего файла CSV; это строка символов, представляющая различные поля данных, возвращаемые запросом. Формат, используемый приложением Stock Tracker: «snl1ohgc1v»:

    • с — символ
    • n — название компании
    • l1 — последнее значение
    • o — начальная стоимость
    • h — высокое значение
    • г — низкое значение
    • c1 — процент изменения
    • v — громкость

Обратите внимание, что этот запрос на самом деле возвращает больше данных, чем может быть отображено в табличном представлении. Другие поля данных используются подробным представлением цитаты, которое более подробно обсуждается в разделе привязки данных.

Построение веб-запроса

Чтобы отобразить котировки акций для пользователя, Stock Tracker должен выполнить веб-запрос для получения данных из Yahoo! Финансовый веб-сервис, а затем заполните представление таблицы котировок акций результатами запроса. Запрос выполняется в методе refreshTable () , а таблица заполняется обработчиком обратного вызова, реализованным как анонимный внутренний класс, определенный в этом методе. Этот код определен в классе StockTracker .

Сначала создается веб-запрос:

getQuery = new GetQuery(SERVICE_HOSTNAME, SERVICE_PATH);

Затем значение аргумента «s» создается путем объединения значений в списке символов с запятыми и применяются аргументы запроса:

StringBuilder symbolsArgumentBuilder = new StringBuilder();
for (int i = 0, n = symbols.getLength(); i < n; i++) {
if (i > 0) {
symbolsArgumentBuilder.append(",");
}

symbolsArgumentBuilder.append(symbols.get(i));
}

String symbolsArgument = symbolsArgumentBuilder.toString();

getQuery.getArguments().put("s", symbolsArgument);
getQuery.getArguments().put("f", "snl1ohgc1v");

Полученный URL-адрес запроса будет похож на:

http://download.finance.yahoo.com/d/quotes.csv?s=aapl,amzn,ebay&f=snl1ohgc1v

Затем создается и настраивается экземпляр CSVSerializer:

CSVSerializer quoteSerializer = new CSVSerializer();
quoteSerializer.getKeys().add(StockQuote.SYMBOL_KEY);
quoteSerializer.getKeys().add(StockQuote.COMPANY_NAME_KEY);
quoteSerializer.getKeys().add(StockQuote.VALUE_KEY);
quoteSerializer.getKeys().add(StockQuote.OPENING_VALUE_KEY);
quoteSerializer.getKeys().add(StockQuote.HIGH_VALUE_KEY);
quoteSerializer.getKeys().add(StockQuote.LOW_VALUE_KEY);
quoteSerializer.getKeys().add(StockQuote.CHANGE_KEY);
quoteSerializer.getKeys().add(StockQuote.VOLUME_KEY);

По умолчанию класс GetQuery использует экземпляр pivot.core.serialization.JSONSerializer для десериализации данных, возвращаемых запросом GET. Тем не менее, данные цитаты из Yahoo! Финансы возвращаются в виде файла CSV; CSVSerializer — это реализация интерфейса pivot.core.serialization.Serializer, который анализирует поток данных CSV в последовательность пар имя / значение (в частности, экземпляр List <Dictionary <String, Object >>). Коллекция ключей CSVSerializer отображает столбцы в данных CSV на ключи в возвращенных экземплярах словаря.

По умолчанию CSVSerializer создает экземпляр HashMap <String, Object> для каждой строки, с которой он сталкивается в потоке CSV. Однако вызывающая сторона может указать имя другой реализации Dictionary, используя метод setItemClass () :

quoteSerializer.setItemClass(StockQuote.class);

Поскольку данные CSV нетипизированы, все значения по умолчанию возвращаются в виде строк. StockQuote — это пользовательская реализация интерфейса Dictionary, которая преобразует числовые данные столбца в значения типа Float, когда они анализируются сериализатором. Это позволяет избежать потери производительности при обходе данных дважды: один раз, чтобы прочитать их из потока CSV, и снова преобразовать их в соответствующий тип. Средства визуализации ячеек, которые мы присвоили столбцам в файле WTKX, обеспечивают правильное форматирование и представление данных.

Наконец, запрос выполняется:

getQuery.setSerializer(quoteSerializer);

getQuery.execute(new TaskAdapter<Object>(new TaskListener<Object>() {
...
}

Аргумент, передаваемый методу execute (), представляет собой TaskAdapter, заключенный в анонимную реализацию внутреннего класса TaskListener <Object>. TaskListener представляет собой интерфейс определяется pivot.util.concurrent пакета и служит в качестве обработчика обратного вызова для асинхронных операций , осуществляемых pivot.util.concurrent.Task класса, из которых GetQuery является подклассом. TaskAdapter определяется пакетом pivot.wtk и обеспечивает обратный вызов в потоке пользовательского интерфейса (в противном случае прослушиватель вызывается в контексте фонового потока).

TaskListener определяет два метода:

public void taskExecuted(Task<V> task);
public void executeFailed(Task<V> task);

Параметр шаблона V определяется классом Task и представляет (необязательное) возвращаемое значение операции. Первый метод вызывается, если задача завершается успешно, а второй вызывается, если задача не выполнена по какой-либо причине.

Обработчик успеха StockTracker определен следующим образом:

public void taskExecuted(Task<Object> task) {
if (task == getQuery) {
Sequence<Span> selectedRanges = stocksTableView.getSelectedRanges();

List<StockQuote> quotes = (List<StockQuote>)task.getResult();
stocksTableView.setTableData(quotes);

if (selectedRanges.getLength() > 0) {
stocksTableView.setSelectedRanges(selectedRanges);
} else {
if (quotes.getLength() > 0) {
stocksTableView.setSelectedIndex(0);
}
}

ResourceBundle resourceBundle =
ResourceBundle.getBundle(StockTracker.class.getName(), locale);

DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG,
DateFormat.MEDIUM, locale);
String lastUpdateText = resourceBundle.getString("lastUpdate")
+ ": " + dateFormat.format(new Date());
lastUpdateLabel.setText(lastUpdateText);

getQuery = null;
}
}

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

  • Кэширует текущее состояние выбора представления таблицы котировок.

  • Получает результат запроса и приводит его к соответствующему типу (List <StockQuote>)

  • Устанавливает список в качестве данных модели для табличного представления

  • Восстанавливает любое состояние выбора (которое было бы потеряно при сбросе данных модели)

  • Обновляет значение метки «последнее обновление», чтобы отразить текущее время способом, соответствующим текущей локали

В случае сбоя обработчик просто записывает исключение на консоль:

public void executeFailed(Task<Object> task) {
if (task == getQuery) {
System.out.println(task.getFault());
getQuery = null;
}
}

В этом примере демонстрируется использование только GetQuery, но Pivot также обеспечивает поддержку операций HTTP POST, PUT и DELETE с использованием классов PostQuery, PutQuery и DeleteQuery соответственно. Это упрощает создание полноценного REST-клиента с использованием Pivot.