spring使用websocket(转)

转载:https://blog.csdn.net/fffvdgjvbsfkb123456/article/details/116465394

WebSocket介绍
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。

WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。

 

 

 

协议有两部分,握手和数据传输。
握手是基于http协议的
来自客户端的握手形式如下:

 

 

来自服务器的握手形式如下:

 

 

websocket方法


引入POM依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-websocket</artifactId>
    <version>4.2.4.RELEASE</version>
</dependency>

WebSocket入口配置

复制代码
@Configuration  
@EnableWebSocket  
public class WebSocketConfig implements WebSocketConfigurer {  
    /** 
     * 注册handle 
     * @see org.springframework.web.socket.config.annotation.WebSocketConfigurer#registerWebSocketHandlers(org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry) 
     */  
    @Override  
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {  
          registry.addHandler(myHandler(), "/testHandler.do").addInterceptors(new WebSocketInterceptor());  
          registry.addHandler(myHandler(), "/socketJs/testHandler.do").addInterceptors(new WebSocketInterceptor()).withSockJS();  
  
    }  
      
    @Bean  
    public WebSocketHandler myHandler(){  
        return new MyMessageHandler();  
    }  
}
复制代码

实现WebSocketConfigurer接口,重写registerWebSocketHandlers方法,这是一个核心实现方法,配置websocket入口,允许访问的域、注册Handler、SockJs支持和拦截器。
registry.addHandler注册和路由的功能,当客户端发起websocket连接,把/path交给对应的handler处理,而不实现具体的业务逻辑,可以理解为收集和任务分发中心。
addInterceptors,是为handler添加拦截器,可以在调用handler前后加入我们自己的逻辑代码。
创建拦截器

复制代码
public class WebSocketInterceptor extends HttpSessionHandshakeInterceptor {
    @Override
    public boolean beforeHandshake(ServerHttpRequest request,
            ServerHttpResponse response, WebSocketHandler wsHandler,
            Map<String, Object> attributes) throws Exception {
        if (request instanceof ServletServerHttpRequest) {
            ServletServerHttpRequest serverHttpRequest = (ServletServerHttpRequest) request;
            // 获取参数
            String userId = serverHttpRequest.getServletRequest().getParameter(
                    "userId");
            attributes.put("currentUser", userId);
        }

        return true;
    }

    // 初次握手访问后
    @Override
    public void afterHandshake(ServerHttpRequest serverHttpRequest,
            ServerHttpResponse serverHttpResponse,
            WebSocketHandler webSocketHandler, Exception e) {

    }
}
复制代码

beforeHandshake,在调用handler前处理方法。常用在登录用户信息,绑定WebSocketSession,在handler里根据用户信息获取WebSocketSession发送消息。

Handler处理类

复制代码
public class MyMessageHandler implements WebSocketHandler {

    /**
     * userMap:使用线程安全map存储用户连接webscoket信息
     * 
     * @since JDK 1.7
     */
    private final static Map<String, WebSocketSession> userMap = new new ConcurrentHashMap<String, WebSocketSession>();

    /**
     * 关闭websocket时调用该方法
     * 
     * @see org.springframework.web.socket.WebSocketHandler#afterConnectionClosed(org.springframework.web.socket.WebSocketSession,
     *      org.springframework.web.socket.CloseStatus)
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session,
            CloseStatus status) throws Exception {
        String userId = this.getUserId(session);
        if (StringUtils.isNoneBlank(userId)) {
            userMap.remove(userId);
            System.err.println("该" + userId + "用户已成功关闭");
        } else {
            System.err.println("关闭时,获取用户id为空");
        }

    }

    /**
     * 建立websocket连接时调用该方法
     * 
     *  org.springframework.web.socket.WebSocketHandler#afterConnectionEstablished(org.springframework.web.socket.WebSocketSession)
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session)
            throws Exception {
        String userId = this.getUserId(session);
        if (StringUtils.isNoneBlank(userId)) {
            userMap.put(userId, session);
            session.sendMessage(new TextMessage("建立服务端连接成功!"));
        }

    }

    /**
     * 客户端调用websocket.send时候,会调用该方法,进行数据通信
     * 
     * org.springframework.web.socket.WebSocketHandler#handleMessage(org.springframework.web.socket.WebSocketSession,
     *      org.springframework.web.socket.WebSocketMessage)
     */
    @Override
    public void handleMessage(WebSocketSession session,
            WebSocketMessage<?> message) throws Exception {
            String msg = message.toString();
            String userId = this.getUserId(session);
            System.err.println("该" + userId + "用户发送的消息是:" + msg);
            message = new TextMessage("服务端已经接收到消息,msg=" + msg);
            session.sendMessage(message);
    }

    /**
     * 传输过程出现异常时,调用该方法
     * 
     * org.springframework.web.socket.WebSocketHandler#handleTransportError(org.springframework.web.socket.WebSocketSession,
     *      java.lang.Throwable)
     */
    @Override
    public void handleTransportError(WebSocketSession session, Throwable e)
            throws Exception {
        WebSocketMessage<String> message = new TextMessage("异常信息:"
                + e.getMessage());
        session.sendMessage(message);
    }

    /**
     * 
     *   org.springframework.web.socket.WebSocketHandler#supportsPartialMessages()
     */
    @Override
    public boolean supportsPartialMessages() {

        return false;
    }

    /**
     * sendMessageToUser:发给指定用户
     * 
     */
    public void sendMessageToUser(String userId, String contents) {
        WebSocketSession session = userMap.get(userId);
        if (session != null && session.isOpen()) {
            try {
                TextMessage message = new TextMessage(contents);
                session.sendMessage(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * sendMessageToAllUsers:发给所有的用户
     * 
     */
    public void sendMessageToAllUsers(String contents) {
        Set<String> userIds = userMap.keySet();
        for (String userId : userIds) {
            this.sendMessageToUser(userId, contents);
        }
    }

    /**
     * getUserId:获取用户id
     * 
     * @author liuchao
     * @param session
     * @return
     * @since JDK 1.7
     */
    private String getUserId(WebSocketSession session) {
        try {
            String userId = (String) session.getAttributes().get("currentUser");
            return userId;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
复制代码

客户端连接

复制代码
<script type="text/javascript">
    $(function(){
            var host= window.location.host;
            var websocket;
            if ('WebSocket' in window) {
                websocket = new WebSocket("ws://"+host+"/testHandler.do?userId=9528");
            } else if ('MozWebSocket' in window) {
                websocket = new MozWebSocket("ws://"+host+"/testHandler.do?userId=9528");
            } else {
                websocket = new SockJS("http://"+host+"/socketJs/testHandler.do?userId=9528");
            }
            websocket.onopen = function (evnt) {
                console.log("链接服务器成功!")
            };
            websocket.onmessage = function (evnt) {
                console.log(evnt.data);
                $("#message").html(evnt.data);
            };
            websocket.onerror = function (evnt) {
                console.log("websocket错误");
            };
            websocket.onclose = function (evnt) {
                console.log("与服务器断开了链接!")
            }
            $('#send').bind('click', function() {
                send();
            });
            function send(){
                if (websocket != null) {
                    var message = document.getElementById('message').value;
                    websocket.send(message);
                } else {
                    alert('未与服务器链接.');
                }
            }
    });
</script>
复制代码

 

posted @   Mars.wang  阅读(368)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
点击右上角即可分享
微信分享提示