spring websocket

本文介绍如何使用Spring框架的WebSocket API进行消息处理,包括低层级API的实现方式及配置,同时探讨了STOMP协议在WebSocket上的应用,展示了客户端与服务器端交互的完整示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、使用Spring的低层级WebSocket API

  1. 为了在Spring使用较低层级的API来处理消息,我们必须编写一个实现WebSocketHandler的类,或继承AbstractWebSocketHandler类。
public class MyWebSocket extends AbstractWebSocketHandler{
    @Override//当新连接建立的时候,会调用
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        LOG.debug("打开链接");
    }
    @Override//接受文本消息
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        LOG.info("收到消息:{}",message.getPayload());
        Thread.sleep(2000);
        session.sendMessage(new TextMessage("响应"));
    }
    @Override
    protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception {
        super.handleBinaryMessage(session, message);
    }
    @Override
    protected void handlePongMessage(WebSocketSession session, PongMessage message) throws Exception {
        super.handlePongMessage(session, message);
    }
    @Override//当连接关闭时,会调用
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        LOG.debug("关闭链接");
        super.afterConnectionClosed(session, status);
    }
    private Logger LOG=LoggerFactory.getLogger(getClass());
}

2.配置启用WebSocket映射处理器

@Configuration
@EnableWebSocket//启用webSocket的功能
public class RootConfig implements WebSocketConfigurer{

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        //registry.addHandler(myWebSocket(), "/mySocket")
        //将myWebSocket映射到/mySocket路径,withSockJS()表示当有的浏览器或服务端不支持websocket时,SockJS在底层会提供备用方案,客户端要使用要使用sockjs创建sock
        registry.addHandler(myWebSocket(), "/mySocket").withSockJS();
    }
    @Bean //生命MyWebSocket的bean
    public MyWebSocket myWebSocket(){
        return new MyWebSocket(); 
    }
}

xml配置
这里写图片描述
3.jsp页面客户端编写


<script type="text/javascript" src="//cdn.jsdelivr.net/sockjs/1/sockjs.min.js"></script>
    <script type="text/javascript">
        //当客户段和服务段都支持websock时
        //var url="ws://"+window.location.host+"/SpringMVC/mySocket";
        //var sock=new WebSocket(url);
        //当客户点不支持websocket时
        var url="<c:url value="/mySocket" />";
        var sock= new SockJS(url);
        var i=0;
        sock.onopen=function(){
            console.log("打开链接");
            sayMarco();
        }
        sock.onmessage=function(e){
            console.log("处理信息"+e.data)
            if(i==5){
                console.log("关闭链接");
                sock.close();
            }else{
                setTimeout(function(){
                    sayMarco("请求"+i);
                },2000);
                i++;
            }

        }

        sock.onclose=function(e){
            console.log("wasClean:"+e.wasClean+"code:"+e.code+"reason:"+e.reason);
            console.log("关闭连接");
        }

        function sayMarco(a){
            console.log("发送消息");
            sock.send(a);
        } 


    </script>

二、使用STOMP消息

1.配置@EnableWebSocketMessageBroker注解能够在WebSocket之上启用STOMP

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketMessageBrokerConfig extends AbstractWebSocketMessageBrokerConfigurer{
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        //将“/sockt”注册为STOMP端点,客户端在订阅或发布消息到目的地路径前,要连接该端点
        //在客户端链接时使用
        registry.addEndpoint("/sockt").withSockJS();        
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        //代理将会处理前缀为“/topic”和“/queue”的消息
        //(以“/topic”和“/queue”作为前缀)发送到代理上的消息,其中也包括@MessageMapping注解方法的返回值所形成的消息,将会路由到代理上,并最终发送到订阅这些目的地的客户端。
        registry.enableSimpleBroker("/queue","/topic");
        //发往应用程序的消息将会带有“/app”前缀。
        //(/app前缀)以应用程序为目的地的消息将会直接路由到带有@MessageMapping注解的控制器方法中
        registry.setApplicationDestinationPrefixes("/app");
        //处理指定用户发送消息
        registry.setUserDestinationPrefix("/user");
    }

registry.enableSimpleBroker(“/queue”,”/topic”);
启用简单代理,
registry.enableStompBrokerRelay(“/queue”,”/topic”);启用真正支持STOMP的代理来支撑WebSocket消息,如RabbitMQ或ActiveMQ
这里写图片描述

2.处理来自客户端的STOMP消息
@MessageMapping(“/marco”) 接受/app/marco的socket请求
@SubscribeMapping(“/subscribe”) 接受订阅请求/topic/subscribe
@SendTo(“/topic/geting”) 发送到订阅该路径的客户端
@SendToUser(“/topic/nitoifcation”) 发送到单个用户

    @MessageMapping("/geting")
    public Shout geting(Shout message){
        System.out.println("123"+message.getMessage());
        Shout s=new Shout();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        s.setMessage(message.getMessage());
        return s;
    }
    <script type="text/javascript" src="//cdn.jsdelivr.net/sockjs/1/sockjs.min.js"></script>
    <script type="text/javascript" src="//cdn.bootcss.com/stomp.js/2.3.3/stomp.js"></script>
    <script type="text/javascript">
    var url="<c:url value="/sockt" />";
    var sock= new SockJS(url);
    var stomp=Stomp.over(sock);
    var abc=JSON.stringify({'message':'你好','user':"123"});
    stomp.connect({},function(frame){
        stomp.send('/app/geting',{},abc);
        stomp.subscribe("/topic/geting",function(resp){
            var a=JSON.parse(resp.body);
            console.log(a);
        }); 
    }); 
    @SubscribeMapping("/subscribe")
    public Shout subscribe(){
        System.out.println(123);
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        Shout s=new Shout();
        s.setMessage("响应");
        return s;
    }
    stomp.connect({},function(frame){
    //订阅
        stomp.subscribe("/app/subscribe",function(resp){
            var a=JSON.parse(resp.body);
            console.log(a);
        }); 
    });
    @MessageMapping("/login")
    @SendToUser("/topic/nitoifcation")
    public Notification login(){

        return new Notification("登陆成功");
    }
     stomp.connect({},function(frame){
        stomp.send('/app/login',{},abc);
        stomp.subscribe("/user/topic/nitoifcation",function(resp){
            var a=JSON.parse(resp.body);
            console.log(a);
        }); 
    }); 
@Service("homeService")
public class HomeService{


    @Autowired //注入SimpMessageSendingOperations可以在任何时间发送消息
    private SimpMessageSendingOperations message;


    public void send(Shout str){
        message.convertAndSend("/topic/nitoifcation", str);
        message.convertAndSendToUser("123","/topic/nitoifcation", str);
    }

}
### Spring WebSocket 使用指南 #### 1. Spring WebSocket 简介 Spring 提供了 `spring-websocket` 和 `spring-messaging` 模块来支持 WebSocket 协议,允许开发人员轻松构建实时通信的应用程序。WebSocket 是一种全双工通信协议,在单个 TCP 连接上提供了持久化的双向数据传输通道[^5]。 --- #### 2. 配置环境与依赖项 为了使用 Spring WebSocket 功能,需要引入必要的 Maven 或 Gradle 依赖项。以下是基于 Spring Boot 的典型依赖配置: ```xml <!-- Maven --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-core</artifactId> </dependency> ``` 对于非 Spring Boot 应用,则需手动管理相关模块的版本兼容性[^4]。 --- #### 3. WebSocket 配置详解 ##### 3.1 启用消息代理模式 Spring 支持通过 STOMP (Simple Text Oriented Messaging Protocol) 来封装 WebSocket 数据流。以下是一个典型的 XML 配置示例: ```xml <websocket:message-broker application-destination-prefix="/app"> <websocket:stomp-endpoint path="/portfolio"> <websocket:sockjs/> </websocket:stomp-endpoint> <websocket:simple-broker prefix="/topic, /queue"/> </websocket:message-broker> ``` 此配置启用了 SockJS 回退机制,并设置了 `/app` 路径作为客户端发送消息的目标前缀,同时定义了简单的消息代理路径 `/topic` 和 `/queue`[^3]。 ##### 3.2 Java 注解方式配置 如果更倾向于编程式的配置方法,可以创建一个继承自 `AbstractWebSocketMessageBrokerConfigurer` 的类并覆盖相应的方法: ```java @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker("/topic", "/queue"); config.setApplicationDestinationPrefixes("/app"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/ws").withSockJS(); } } ``` 这段代码实现了相同的逻辑,但更加灵活且易于维护[^4]。 --- #### 4. 处理器定制化 可以通过扩展 `TextWebSocketHandler` 或 `BinaryWebSocketHandler` 类来自定义处理逻辑。例如: ```java @Component public class MyWebSocketHandler extends TextWebSocketHandler { @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { String payload = message.getPayload(); System.out.println("Received Message: " + payload); // 发送响应给客户端 session.sendMessage(new TextMessage("Echo: " + payload)); } } ``` 当需要增强会话性能时,还可以利用 `ConcurrentWebSocketSessionDecorator` 对原始会话对象进行装饰[^1]。 --- #### 5. 前端实现 前端通常采用 JavaScript 结合 STOMP 客户端库完成连接建立和消息收发操作。下面展示了一个基本的例子: ```javascript var socket = new SockJS('/ws'); var stompClient = Stomp.over(socket); stompClient.connect({}, function(frame) { console.log('Connected: ' + frame); stompClient.subscribe('/topic/greetings', function(greeting){ alert(JSON.parse(greeting.body).content); }); }); function sendMessage() { var name = document.getElementById('name').value; stompClient.send("/app/hello", {}, JSON.stringify({'name': name})); } ``` 该脚本展示了如何订阅主题以及向服务器推送请求。 --- #### 6. 测试与调试技巧 测试 WebSocket 功能建议借助浏览器开发者工具查看网络活动详情;或者运行专门的压力测试工具如 Apache JMeter 检验系统的稳定性表现[^4]。 --- #### 7. 生产环境中常见问题及其解决方案 | **问题描述** | **可能原因分析** | **解决办法** | |--------------|------------------|-------------| | 断线频繁 | 网络波动 | 实现心跳包保持活跃状态 | | 消息丢失 | 缓冲区溢出 | 开启自动重传策略 | 更多高级特性比如集群部署下的共享存储方案可通过集成 Redis 或其他分布式缓存服务达成目标[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值