WebSocket详解(Java后端,基于Springboot)

WebSocket的介绍

WebSocket是一种在单个TCP连接上进行全双工通信的协议。这种协议在2011年被IETF定为标准RFC 6455,并由RFC7936补充规范,同时WebSocket API也被W3C定为标准。它使得客户端和服务器之间的数据交换变得更加简单,特别是允许服务端主动向客户端推送数据。

WebSocket技术具有一系列显著特点:

  1. 实时性更高:WebSocket技术可以实现实时通信,传输数据的延迟更低,因此可以更快地将数据传输到客户端。
  2. 减少网络带宽的使用:通过建立一个持久化的连接,WebSocket减少了HTTP协议中每次请求和响应所需要的网络带宽。
  3. 双向通信:WebSocket技术支持全双工通信模式,即客户端和服务器可以同时发送和接收数据。
  4. 跨域支持:WebSocket技术可以跨不同的域进行通信。
  5. 安全性更高:WebSocket可以通过SSL/TLS协议实现加密通信,确保数据传输的安全性。

WebSocket的应用场景非常广泛,包括但不限于:

  • 即时通讯:如聊天应用、在线客服系统等,用户可以实时地发送和接收消息。
  • 实时数据展示:如实时股票行情、实时天气更新等,可以实时地推送数据给前端。
  • 多人游戏:WebSocket可以实现多人在线游戏,玩家可以实时地进行交互和通信。
  • 实时协作:如实时协同编辑器,多个用户可以同时编辑一个文档,并实时地看到其他用户的操作。
  • 数据监控:WebSocket可以用于实时监控系统的运行状态、日志更新等,便于及时发现和解决问题。

注意,WebSocket也存在一些潜在的问题,如兼容性问题(特别是在一些旧版本的浏览器上),服务器资源占用(由于需要维护大量的长连接),以及安全性问题(需要特殊的安全设置以防止恶意攻击和数据泄漏)。

1. 添加依赖(基于idea)

首先,你需要在你的pom.xml(如果你使用Maven)或build.gradle(如果你使用Gradle)中添加Spring Boot WebSocket的依赖。

对于Maven,添加以下依赖:

<dependencies>  
    <!-- Spring Boot Starter WebSocket -->  
    <dependency>  
        <groupId>org.springframework.boot</groupId>  
        <artifactId>spring-boot-starter-websocket</artifactId>  
    </dependency>  
    <!-- 如果你还需要HTTP功能 -->  
    <dependency>  
        <groupId>org.springframework.boot</groupId>  
        <artifactId>spring-boot-starter-web</artifactId>  
    </dependency>  
    <!-- 其他依赖... -->  
</dependencies>

对于Gradle,添加以下依赖:

dependencies {  
    // Spring Boot Starter WebSocket  
    implementation 'org.springframework.boot:spring-boot-starter-websocket'  
    // 如果你还需要HTTP功能  
    implementation 'org.springframework.boot:spring-boot-starter-web'  
    // 其他依赖...  
}

2. 配置WebSocket

接下来,你需要配置WebSocket端点。我们继承WebMvcConfigurationSupport。以下是一个简单的配置示例:


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * 开启WebSocket支持 配置websocket并开启
 */
@Configuration
public class WebSocketConfig extends WebMvcConfigurationSupport {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        super.addResourceHandlers(registry);
        // 相对路径
        registry.addResourceHandler("image/**").addResourceLocations("classpath:/static/image/");
        // 绝对路径
        // registry.addResourceHandler("image/**").addResourceLocations("file:" + "image/");
    }
}

上述代码的WebSocketConfig该类继承自WebMvcConfigurationSupport,并试图同时配置WebSocket和静态资源处理。然而,这种设计是有问题的,原因如下:

  1. 继承WebMvcConfigurationSupport: 继承WebMvcConfigurationSupport会关闭Spring Boot的自动配置功能,这意味着您将失去很多Spring Boot为MVC提供的默认配置。通常,如果您只是想要添加或覆盖某些配置,而不是完全自定义整个MVC配置,那么不推荐继承WebMvcConfigurationSupport

  2. WebSocket配置: 在这个配置类中,@Bean注解创建一个ServerEndpointExporter的bean,这通常用于配置JSR 356 (Java API for WebSocket) 的端点。但是,ServerEndpointExporter并不是Spring Boot的WebSocket消息代理的一部分,而是用于JSR 356 WebSocket端点的导出。如果您打算使用Spring的WebSocket消息代理(即STOMP over WebSocket),那么您不需要ServerEndpointExporter

  3. 静态资源处理: 通过覆盖addResourceHandlers方法来配置静态资源的位置。尽管这本身不是错误的,但如果您只是想要配置静态资源,那么您并不需要继承WebMvcConfigurationSupport。您可以直接在另一个配置类中通过实现WebMvcConfigurer接口来完成这个操作。

