Протокол STOMP - основан на реализации Websocket

задняя часть

Продолжая протокол STOMP для Websocket сегодня, из-за его простой конструкции и легкости использования при разработке клиентов его можно увидеть на многих языках, и он не является «эксклюзивным» для websocket.

определение

STOMP (простой/потоковый протокол обмена текстовыми сообщениями), простой (потоковый) протокол обмена текстовыми сообщениями. Протокол, принадлежащий очереди сообщений, чем-то похожий на jms.

эффект

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

Знакомство с персонажами

Источник изображения "Весна в действии"

  • Клиент-производитель: отправить сообщение получателю;
  • Потребительский клиент: получайте сообщения, отправленные подписанным пунктом назначения;
  • Канал запроса: пул потоков, который получает сообщения, отправленные производителями;
  • Соответствующий канал: пул потоков, который отправляет сообщения потребителям;
  • Брокер: диспетчер очереди сообщений.Записывает, какие клиенты подписываются на какой пункт назначения.
  • Адрес назначения приложения: Прежде чем сообщение, отправленное на этот тип адреса назначения, достигнет брокера, оно будет перенаправлено на метод, написанный приложением.Это эквивалентно перехвату сообщения, поступающего в брокер один раз, чтобы выполнить некоторую бизнес-обработку сообщение———"/app" на картинке
  • Адрес назначения, не относящийся к приложению: сообщения, отправленные на этот тип адреса назначения, будут направляться непосредственно брокеру и не будут перехвачены приложением — «/topic» на рисунке.

Технологический поток

  • Производитель отправляет сообщение получателю
  • запросить канал для приема сообщений
  • Если адрес назначения является адресом назначения приложения (/app), перейдите к соответствующему бизнес-методу, написанному самим приложением для обработки, а затем перейдите к брокеру.
  • Если адрес назначения не является адресом назначения (/topic), перейдите непосредственно к broker.broker, чтобы создать сообщение, а затем отправить сообщение всем потребителям, подписавшимся на этот адрес назначения, через соответствующий канал.

Код

Следующее использует SpringSecurity и WebSocket-STOMP для реализации функции обмена сообщениями "точка-точка":

Включить функцию STOMP

@Configuration
@EnableWebSocketMessageBroker//开启消息代理
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    /**
     * 建立连接点信息
     * @param registry
     */
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws/ep").withSockJS();
         registry.setApplicationDestinationPrefixes("/app");
    }

    /**
     * 配置消息队列
     * 基于内存的STOMP消息代理
     * @param registry
     */
    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/queue");
    }
}
  • Зарегистрируйте «/ws/ep» как конечную точку STOMP. Клиенты должны подключаться к этой конечной точке, прежде чем подписываться или публиковать сообщения по пути назначения.
  • Сообщения, начинающиеся с /app, будут направляться методам, аннотированным с помощью @MessageMapping или @SubscribeMapping;
  • Сообщения, начинающиеся с /queue, будут отправлены брокеру STOMP.В зависимости от выбранного брокера STOMP необязательный префикс адресата также будет ограничен;
  • Сообщения, начинающиеся с /user, будут перенаправлять сообщение в место назначения, уникальное для пользователя.

Обработка сообщений STOMP

пользовательский протокол связи

@Controller
public class WScontroller {

    @Autowired//消息发送模板
    SimpMessagingTemplate simpMessagingTemplate;

    @MessageMapping("/ws/chat")
    public void receiveMessage(String message, Principal principal) {
        String[] split = message.split(";");
        HashMap<String, Object> map = new HashMap<>();
        map.put("username",split[1]);
        map.put("msg",split[0]);
        simpMessagingTemplate.convertAndSendToUser(split[1], "/queue/msg",map);
    }
  • Получить сообщение, отправленное клиентом, параметром является само сообщениеmessage
  • Аннотации @MessageMapping или @SubscribeMapping могут обрабатывать сообщения, отправленные клиентом, и выбирать, имеет ли метод возвращаемое значение.
  • @MessageMapping указывает, что пунктом назначения является «/app/ws/chat» (префикс «/app» подразумевается, поскольку мы настроили его как префикс назначения для приложения).
  • Протокол связи можно настроить - формат настраиваемых параметров
  • Может получать данные в формате json, не нужно добавлять дополнительную аннотацию @Requestbody при передаче данных josn
  • Отправитель сообщения не передается из внешнего интерфейса, а получается из springsecurity, чтобы предотвратить олицетворение внешнего интерфейса.
  • Если аннотированный метод контроллера @MessageMapping имеет возвращаемое значение, возвращаемое значение будет отправлено брокеру сообщений, но с префиксом «/topic».
  • Переопределите пункт назначения, аннотировав метод с помощью @SendTo.

Реализация клиента

Код клиента (UVE)

<template>
  <div>
    <div>
      <div v-for="(m,index) in ms">{{m.username}}:{{m.msg}}</div>

    </div>
    <el-input v-model="msg"></el-input>
    <el-button @click="sendMsg"></el-button>
  </div>
</template>

<script>
  import "../../lib/sockjs"
  import "../../lib/stomp"
    export default {
        name: "FriendChat",
      data() {
        return {
          msg: '',
          ms: [],
          stomp: null
        };
      },
      mounted() {
        this.intCon();
      },
      methods: {
        // 建立连接
        initCon() {
          let _this = this;
           this.stomp = Stomp.over(new SockJS("/ws/ep"));
            this.stomp.connect({},success=>{
              _this.stomp.subscribe("/user/queue/msg",msg=>{
                _this.ms.push(JSON.parse(msg.body));
              })
            },fail=>{

            })
        },
        // 发送消息
        sendMsg() {
          this.stomp.send("/ws/chat",{},this.msg)
        }
      }
    }
</script>
<style scoped>
</style>