Это пример, который я хотел попробовать на какое-то время — приложение 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 ), и колода с презентацией доступна
здесь.