如果您打算使用Spring的WebSocket消息代理,那么您应该使用类似您之前的WebSocketConfig配置类(不继承WebMvcConfigurationSupport),并实现WebSocketMessageBrokerConfigurer接口。静态资源处理则可以通过实现WebMvcConfigurer接口来完成。

以下是一个改进后的配置示例:

WebSocket配置 (不使用WebMvcConfigurationSupport)

import org.springframework.context.annotation.Configuration;  
import org.springframework.messaging.simp.config.MessageBrokerRegistry;  
import org.springframework.web.socket.config.annotation.*;  
  
// 使用@Configuration注解来标识这个类是一个配置类  
@Configuration  
// 使用@EnableWebSocketMessageBroker注解来启用WebSocket消息代理支持  
@EnableWebSocketMessageBroker  
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {  
  
    @Override  
    public void configureMessageBroker(MessageBrokerRegistry config) {  
        // 配置消息代理的前缀,客户端订阅消息时需要使用这个前缀  
        config.enableSimpleBroker("/topic");  
        // 配置应用目标前缀,客户端发送消息到服务器时使用这个前缀  
        config.setApplicationDestinationPrefixes("/app");  
    }  
  
    @Override  
    public void registerStompEndpoints(StompEndpointRegistry registry) {  
        // 注册一个STOMP协议的WebSocket端点,客户端将连接到这个端点  
        // addEndpoint方法第一个参数是端点URL,第二个参数是使用的子协议,这里使用SockJS  
        registry.addEndpoint("/websocket").withSockJS();  
    }  
  
    // (可选)配置跨域策略  
    @Override  
    public void configureWebSocketTransport(WebSocketTransportRegistration registration) {  
        registration.setMessageSizeLimit(8192); // 设置消息大小限制  
        registration.setSendBufferSizeLimit(16384); // 设置发送缓冲区大小限制  
    }  
}

静态资源配置 (通过实现WebMvcConfigurer)

@Configuration  
public class WebMvcConfig implements WebMvcConfigurer {  
  
    @Override  
    public void addResourceHandlers(ResourceHandlerRegistry registry) {  
        registry.addResourceHandler("image/**")  
                .addResourceLocations("classpath:/static/image/");  
        // 如果需要绝对路径,可以添加另一个资源处理器  
    }  
}

WebSocketController.java

import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.messaging.handler.annotation.*;  
import org.springframework.stereotype.Controller;  
  
// 使用@Controller注解来标识这个类是一个控制器  
@Controller  
public class WebSocketController {  
  
    // 假设有一个服务来处理消息逻辑  
    @Autowired  
    private MessageService messageService;  
  
    // 使用@MessageMapping注解定义客户端发送消息到服务器的路由  
    @MessageMapping("/hello")  
    // 使用@SendTo注解定义服务器向客户端发送消息的路由  
    @SendTo("/topic/greetings")  
    public String greeting(String message) {  
        // 调用服务来处理消息  
        String processedMessage = messageService.processMessage(message);  
        // 返回处理后的消息给客户端  
        return processedMessage;  
    }  
  
    // (可选)定义一个方法处理连接事件  
    @EventHandler  
    public void handleConnect(SessionConnectedEvent event) {  
        // 处理客户端连接事件  
    }  
  
    // (可选)定义一个方法处理断开连接事件  
    @EventHandler  
    public void handleDisconnect(SessionDisconnectEvent event) {  
        // 处理客户端断开连接事件  
    }  
}

MessageService.java

import org.springframework.stereotype.Service;  
  
// 使用@Service注解来标识这个类是一个服务类  
@Service  
public class MessageService {  
  
    public String processMessage(String message) {  
        // 这里可以添加消息处理的逻辑,比如格式化、验证等  
        // 返回一个处理后的消息  
        return "Hello, " + message + "!";  
    }  
}

以上代码配置了一个简单的WebSocket服务器,包括WebSocket消息代理、端点配置以及消息处理器。

  • WebSocketConfig 类是WebSocket的配置类,通过实现 WebSocketMessageBrokerConfigurer 接口,定义了消息代理和端点的配置。
  • WebSocketController 类是WebSocket的控制器,使用 @MessageMapping 注解来映射客户端发送的消息,并使用 @SendTo 注解来指定消息发送的路由。
  • MessageService 类是一个简单的服务类,用来处理WebSocket接收到的消息。

3.基于@ServerEndpoint的注解实现websocket通信

在Spring框架中,@ServerEndpoint注解用于声明一个WebSocket端点,这个端点可以被客户端通过WebSocket协议进行连接。然而,@ServerEndpoint注解本身并不与Spring容器集成,所以直接使用@Component注解来将其声明为一个Spring管理的bean是不起作用的。

