websocket实现订阅频道及定时推送对应频道数据

背景:主要是为了实现一个实时数据大屏,因为需要实时数据刷新,所以需要不停的从服务器获取数据库最新数据,最开始的想到是否可以前端使用定时器不断向服务器发送ajax请求数据,但这样的弊端便是会导致服务器的压力很大,所以后来在网上看到一个框架goeasy,一个实时的web消息推送服务,因为数据大屏对应不同的图表数据来源不同,而恰好goeasy又有可以订阅不同的频道,推送对应的消息,在这点的前提之下,我在后台再使用spring的定时器,就可对应频道推送对应数据,这样的实现效果挺好,但是他们的服务收费,虽然收费不高,不过后来觉得是否可以使用websocket来实现一个类似的功能,在网上了解到websocket_stomp可以实现订阅的功能,于是决定模范goeasy做一个类似的,订阅-发布功能,此记下记录。

声明:由于是做数据大屏不需要接收websocket消息只需要推送,所以这里没有接收websocket消息对应的代码

技术:websocket+stomp,spring schedule

========pom包导入========

        <!-- spring socket -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-websocket</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-messaging</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- spring socket -->

1.首先websoket的配置,使用注解方式

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;


/**
   * @author HeJD
   * @date 2018/9/3 16:58
   * @Description:WebSocket配置类
   */
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
       /*
         * 用户可以订阅来自以"/topic"为前缀的消息,
         * 客户端只可以订阅这个前缀的主题
         */
        config.enableSimpleBroker("/topic");
        /*
         * 客户端发送过来的消息,需要以"/app"为前缀,再经过Broker转发给响应的Controller,
         * 我这里基本没用到,声明有说
         */
        config.setApplicationDestinationPrefixes("/app");

    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
         /*
          * 路径"/webSocketEndPoint"被注册为STOMP端点,对外暴露,客户端通过该路径接入WebSocket服务
          */
       registry.addEndpoint("websocket/socketServer.action");
    }

}

2.spring schedule的配置,使用注解的方式,applicationContext.xml中

2.1命名空间加入

xmlns:task="http://www.springframework.org/schema/task" 
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.1.xsd

2.2启用注解驱动及定时器线程池

        <!-- scheduler -->
        <task:annotation-driven scheduler="myScheduler"/>
        <task:scheduler id="myScheduler" pool-size="5"/>

属性解释:pool-size,开启五个线程,spring schedule默认是单线程,开启5个线程可以让定时任务之间互不干扰,官网推荐1-10

3.使用定时器,开启定时任务

/**
 * @Auther: HeJD
 * @Date: 2018/8/29 17:18
 * @Description:
 */
@Component
public class TaskServiceImpl implements TaskService {

    private Logger log=Logger.getLogger(XgqTaskDepotServiceImpl.class);

    //取数据的Dao
    @Autowired
    private OrderMapper orderMapper;

    //这个就是我们可以指定频道推送对应数据的对象
    @Autowired
    private SimpMessagingTemplate simpMessagingTemplate;


    @Scheduled(cron="0/10 * *  * * ? ")   //CRON表达式每10秒执行一次
    @Override
    public void selectCurDayDepotOrderInfo() {
        log.info("=====================AAA频道每10秒执行一次刷新=====================");
        List<orderVo> orderVoVoList = orderMapper.selectCurDayOrderInfo();
        EchartsVo echartsVo=this.assembleEchartsVo(orderVoVoList );
        simpMessagingTemplate.convertAndSend(Const.Channel.AAA_CHANNEL.getName(),echartsVo);
    }

    @Scheduled(cron="0/13 * *  * * ? ")
    @Override
    public void selectCustomerOrderInfo() {
        log.info("=====================BBB频道每13秒执行一次刷新=====================");
        List<orderVo> orderVoVoList =  orderMapper.selectCustomerOrderInfo();
        simpMessagingTemplate.convertAndSend(Const.Channel.BBB_CHANNEL.getName(), orderVoVoList);
    }
}

3.1,自定义频道的枚举常量,记录频道序号和频道名

/**
 * 全局常量类
 * @author HeJD
 * @date 2018年7月12日
 */
public class Const { 
   /**
	 * webSocket订阅频道枚举
	 */
	public enum Channel{

		AAA_CHANNEL(1,"/topic/AAA"),
		BBB_CHANNEL(2,"/topic/BBB");

		private final int code;
		private final String name;

		Channel(int code, String name) {
			this.code = code;
			this.name = name;
		}
		public String getName() {
			return name;
		}
	}
}

4.前端连接websokect并订阅频道

    <script src="${cms_path}/res/js/jquery-2.0.3.min.js"></script>
    <script src="${cms_path}/res/js/echarts.common.min.js"></script>
    <script src="${cms_path}/res/js/sockjs-client/sockjs.min.js"></script>
    <script src="${cms_path}/res/js/stomp-websocket/stomp.js"></script>
    <script src="${cms_path}/res/js/websocket-reconnection/reconnecting-websocket.min.js"></script>

<script type="text/javascript">
   var url=getUrl();
    var  socket = new ReconnectingWebSocket(url);   //WebSocket对应的地址
    stompClient = Stomp.over(socket);
    var headers={
        username:'admin',
        password:'admin'
    };
    stompClient.connect(headers, function (frame) {
        setConnected(true);
        console.log('Connected: ' + frame);
        //订阅AAA频道
        stompClient.subscribe('/topic/AAA', function (greeting) {
             //后台传过来的json字符串转换为json对象 
              var obj=  JSON.parse(greeting.body);
             //处理并显示数据 
        });
       //订阅BBB频道
        stompClient.subscribe('/topic/BBB', function (greeting) {
             //后台传过来的json字符串转换为json对象 
              var obj=  JSON.parse(greeting.body);
             //处理并显示数据 
        });
    });

//获取项目路径
 function getUrl() {
     var strFullPath=window.document.location.href;
     var strPath=window.document.location.pathname;
     var pos=strFullPath.indexOf(strPath);
     var prePath=strFullPath.substring(0,pos);
     var postPath=strPath.substring(0,strPath.substr(1).indexOf('/')+1);
     var basePath = prePath+postPath;
     var url=basePath.replace("http","ws")+"//websocket/socketServer.action";
     return url
 }
</script>

效果图如下:

结语:到这里websocket_stomp+定时器的功能就实现了,我使用的echarts显示数据,这里就不贴对应的代码了,只需要实现可以定时推送对应频道的数据到前端就好了,毕竟有了数据,前端显示数据根据前端框架或自己的需要即可。

推荐一篇参考文章:https://blog.csdn.net/elonpage/article/details/78446695?locationNum=5&fps=1

  • 10
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值