Это пример, который я хотел попробовать на какое-то время — приложение Websocket, которое следит за содержимым файла.
Ниже приведен окончательный вид веб-приложения. Это приложение
состоит из нескольких частей:
Генерация файла на хвост:
Я решил использовать набор из 100 случайных кавычек в качестве источника содержимого файла, каждые несколько секунд приложение генерирует цитату и записывает эту цитату во временный файл.
Spring Integration используется для подключения этого потока для записи содержимого в файл:
<int:channel id="toFileChannel"/> <int:inbound-channel-adapter ref="randomQuoteGenerator" method="generateQuote" channel="toFileChannel"> <int:poller fixed-delay="2000"/> </int:inbound-channel-adapter> <int:chain input-channel="toFileChannel"> <int:header-enricher> <int:header name="file_name" value="quotes.txt"/> </int:header-enricher> <int-file:outbound-channel-adapter directory="#{systemProperties['java.io.tmpdir']}" mode="APPEND" /> </int:chain>
Вкратце, потоки Spring Integration теперь можно записывать с использованием DSL на основе Java, и этот поток с использованием Java доступен
здесь.
Завершение файла и отправка контента брокеру
Фактическая привязка самого файла может быть выполнена с помощью специальной команды хвоста ОС или с использованием библиотеки, подобной
Apache Commons IO . Опять же, в моем случае я решил использовать Spring Integration, которая предоставляет адаптеры входящего канала для привязки файла исключительно с использованием конфигурации, этот поток выглядит следующим образом:
<int:channel id="toTopicChannel"/> <int-file:tail-inbound-channel-adapter id="fileInboundChannelAdapter" channel="toTopicChannel" file="#{systemProperties['java.io.tmpdir']}/quotes.txt" delay="2000" file-delay="10000"/> <int:outbound-channel-adapter ref="fileContentRecordingService" method="sendLinesToTopic" channel="toTopicChannel"/>
и его рабочий
Java-эквивалент.
Существует ссылка на «fileContentRecordingService» выше, это компонент, который направит строки файла в место, на которое будет подписан клиент Websocket.
Конфигурация сервера Websocket
Поддержка Spring Websocket упрощает написание приложения на основе Websocket, в этом случае вся рабочая конфигурация выглядит следующим образом:
@Configuration @EnableWebSocketMessageBroker public class WebSocketDefaultConfig extends AbstractWebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { //config.enableStompBrokerRelay("/topic/", "/queue/"); config.enableSimpleBroker("/topic/", "/queue/"); config.setApplicationDestinationPrefixes("/app"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/tailfilesep").withSockJS(); } }
Это может показаться немного чрезмерным, но то, что делают эти несколько строк конфигурации, является очень мощным, и конфигурацию можно лучше понять, пройдя по
ссылке здесь . Вкратце, он устанавливает конечную точку веб-сокета в ‘/ tailfileep’ uri, эта конечная точка улучшена
поддержкой SockJS , Stomp используется в качестве суб-протокола, конечные точки `/ topic` и` / queue` настроены для реального брокера, такого как RabbitMQ или ActiveMQ, но только в памяти.
Возвращаясь к «fileContentRecordingService» еще раз, этот компонент, по сути, берет строку файла и отправляет ее этому посреднику в памяти, SimpMessagingTemplate облегчает эту проводку:
public class FileContentRecordingService { @Autowired private SimpMessagingTemplate simpMessagingTemplate; public void sendLinesToTopic(String line) { this.simpMessagingTemplate.convertAndSend("/topic/tailfiles", line); } }
Настройка веб-сокета
Пользовательский интерфейс
основан на angularjs , клиентский контроллер настроен таким образом и внутренне использует библиотеки javascript для поддержки
sockjs и
stomp :
var tailFilesApp = angular.module("tailFilesApp",[]); tailFilesApp.controller("TailFilesCtrl", function ($scope) { function init() { $scope.buffer = new CircularBuffer(20); } $scope.initSockets = function() { $scope.socket={}; $scope.socket.client = new SockJS("/tailfilesep); $scope.socket.stomp = Stomp.over($scope.socket.client); $scope.socket.stomp.connect({}, function() { $scope.socket.stomp.subscribe("/topic/tailfiles", $scope.notify); }); $scope.socket.client.onclose = $scope.reconnect; }; $scope.notify = function(message) { $scope.$apply(function() { $scope.buffer.add(angular.fromJson(message.body)); }); }; $scope.reconnect = function() { setTimeout($scope.initSockets, 10000); }; init(); $scope.initSockets(); });
Основой этого кода является функция «уведомить», которая обратный вызов действует на сообщения от сервера, в этом случае новые строки, поступающие в файл и отображающие его в текстовой области.
Это оборачивает все приложение для создания файла. Полный рабочий образец без каких-либо внешних зависимостей доступен в
этом месте github , инструкции по его запуску также доступны в этом месте.
Вывод
Spring Websockets предоставляет краткий способ создания приложений на основе Websocket, этот пример демонстрирует эту поддержку. Я недавно выступал по этой теме на своем местном JUG (
IndyJUG ), и колода с презентацией доступна
здесь.