背景:主要是为了实现一个实时数据大屏,因为需要实时数据刷新,所以需要不停的从服务器获取数据库最新数据,最开始的想到是否可以前端使用定时器不断向服务器发送ajax请求数据,但这样的弊端便是会导致服务器的压力很大,所以后来在网上看到一个框架goeasy,一个实时的web消息推送服务,因为数据大屏对应不同的图表数据来源不同,而恰好goeasy又有可以订阅不同的频道,推送对应的消息,在这点的前提之下,我在后台再使用spring的定时器,就可对应频道推送对应数据,这样的实现效果挺好,但是他们的服务收费,虽然收费不高,不过后来觉得是否可以使用websocket来实现一个类似的功能,在网上了解到websocket_stomp可以实现订阅的功能,于是决定模范goeasy做一个类似的,订阅-发布功能,此记下记录。
声明:由于是做数据大屏不需要接收websocket消息只需要推送,所以这里没有接收websocket消息对应的代码
技术:websocket+stomp,spring schedule
========pom包导入========
org.springframework
spring-orm
${spring.version}
org.springframework
spring-websocket
${spring.version}
org.springframework
spring-messaging
${spring.version}
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启用注解驱动及定时器线程池
属性解释: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 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 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并订阅频道
效果图如下:
结语:到这里websocket_stomp+定时器的功能就实现了,我使用的echarts显示数据,这里就不贴对应的代码了,只需要实现可以定时推送对应频道的数据到前端就好了,毕竟有了数据,前端显示数据根据前端框架或自己的需要即可。
推荐一篇参考文章:https://blog.csdn.net/elonpage/article/details/78446695?locationNum=5&fps=1