websocket+sockjs公告通知【基于STOMP协议】

154 阅读2分钟

前言: 消息推送技术,之前你可能用过 Ajax 轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。有了长连接的websocket,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。 WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。 WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

webSocket的配置文件

@Configuration
/**
 * 注解开启使用STOMP协议来传输基于代理(message broker)的消息
 */
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    /*@Resource
    private GetHeaderParamInterceptor getHeaderParamInterceptor;*/
    /**
     * 注册stomp的端点
     */
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        // 允许使用socketJs方式访问,允许跨域
        // 在网页上我们就可以通过这个链接
        // http://localhost:8080//ws/endpointChat
        // 来和服务器的WebSocket连接
        registry.addEndpoint("/ws/endpointChat")
                .setAllowedOrigins("*")
                .withSockJS();
    }
    @Override
    /**
     * 配置消息代理
     */
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        //点对点queue,广播式topic
        registry.enableSimpleBroker("/queue","/topic");
        //registry.setUserDestinationPrefix("/user");
    }

    /**
    * @Description  采用自定义拦截器   获取connect时候传递的参数
    * @Author  mk
    * @Date   2020/12/17 9:47
    * @Param
    * @Return
    *
    */
   /* @Override
    public void configureClientInboundChannel(ChannelRegistration registration) {
        registration.interceptors(getHeaderParamInterceptor);
    }*/

}

websocket处理类controller

@Controller
public class WsController {
    @MessageMapping("/ws/nf")
    @SendTo("/topic/nf")
    public String handleNF() {
        return "公告通知";
    }
}

前端代码

const actions = {
  connect(context){
    context.state.stomp = Stomp.over(new SockJS("http://39.104.74.107:9090/ws/endpointChat"));
    context.state.stomp.connect({}, frame=> {
      
      //公告
      context.state.stomp.subscribe("/topic/nf", message=> {
        context.commit('toggleNFDot', true);
      });

    }, failedMsg=> {

    });
  }
}

const mutations = {
  toggleNFDot(state, newValue){
    state.nfDot = newValue;
  },
}

用户发送系统通知,在系统通知保存到数据库后,发送websocket消息

 sendNFMsg(){
        this.dialogLoading = true;
        var _this = this;
        SendMsg({message: this.message, title: this.title}).then(resp=> {
          _this.dialogLoading = false;
          if (resp && resp.status == 200) {
            var data = resp.data;
            _this.$message({type: "success", message: resp.data.msg});
            if (resp.data.code == 2000000) {
             _this.$store.state.stomp.send("/ws/nf", {}, '');
              _this.initSysMsgs();
              _this.cancelSend();
            }
          }
        })
      },

用户进入home页面,发起后端请求,看是否有未读消息,来控制闹钟小红点的显示

initSysMsgs(){
        var _this = this;
        getMsg().then(resp=> {
          _this.sysmsgs=resp.data.data;
          var isDot = false;
          resp.data.data.forEach(msg=> {
            if (msg.state == 0) {
              isDot = true;
            }
          })
          _this.$store.commit('toggleNFDot', isDot);
        })
      }

效果图: 在这里插入图片描述

参考自“江南一点雨”大神的vhr项目