Русский
Русский
English
Статистика
Реклама

Перевод Пишем чат с использованием Spring Boot и WebSockets



Всем привет. В преддверии старта курса Разработчик на Spring Framework мы подготовили для вас еще один полезный перевод. Но, прежде чем перейти к статье, хотим поделиться с вами бесплатной записью урока от наших преподавателей по теме: Рефакторинг кода приложений на Spring, а также предлагаем посмотреть запись вебинара из которого вы сможете подробно узнать о программе курса и формате обучения.


А теперь перейдем к статье


В статье Building Scalable Facebook-like Notification using Server-Sent Event and Redis для отправки сообщений от сервера клиенту мы использовали Server-sent Events. Также там было упомянуто о WebSocket технологии двунаправленной связи между сервером и клиентом.

В этой статье мы посмотрим на один из распространенных примеров использования WebSocket. Мы напишем приложение для обмена приватными сообщениями.

Ниже на видео продемонстрировано то, что мы собираемся сделать.

https://www.google.com/url?q=https://youtu.be/fgfSyAQD24k&sa=D&ust=1598454677145000&usg=AFQjCNEMeXm-44vGZ6p9UR1KURKO9HEaMA

Введение в WebSockets и STOMP


WebSocket это протокол для двусторонней связи между сервером и клиентом.
WebSocket, в отличие от HTTP, протокола прикладного уровня, является протоколом транспортного уровня (TCP). Хотя для первоначальной установки соединения используется HTTP, но потом соединение обновляется до TCP-соединения, используемого в WebSocket.

WebSocket протокол низкого уровня, который не определяет форматы сообщений. Поэтому WebSocket RFC определяет подпротоколы, описывающие структуру и стандарты сообщений. Мы будем использовать STOMP поверх WebSockets (STOMP over WebSockets).

Протокол STOMP (Simple / Streaming Text Oriented Message Protocol) определяет правила обмена сообщениями между сервером и клиентом.

STOMP похож на HTTP и работает поверх TCP, используя следующие команды:

  • CONNECT
  • SUBSCRIBE
  • UNSUBSCRIBE
  • SEND
  • BEGIN
  • COMMIT
  • ACK


Спецификацию и полный список команд STOMP можно найти здесь.

Архитектура




  • Сервис аутентификации (Auth Service) ответственен за аутентификацию и управление пользователями. Здесь мы не будем изобретать колесо и воспользуемся сервисом аутентификации из статьи JWT and Social Authentication using Spring Boot.
  • Сервис чата (Chat Service) ответственен за настройку WebSocket, обработку STOMP-сообщений, а также за сохранение и обработку сообщений пользователей.
  • Клиент (Chat Client) это приложение на ReactJS, использующее STOMP-клиента для подключения и подписки на чат. Также здесь находится пользовательский интерфейс.


Модель сообщения


Первое, о чем нужно подумать это модель сообщения. ChatMessage выглядит следующим образом:

public class ChatMessage {   @Id   private String id;   private String chatId;   private String senderId;   private String recipientId;   private String senderName;   private String recipientName;   private String content;   private Date timestamp;   private MessageStatus status;}


Класс ChatMessage довольно простой, с полями, необходимыми для идентификации отправителя и получателя.

В нем также есть поле статуса, указывающее доставлено ли сообщение клиенту.

public enum MessageStatus {    RECEIVED, DELIVERED}


Когда сервер получает сообщение из чата, он не отправляет сообщение адресату напрямую, а отправляет уведомление (ChatNotification), чтобы оповестить клиента о получении нового сообщения. После этого клиент сам может получить новое сообщение. Как только клиент получит сообщение, оно помечается как доставленное (DELIVERED).

Уведомление выглядит следующим образом:

public class ChatNotification {    private String id;    private String senderId;    private String senderName;}


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





Настройка WebSocket и STOMP в Spring


Первым делом настраиваем конечную точку STOMP и брокер сообщений.

Для этого создаем класс WebSocketConfig с аннотациями @Configuration и @EnableWebSocketMessageBroker.

@Configuration@EnableWebSocketMessageBrokerpublic class WebSocketConfig implements WebSocketMessageBrokerConfigurer {    @Override    public void configureMessageBroker(MessageBrokerRegistry config) {        config.enableSimpleBroker( "/user");        config.setApplicationDestinationPrefixes("/app");        config.setUserDestinationPrefix("/user");    }    @Override    public void registerStompEndpoints(StompEndpointRegistry registry) {        registry                .addEndpoint("/ws")                .setAllowedOrigins("*")                .withSockJS();    }    @Override    public boolean configureMessageConverters(List<MessageConverter> messageConverters) {        DefaultContentTypeResolver resolver = new DefaultContentTypeResolver();        resolver.setDefaultMimeType(MimeTypeUtils.APPLICATION_JSON);        MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();        converter.setObjectMapper(new ObjectMapper());        converter.setContentTypeResolver(resolver);        messageConverters.add(converter);        return false;    }}