要解决这个问题,你需要使用ServerEndpointExporter来手动注册@ServerEndpoint注解的类,以便它们能够被Spring容器管理。ServerEndpointExporter是一个Spring Boot组件,它会自动注册带有@ServerEndpoint注解的类,使其可以作为WebSocket端点。

以下是如何使用@ServerEndpoint@Component注解,并通过ServerEndpointExporter来实现WebSocket长连接的步骤:

1.创建一个带有@ServerEndpoint注解的类,用于处理WebSocket连接。

import javax.websocket.OnClose;  
import javax.websocket.OnMessage;  
import javax.websocket.OnOpen;  
import javax.websocket.Session;  
import javax.websocket.server.ServerEndpoint;  
import org.springframework.stereotype.Component;  
  
@ServerEndpoint("/ws/{userId}/{device}")  
@Component  
public class MyWebSocketEndpoint {  
  
    @OnOpen  
    public void onOpen(Session session, @PathParam("userId") String userId, @PathParam("device") String device) {  
        // 连接建立时的处理逻辑  
        System.out.println("Client connected: " + session.getId() + " with userId=" + userId + " and device=" + device);  
    }  
  
    @OnMessage  
    public void onMessage(String message, Session session) {  
        // 收到消息时的处理逻辑  
        System.out.println("Message received: " + message + " from session: " + session.getId());  
    }  
  
    @OnClose  
    public void onClose(Session session) {  
        // 连接关闭时的处理逻辑  
        System.out.println("Client disconnected: " + session.getId());  
    }  
}

请注意,上面的代码中使用了@PathParam注解来提取URL模板参数userIddevice。但是,@PathParam并不是javax.websocket包中的一部分,它是JAX-RS规范的一部分。在标准的WebSocket API中,你需要在@OnOpen方法中手动解析路径参数。

2. 创建一个配置类来注册ServerEndpointExporter

import org.springframework.context.annotation.Bean;  
import org.springframework.context.annotation.Configuration;  
import org.springframework.web.socket.server.standard.ServerEndpointExporter;  
  
@Configuration  
public class WebSocketConfig {  
  
    @Bean  
    public ServerEndpointExporter serverEndpointExporter() {  
        return new ServerEndpointExporter();  
    }  
}

在这个配置类中,我们创建了一个ServerEndpointExporter的bean,Spring Boot会自动扫描并注册所有带有@ServerEndpoint注解的类。

请注意@PathParam注解在标准的WebSocket API中并不适用。如果你需要处理URL模板参数,你可能需要手动解析它们,或者使用Spring的@RequestMappingHandlerAdapter来创建一个自定义的WebSocket端点处理器。

  • 14
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot集成WebSocket可以实现后端向前端发送数据的功能。下面是实现该功能的步骤: 1. 在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> ``` 2. 创建一个WebSocket配置类,用于配置WebSocket相关的Bean。可以创建一个类,并使用`@Configuration`和`@EnableWebSocket`注解进行标记,如下所示: ```java @Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(myHandler(), "/websocket"); } @Bean public WebSocketHandler myHandler() { return new MyHandler(); } } ``` 3. 创建一个WebSocket处理器类,用于处理WebSocket连接和消息的逻辑。可以创建一个类,并实现`WebSocketHandler`接口,如下所示: ```java public class MyHandler implements WebSocketHandler { @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { // 当建立WebSocket连接时调用,可以在这里进行一些初始化操作 } @Override public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception { // 处理收到的消息 String payload = (String) message.getPayload(); // 向前端发送消息 session.sendMessage(new TextMessage("Hello, " + payload)); } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { // 当关闭WebSocket连接时调用,可以在这里进行一些清理操作 } @Override public boolean supportsPartialMessages() { return false; } } ``` 4. 在Controller中注入`SimpMessagingTemplate`类,用于发送消息给WebSocket客户端。然后,可以在需要发送消息的地方调用`simpMessagingTemplate.convertAndSend()`方法发送消息,如下所示: ```java @RestController public class MyController { private final SimpMessagingTemplate messagingTemplate; public MyController(SimpMessagingTemplate messagingTemplate) { this.messagingTemplate = messagingTemplate; } @GetMapping("/send") public String sendMessage() { messagingTemplate.convertAndSend("/websocket", "Hello from the server!"); return "Message sent"; } } ``` 5. 在前端页面中使用JavaScript代码连接WebSocket,并处理接收到的消息。可以使用`new WebSocket()`方法创建WebSocket对象,并使用`onmessage`事件监听接收到的消息,如下所示: ```javascript var websocket = new WebSocket("ws://localhost:8080/websocket"); websocket.onmessage = function(event) { var message = event.data; // 处理接收到的消息 console.log(message); }; ``` 以上就是使用Spring Boot集成WebSocket实现后端向前端发送数据的基本步骤。通过WebSocket连接,后端可以通过WebSocketSession对象向前端发送消息。前端页面可以通过WebSocket对象接收并处理后端发送的消息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值