spring 整合websoket(整理)

大城市里の小女人 提交于 2019-12-10 16:21:17

定义:

  • sockjs.js:  浏览器JavaScript库,它提供了一个类似于网络的对象。SockJS提供了一个连贯的、跨浏览器的Javascript API,它在浏览器和web服务器之间创建了一个低延迟、全双工、跨域通信通道。

  • STOMP:简单(流)文本定向消息协议,它提供了一个可互操作的连接格式,允许STOMP客户端与任意STOMP消息代理(Broker)进行交互。有点像TCP和HTTP之间的关系,在websocket的通信中,有了STOMP协议后,客户端和服务端能够以更友好的方式进行交流。如果没有提供第三方的STOMP代理,比如Rabbitmq等,那么使用的就是spring容器自己提供的STOMP代理。

关系:

能够使用sock.js建立websocket的客户端连接。websocket可以使用STOMP协议作为传输的协议。

样例代码如下:

  • 定义WebSocketMessageBrokerConfigurer,一般是继承自AbstractWebSocketMessageBrokerConfigurer:
@Configuration
@EnableWebSocketMessageBroker  //在 WebSocket 上启用 STOMP
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        /**
         * 启用了STOMP代理中继功能:并将其目的地前缀设置为 "/topic";
         * spring就能知道 所有目的地前缀为"/topic" 的消息都会发送到STOMP代理中;
         */
        config.enableSimpleBroker("/topic", "/user");
        /**
         * 设置了应用的前缀为"app":所有目的地以"/app"打头的消息(发送消息url not连接url)
         * 都会路由到带有@MessageMapping注解的方法中,而不会发布到代理队列或主题中;
         */
        config.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/webSocket").setAllowedOrigins("*").withSockJS();
    }

}

  1. registerStompEndpoints:注册websocket的端点地址,也就是客户端连接的地址,在上面的配置中,客户端连接的地址是:http://ip:port/项目名/websocket
  2. setAllowedOrigins:上面的代码中表示是所有的ip地址都能够连接,也可以对固定的地址进行过滤。
  3. sockjs():提供对sockjs访问的支持。

websocket一般有两种应用场景:

  • 客户端订阅到服务端,这个时候服务端会处理一些客户端的信息,比如将客户端的信息注册到服务端的列表之中。
  • 服务端收到消息后进行推送到客户端。

上面的配置中:

  • /app:代表客户端直接发送给服务端的消息,不需要经过stomp消息代理,将由@MessageMapping的直接处理,并返回消息。
    例如:客户端发送的消息:
stompClient.send("/app/webSocket/updateDevice", {}, JSON.stringify(req));  

/app/websockt/send将由下面的代码来进行处理:

 @MessageMapping("/webSocket/send")
    public void updateDevice(SimpMessageHeaderAccessor headerAccessor, String requestContent)
        throws Exception {
        SubscriptionMsg msg = JSON.parseObject(requestContent, SubscriptionMsg.class);
        System.out.println(msg);
    }

STOMP消息代理的配置如下:

 config.enableSimpleBroker("/topic", "/user");

客户端使用stompClient.subscribe("/topic/theme"),将通过STOMP订阅在这个topic的主题.

  • 发送消息到单个/user通道:
  @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
//        registry.setPathMatcher(new AntPathMatcher("."));//可以已“.”来分割路径,看看类级别的@messageMapping和方法级别的@messageMapping
 
        registry.enableSimpleBroker("/topic","/user");
        registry.setUserDestinationPrefix("/user/");
        registry.setApplicationDestinationPrefixes("/app");//走@messageMapping
    }
@RequestMapping("/app")
@Controller
public class WebSocketController {
    @Resource
    private SimpMessagingTemplate simpMessagingTemplate;
 
    @MessageMapping("/hello")
//  @SendTo("/topic/hello")//会把方法的返回值广播到指定主题(“主题”这个词并不合适)
    public void toTopic(SocketMessageVo msg , String name) {
        System.out.println(msg.getName()+","+msg.getMsg());
        this.simpMessagingTemplate.convertAndSend("/topic/hello",msg.getName()+","+msg.getMsg());
//      return "消息内容:"+ msg.getName()+"--"+msg.getMsg();
    }
 
    @MessageMapping("/message")
//  @SendToUser("/message")//把返回值发到指定队列(“队列”实际不是队列,而是跟上面“主题”类似的东西,只是spring在SendTo的基础上加了用户的内容而已)
    public void toUser(SocketMessageVo msg ) {
        System.out.println(msg.getName()+","+msg.getMsg());
        this.simpMessagingTemplate.convertAndSendToUser("123","/message",msg.getName()+msg.getMsg());
    }
 
    @RequestMapping("/sendMsg")
    public void sendMsg(HttpSession session){
        System.out.println("测试发送消息:随机消息" +session.getId());
        this.simpMessagingTemplate.convertAndSendToUser("123","/message","后台具体用户消息");
    }
}

总结一下:

WebSocketConfig 中配置setApplicationDestinationPrefixes()的消息会被转发到WebSocketController 中 @MessageMapping 相应方法进行处理。@SendTo("/topic/message") 会把方法的返回值序列化为json串,然后发送到指定的主题,不用此注解,使用 simpMessagingTemplate.convertAndSend 效果相同;若为 @SendToUser("/message") 则为发送到指定的用户队列(实际队列名字为/user/用户名/原队列名),不用此注解,使用 simpMessagingTemplate.convertAndSendToUser() 效果相同;

参考文档:https://www.cnblogs.com/nevermorewang/p/7274217.html

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!