Первый метод конфигурирует простой брокер сообщений в памяти с одним адресом с префиксом /user для отправки и получения сообщений. Адреса с префиксом /app предназначены для сообщений, обрабатываемых методами с аннотацией @MessageMapping, которые мы обсудим в следующем разделе.

Второй метод регистрирует конечную точку STOMP /ws. Эта конечная точка будет использоваться клиентами для подключения к STOMP-серверу. Здесь также включается резервный SockJS, который будет использоваться, если WebSocket будет недоступен.

Последний метод настраивает конвертер JSON, который используется Spring'ом для преобразования сообщений из/в JSON.

Контроллер для обработки сообщений


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

@Controllerpublic class ChatController {    @Autowired private SimpMessagingTemplate messagingTemplate;    @Autowired private ChatMessageService chatMessageService;    @Autowired private ChatRoomService chatRoomService;    @MessageMapping("/chat")    public void processMessage(@Payload ChatMessage chatMessage) {        var chatId = chatRoomService                .getChatId(chatMessage.getSenderId(), chatMessage.getRecipientId(), true);        chatMessage.setChatId(chatId.get());        ChatMessage saved = chatMessageService.save(chatMessage);                messagingTemplate.convertAndSendToUser(                chatMessage.getRecipientId(),"/queue/messages",                new ChatNotification(                        saved.getId(),                        saved.getSenderId(),                        saved.getSenderName()));    }}


С помощью аннотации @MessageMapping мы настраиваем, что при отправке сообщения в /app/chat вызывается метод processMessage. Обратите внимание, что к маппингу добавится сконфигурированный ранее application-префикс /app.

Этот метод сохраняет сообщение в MongoDB, а затем вызывает метод convertAndSendToUser для отправки уведомления адресату.

Метод convertAndSendToUser добавляет префикс /user и recipientId к адресу /queue/messages. Конечный адрес будет выглядеть так:

/user/{recipientId}/queue/messages


Все подписчики данного адреса (в нашем случае один) получат сообщение.

Генерация chatId


Для каждой беседы между двумя пользователями мы создаем чат-комнату и для ее идентификации генерируем уникальный chatId.

Класс ChatRoom выглядит следующим образом:

public class ChatRoom {    private String id;    private String chatId;    private String senderId;    private String recipientId;}


Значение chatId равно конкатенации senderId_recipientId. Для каждой беседы мы сохраняем две сущности с одинаковыми chatId: одну между отправителем и получателем, а другую между получателем и отправителем, чтобы оба пользователя получали одинаковый chatId.

JavaScript-клиент


В этом разделе мы создадим JavaScript-клиента, который будет отправлять сообщения на WebSocket/STOMP-сервер и получать их оттуда.

Мы будем использовать SockJS и Stomp.js для общения с сервером с использованием STOMP over WebSocket.

const connect = () => {    const Stomp = require("stompjs");    var SockJS = require("sockjs-client");    SockJS = new SockJS("http://localhost:8080/ws");    stompClient = Stomp.over(SockJS);    stompClient.connect({}, onConnected, onError);  };


Метод connect() устанавливает соединение с /ws, где ожидает подключений наш сервер, и также определяет callback-функцию onConnected, которая будет вызвана при успешном подключении, и onError, вызываемую, если при подключении к серверу произошла ошибка.

const onConnected = () => {    console.log("connected");    stompClient.subscribe(      "/user/" + currentUser.id + "/queue/messages",      onMessageReceived    );  };


Метод onConnected() подписывается на определенный адрес и получает все отправляемые туда сообщения.

const sendMessage = (msg) => {    if (msg.trim() !== "") {      const message = {        senderId: currentUser.id,        recipientId: activeContact.id,        senderName: currentUser.name,        recipientName: activeContact.name,        content: msg,        timestamp: new Date(),      };              stompClient.send("/app/chat", {}, JSON.stringify(message));    }  };


В конце метода sendMessage() сообщение отправляется по адресу /app/chat, который указан в нашем контроллере.

Заключение


В этой статье мы рассмотрели все важные моменты создания чата с использованием Spring Boot и STOMP over WebSocket.
Мы также создали JavaScript-клиент с применением библиотек SockJs и Stomp.js.

Пример исходного кода можно найти здесь.



Узнать о курсе подробнее.




Читать ещё:


Источник: habr.com
К списку статей
Опубликовано: 26.08.2020 18:04:13
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Блог компании otus. онлайн-образование

Разработка веб-сайтов

Программирование

Java

Programming

Spring boot

Web development

Websocket

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru