Организация Взаимодействия Веб-Сокета С Приложением Spring

Скажу сразу, стандартная реализация такого взаимодействия существует .

Однако, поскольку данная статья является продолжением темы «Легкий вызов методов удаленного обслуживания в одностраничных приложениях» , здесь будет альтернативная схема взаимодействия, необходимая для замены ajax на вебсокеты, в контексте подхода (jrspc), описанного в теме выше.

В первой статье был описан механизм вызова методов сервиса с помощью ajax. В данной статье описано, как можно реализовать этот механизм, заменив ajax на вебсокеты, не меняя при этом код бизнес-логики приложения.

Такая замена обеспечивает более быстрое соединение (тесты в конце), экономию памяти сервера и добавляет возможность вызова клиентских методов с сервера.

Для демонстрации небольшой приложение для чата , с исходным кодом на GitHub .

На примере анализа которых я попытаюсь объяснить, как реализованы клиентская и серверная части такого взаимодействия.

Приложение работает на сервере Tomcat 7.042. Поддерживает https и wss (непроверенный сертификат) и не ведет логи на сервере.



Серверная часть

Основным вопросом, который возник при организации взаимодействия вебсокета с приложением Spring, был вопрос о том, как обеспечить вызов компонентов Spring из его областей видимости, привязанных к http-сессии, из объекта StreamInbound, возвращаемого методом класса createWebSocketInbound. Вебсокетсервлет , который не привязан к сессии? Чтобы обеспечить необходимый функционал для вызова методов серверного компонента, нам нужно каким-то образом получить доступ к рабочему ApplicationContext из потомка StreamInbound. Если мы попытаемся автоматизировать ApplicationContext, чтобы использовать его для получения нужных нам компонентов в наследника WebSocketServlet или StreamInbound, нас ждет разочарование, поскольку он не будет инициализирован, что абсолютно законно.

Чтобы получить доступ к компонентам из контекстов Spring, которые связаны с сеансом http из обработчика веб-сокета, нам нужно создать объект, который будет сессионным bean-компонентом Spring и который будет храниться в статическом объекте класса хранилища, который может к которому будет обращаться, будет преемником StreamInbound. Этот объект сеанса (назовем его ClientManager) создается во время установления http-соединения.

Соответственно, клиент, прежде чем начать взаимодействовать с сервером через вебсокет, должен сделать один http-запрос на рукопожатие, в результате которого он должен получить id своего ClientManager. Результат этого запроса можно передать в клиентский код двумя способами — вставить clientManagerId в сгенерированную страницу, либо через ajax-запрос со статической страницы (здесь реализован вариант через ajax).

Этот запрос обрабатывается в методе InitializeClientManager контроллера сеанса:

  
  
   

@Controller @Scope("session") public class ClientManagerController { @Autowired private ClientManager clientManager; @RequestMapping(value = "/init", method = RequestMethod.POST) @ResponseBody private String initializeClientManager(HttpSession session) { JSONObject result = new JSONObject(); try{ boolean loged = ClientManagersStorage.checkClientManager(clientManager, session) ; result.put("loged", loged); result.put("clientManagerId", clientManager.getId()); }catch(Throwable th){ result.put("error", th.toString()); } return result.toString(); }

ClientManagersStorage — хранилище наших сессионных менеджеров клиентов, в котором есть методы проверки менеджера на нуль, создания нового, добавления в хранилище, поиска и удаления.



public class ClientManagersStorage { final static private Map<String, ClientManager> clientManagers = new ConcurrentHashMap <String, ClientManager>(); public static boolean checkClientManager(ClientManager clientManager, HttpSession session) { ClientManager registeredClientManager = clientManagers.get(clientManager.getId()); if (registeredClientManager == null) { clientManager.setSession(session); addClientManager(clientManager); registeredClientManager = clientManager; } return registeredClientManager.getUser() != null; } .

}

(вопрос управления жизненным циклом сессии будет рассмотрен чуть ниже) Как видите, менеджеры хранятся в статической карте, с использованием ключа, который является их хэш-кодом, и когда пользователь перезагружает страницу, ему назначается тот же самый менеджер.

Идентификатор этого менеджера передается клиенту в переменной ответа clientManagerId. После того как клиент получил идентификатор своего менеджера, он может открыть соединение через веб-сокет, передав свой clientManagerId в единственном параметре запроса на соединение.

Запрос на открытие этого соединения обрабатывается в методе createWebSocketInbound класса WebSocketConnectorServlet, реализации абстрактного WebSocketServlet.

@Override

Теги: #spring #websockets #jrspc-ws #Разработка сайтов #JavaScript #java

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.