如何结合 Spring REST 和 WebSocket?

Posted

技术标签:

【中文标题】如何结合 Spring REST 和 WebSocket?【英文标题】:How to combine Spring REST and WebSocket? 【发布时间】:2021-01-25 20:02:52 【问题描述】:

我是 Spring 新手,正在从事一个大学项目。

目标:拥有一个 REST POST 端点,既可以保存数据,又可以使用 websocket 发送广播消息。

现在,我的 RestController 似乎工作正常,但真的不知道如何实现 websocket 部分?

这是端点的样子:

@PostMapping("/employees")
 Employee newEmployee(@RequestBody Employee newEmployee) 
    return repository.save(newEmployee);
 

我之前的想法:

-使用带有@SendTo 注解的方法创建@Controller?

-我可以在 RestController newEmployee 方法上使用@SendTo 吗?

什么是最有效的方法?

【问题讨论】:

【参考方案1】:

就像spring提供了@RestController一样,它也提供了@EnableWebSocket注解和处理双向通信的方法,下面是spring创建websocket连接的分步方法 首先创建一个配置类来制作我们的 WebSocketConnection 类 bean,它将作为 websocket 连接、断开连接和来自客户端的消息的处理程序,并将其添加到 WebSocketHandlerRegister 及其命名空间。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

@Configuration
@EnableWebSocket
public class WebSocketConfiguration implements WebSocketConfigurer 

    @Bean
    public WebSocketConnection getWebSocketConnection() 
        return new WebSocketConnection();
    

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) 
        webSocketHandlerRegistry.addHandler(getWebSocketConnection(), "/websocket");
    

现在让我们创建 WebSocketConnection 类

public class WebSocketConnection  extends TextWebSocketHandler 

    private static final Logger log = LoggerFactory.getLogger(WebSocketConnection.class);

    private static final Gson gson = new GsonBuilder().create();

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception 
        log.info("connected with the websocket client : " + session.getId());
    

    @Override
    public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception 
        JsonObject parsedMessage = gson.fromJson(message.getPayload(), JsonObject.class);

        log.info("The message got from the client is " + parsedMessage);

        JsonObject responseMessage = new JsonObject();
        responseMessage.addProperty("response", "Your response was recorded by the server");
        responseMessage.addProperty("messageReceivedtime", LocalDateTime.now().toLocalDate().toString());
        int max = 100;
        int min = 20;
        responseMessage.addProperty("randomNo", (int) Math.floor(Math.random() * (max - min + 1) + min));

        session.sendMessage(new TextMessage(responseMessage.toString())); //sending message back to the client
    

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception 
        log.info("connection closed from the websocket client : " + session.getId());
    

到这里就完成了。 现在从 javascript 的客户端,你将不得不像下面那样制作 websocket 客户端对象

const webSocketClient = new WebSocket('ws://localhost:port/websocket');
//const webSocketClient = new WebSocket('wss://ip:port/websocket') for cases of secure connection

关于javascript中WebSocket客户端的更多信息,请参考这个https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications

您提到了您的目标,即 '有一个保存数据的 REST POST 端点,但也使用 websocket 发送广播消息'不应该在 1 中。 您可以做的是,当用户保存数据时,您可以将服务器的响应返回给已保存数据的用户,然后让该用户向 websocket 服务器发送消息,websocket 服务器将广播给其他用户。

【讨论】:

您好,女士。感谢你的回答。如何在 RestController 中使用这个 Handler? @jhthewow,您可以将 WebSocketConnection 类视为本身具有请求映射'/websocket'的控制器 我想要实现的流程如下: 1. 用户向定义的 REST 端点发送 POST 请求(在描述中) 2. 端点做了两件事:(a)保存数据 -this工作 - (b) 使用 websocket 将数据作为广播消息发送给订阅的客户端。我需要 (b) 方面的帮助。命中 POST 端点后,如何从 RestController 发送消息?

以上是关于如何结合 Spring REST 和 WebSocket?的主要内容,如果未能解决你的问题,请参考以下文章

Spring REST(转)

ElasticSearch 7.3 结合Spring boot进行增删改查和批量(bulk)详解

微服务是不是可以结合 REST 和消息传递?

Spring Cloud入门 - REST客户端Feign

春天。 REST API 的实现 Oauth.2.0

如何使用 Spring Security 和 Angularjs 保护 Spring Rest 服务?