拨开荷叶行,寻梦已然成。仙女莲花里,翩翩白鹭情。
IMG-LOGO
主页 文章列表 使用Spring Boot的定时WebSocket推送

使用Spring Boot的定时WebSocket推送

白鹭 - 2021-11-24 410 0 0

1.概述

在本教程中,我们将看到如何使用WebSockets将计划的消息从服务器发送到浏览器。一种替代方法是使用服务器发送的事件(SSE),但我们将不在本文中介绍。

Spring提供了各种调度选项。首先,我们将介绍@Scheduled注释。然后,我们将看到由Project Reactor提供的‘Flux::interval’方法的示例。该库对于Webflux应用程序是开箱即用的,并且可以在任何Java项目中用作独立库。

此外,还存在更高级的机制,例如Quartz调度程序,但我们不会对其进行介绍。

2.一个简单的聊天应用程序

在上一篇文章中,我们使用WebSockets构建了一个聊天应用程序。让我们用一个新功能扩展它:聊天机器人。这些漫游器是服务器端组件,可将计划的消息推送到浏览器。

2.1。 Maven依赖

让我们从在Maven中设置必要的依赖关系开始。要构建此项目,我们的pom.xml应该具有:

<dependency>

 <groupId>org.springframework.boot</groupId>

 <artifactId>spring-boot-starter-websocket</artifactId>

 </dependency>

 <dependency>

 <groupId>io.projectreactor</groupId>

 <artifactId>reactor-core</artifactId>

 </dependency>

 <dependency>

 <groupId>com.github.javafaker</groupId>

 <artifactId>javafaker</artifactId>

 <version>1.0.2</version>

 </dependency>

 <dependency>

 <groupId>com.google.code.gson</groupId>

 <artifactId>gson</artifactId>

 </dependency>

2.2。 JavaFaker依赖关系

我们将使用JavaFaker库来生成机器人的消息。该库通常用于生成测试数据。在这里,我们将一个名为“ Chuck Norris ”的访客添加到我们的聊天室。

让我们看一下代码:

Faker faker = new Faker();

 ChuckNorris chuckNorris = faker.chuckNorris();

 String messageFromChuck = chuckNorris.fact();

Faker将为各种数据生成器提供工厂方法。我们将使用ChuckNorris生成器。调用chuckNorris.fact()将显示预定义消息列表中的随机句子。

2.3。消息模型

聊天应用程序使用简单的POJO作为消息包装器:

public class OutputMessage {



 private String from;

 private String text;

 private String time;



 // standard constructors, getters/setters, equals and hashcode

 }

放在一起,这是我们如何创建聊天消息的示例:

OutputMessage message = new OutputMessage(

 "Chatbot 1", "Hello there!", new SimpleDateFormat("HH:mm").format(new Date())));

2.4。客户端

我们的聊天客户端是一个简单的HTML页面。它使用SockJS客户端STOMP消息协议。

让我们看看客户端如何订阅主题:

<html>

 <head>

 <script src="./js/sockjs-0.3.4.js"></script>

 <script src="./js/stomp.js"></script>

 <script type="text/javascript">

 // ...

 stompClient = Stomp.over(socket);




 stompClient.connect({}, function(frame) {

 // ...

 stompClient.subscribe('/topic/pushmessages', function(messageOutput) {

 showMessageOutput(JSON.parse(messageOutput.body));

 });

 });

 // ...

 </script>

 </head>

 <!-- ... -->

 </html>

首先,我们通过SockJS协议创建了一个Stomp客户端。然后,主题订阅充当服务器与连接的客户端之间的通信通道。

在我们的存储库中,此代码位于webapp/bots.html 。我们在http:// localhost:8080 / bots.html本地运行时访问它。当然,我们需要根据部署应用程序的方式来调整主机和端口。

2.5。服务器端

在上一篇文章中,我们已经了解了如何在Spring中配置WebSocket。让我们对配置进行一些修改:

@Configuration

 @EnableWebSocketMessageBroker

 public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {



 @Override

 public void configureMessageBroker(MessageBrokerRegistry config) {

 config.enableSimpleBroker("/topic");

 config.setApplicationDestinationPrefixes("/app");

 }



 @Override

 public void registerStompEndpoints(StompEndpointRegistry registry) {

 // ...

 registry.addEndpoint("/chatwithbots");

 registry.addEndpoint("/chatwithbots").withSockJS();

 }

 }

为了推送消息,我们使用实用程序类SimpMessagingTemplate 。默认情况下,它在Spring Context中以@Bean提供。我们可以看到当AbstractMessageBrokerConfiguration在类路径中时如何通过自动配置声明它。因此,我们可以将其注入到任何Spring组件中。

之后,我们使用它来将消息发布到主题/topic/pushmessages 。我们假设我们的类将那个bean注入了一个名为simpMessagingTemplate的变量中:

simpMessagingTemplate.convertAndSend("/topic/pushmessages",

 new OutputMessage("Chuck Norris", faker.chuckNorris().fact(), time));

如前面的客户端示例所示,客户端订阅该主题以在消息到达时对其进行处理。

3.安排推送消息

在Spring生态系统中,我们可以从多种调度方法中进行选择。如果我们使用Spring MVC,则@Scheduled注释由于其简单性而成为自然选择。如果我们使用Spring Webflux,我们也可以使用Project Reactor的Flux::interval方法。我们将看到每个示例。

3.1。配置

我们的聊天机器人将使用JavaFaker的Chuck Norris生成器。我们将其配置为Bean,以便可以将其注入所需的位置。

@Configuration

 class AppConfig {



 @Bean

 public ChuckNorris chuckNorris() {

 return (new Faker()).chuckNorris();

 }

 }

3.2。使用@Scheduled

我们的示例机器人是预定方法。当他们运行时,他们使用SimpMessagingTemplate通过WebSocket发送我们的OutputMessage POJO。

顾名思义,@ @Scheduled批注允许重复执行method 。有了它,我们可以使用基于速率的简单调度或更复杂的“ cron”表达式。

让我们编写第一个聊天机器人的代码:

@Service

 public class ScheduledPushMessages {



 @Scheduled(fixedRate = 5000)

 public void sendMessage(SimpMessagingTemplate simpMessagingTemplate, ChuckNorris chuckNorris) {

 String time = new SimpleDateFormat("HH:mm").format(new Date());

 simpMessagingTemplate.convertAndSend("/topic/pushmessages",

 new OutputMessage("Chuck Norris (@Scheduled)", chuckNorris().fact(), time));

 }



 }

我们用@Scheduled(fixedRate = 5000).注释sendMessage方法@Scheduled(fixedRate = 5000).这使sendMessage每五秒钟运行一次。然后,我们使用simpMessagingTemplate实例将OutputMessage发送到主题。 simpMessagingTemplatechuckNorris实例从Spring上下文作为方法参数注入。

3.3。使用Flux::interval()

如果使用WebFlux,则可以使用[Flux::interval](https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Flux.html#interval-java.time.Duration-)运算符。它将发布的无限流Long通过选择分隔的项D uration

现在,让我们在前面的示例中使用Flux。目标是每五秒钟发送一次Chuck Norris的报价。首先,我们需要实现InitializingBean接口以在应用程序启动时订阅Flux

@Service

 public class ReactiveScheduledPushMessages implements InitializingBean {



 private SimpMessagingTemplate simpMessagingTemplate;



 private ChuckNorris chuckNorris;



 @Autowired

 public ReactiveScheduledPushMessages(SimpMessagingTemplate simpMessagingTemplate, ChuckNorris chuckNorris) {

 this.simpMessagingTemplate = simpMessagingTemplate;

 this.chuckNorris = chuckNorris;

 }



 @Override

 public void afterPropertiesSet() throws Exception {

 Flux.interval(Duration.ofSeconds(5L))

 // discard the incoming Long, replace it by an OutputMessage

 .map((n) -> new OutputMessage("Chuck Norris (Flux::interval)",

 chuckNorris.fact(),

 new SimpleDateFormat("HH:mm").format(new Date())))

 .subscribe(message -> simpMessagingTemplate.convertAndSend("/topic/pushmessages", message));

 }

 }

在这里,我们使用构造函数注入来设置simpMessagingTemplatechuckNorris实例。这次,调度逻辑在afterPropertiesSet(),我们在实现InitializingBean时将其重写。服务启动后,该方法将立即运行。

interval运算符每五秒钟发出一个Long 。然后, map运算符会丢弃该值,并将其替换为我们的消息。最后,我们subscribe Flux来触发每条消息的逻辑。

4。结论

在本教程中,我们已经看到实用程序类SimpMessagingTemplate使通过WebSocket推送服务器消息变得容易。此外,我们已经看到了两种调度一段代码执行的方式。

标签:

0 评论

发表评论

您的电子邮件地址不会被公开。 必填的字段已做标记 *