zoukankan      html  css  js  c++  java
  • spring对websocket的集成和使用

    WebSocket是HTML5提出的一个用于通信的协议规范,该协议通过一个握手机制,在客户端和服务端之间建立一个类似于TCP的连接,从而方便客户端和服务端之间的通信。

    WebSocket协议本质上是一个基于TCP的协议,是先通过HTTP/HTTPS协议发起一条特殊的HTTP请求进行握手后创建一个用于交换数据的TCP连接,此后服务端与客户端通过此TCP连接进行实时通信。客户端和服务端只需要要做一个握手的动作,在建立连接之后,服务端和客户端之间就可以通过此TCP连接进行实时通信。

    websocket是建立在物理层上的连接,相比于基于网络层的长连接可以节约资源,相比于AJAX轮训可以降低服务器压力。

    spring在4.0后将websocket集成进去,要使用spring的websocket的话,spring的版本要在4.0及以上。

    spring使用websocket需要的jar(pom.xml)

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

    web.xml中对websocket的配置

      <servlet>  
          <servlet-name>springMVC</servlet-name>  
          <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
          <init-param>
              <param-name>contextConfigLocation</param-name>
              <param-value>classpath:/springMVC/spring-webSocket.xml</param-value>
          </init-param>
          <load-on-startup>1</load-on-startup>  
          <async-supported>true</async-supported>
        </servlet>      
        <servlet-mapping>  
          <servlet-name>springMVC</servlet-name>  
          <url-pattern>/</url-pattern>  
        </servlet-mapping> 

    springMVC中对websocket的xml配置

    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xmlns:websocket="http://www.springframework.org/schema/websocket"
        xsi:schemaLocation="
                http://www.springframework.org/schema/beans 
                http://www.springframework.org/schema/beans/spring-beans-4.0.xsd 
                http://www.springframework.org/schema/websocket
                http://www.springframework.org/schema/websocket/spring-websocket-4.0.xsd">
    
        <!-- websocket处理类 -->
        <bean id="msgHandler" class="com.test.websocket.MyWebSocketHandler" />
        <!-- 握手接口/拦截器 ,看项目需求是否需要-->
        <bean id="handshakeInterceptor" class="com.test.websocket.MyHandshakeInterceptor" />
        <websocket:handlers>
            <websocket:mapping path="/websocket" handler="msgHandler" />
            <websocket:handshake-interceptors>
                <ref bean="handshakeInterceptor" />
            </websocket:handshake-interceptors>
        </websocket:handlers>
        <!-- 注册 sockJS,sockJs是spring对不能使用websocket协议的客户端提供一种模拟 -->
        <websocket:handlers>
            <websocket:mapping path="/sockjs/websocket" handler="msgHandler" />
            <websocket:handshake-interceptors>
                <ref bean="handshakeInterceptor" />
            </websocket:handshake-interceptors>
            <websocket:sockjs />
        </websocket:handlers>
    </beans>

    springMVC中对websocket的注解配置

    @Configuration
    @EnableWebSocket
    public class WebSocketServerConfig implements WebSocketConfigurer {
    
        @Override
        public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
            // 添加拦截地址以及相应的websocket消息处理器
            WebSocketHandlerRegistration registration = registry.addHandler(new MyWebSocketHandler(), "/websocket","sockjs/websocket");
            SockJsServiceRegistration sockJS = registration.withSockJS();
            // 添加拦截器
            registration.addInterceptors(new MyHandshakeInterceptor());
        }
    
    }

    握手拦截器,继承HttpSessionHandshakeInterceptor类,做一些连接握手或者握手后的一些处理

    public class MyHandshakeInterceptor extends HttpSessionHandshakeInterceptor {
    
        // 握手前
        @Override
        public boolean beforeHandshake(ServerHttpRequest request,
                ServerHttpResponse response, WebSocketHandler wsHandler,
                Map<String, Object> attributes) throws Exception {
    
            System.out
                    .println("++++++++++++++++ HandshakeInterceptor: beforeHandshake  ++++++++++++++"
                            + attributes);
    
            return super.beforeHandshake(request, response, wsHandler, attributes);
        }
    
        // 握手后
        @Override
        public void afterHandshake(ServerHttpRequest request,
                ServerHttpResponse response, WebSocketHandler wsHandler,
                Exception ex) {
    
            System.out
                    .println("++++++++++++++++ HandshakeInterceptor: afterHandshake  ++++++++++++++");
    
            super.afterHandshake(request, response, wsHandler, ex);
        }
    }

    创建MyWebSocketHandler类继承WebSocketHandler类(Spring提供的有AbstractWebSocketHandler类、TextWebSocketHandler类、BinaryWebSocketHandler类,看自己需要进行继承),该类主要是用来处理消息的接收和发送

    public class MyWebSocketHandler implements WebSocketHandler {
        
        private Logger logger = LoggerFactory.getLogger(MsgWebSocketHandler.class);
        
        //保存用户链接
        private static ConcurrentHashMap<String, WebSocketSession> users = new ConcurrentHashMap<String, WebSocketSession>();
      // 连接 就绪时
        @Override
        public void afterConnectionEstablished(WebSocketSession session)
                throws Exception {
            users.put(session.getId(), session);
        }
    
        // 处理信息
        @Override
        public void handleMessage(WebSocketSession session,
                WebSocketMessage<?> message) throws Exception {
            System.err.println(session + "---->" + message + ":"+ message.getPayload().toString());
        }
    
        // 处理传输时异常
        @Override
        public void handleTransportError(WebSocketSession session,
                Throwable exception) throws Exception {
    
        }
    
        // 关闭 连接时
        @Override
        public void afterConnectionClosed(WebSocketSession session,
                CloseStatus closeStatus) {
            logger.debug("用户: " + session.getRemoteAddress() + " is leaving, because:" + closeStatus);
            
        }
    
        //是否支持分包
        @Override
        public boolean supportsPartialMessages() {
            return false;
        }
    }

    要进行发送消息的操作,自己可以写方法,利用保存的已经完成连接的WebSocketSession,通过调用sendMessage(WebScoketMessage<?> message)方法进行消息的发送,参数message是发送的消息内容,Spring提供的类型有TextMessage、BinaryMessage、PingMessage、PongMessage。

    前端客户端JS

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>websocket</title>
    </head>
    <style type="text/css">
        #div {
            color: red;
        }
    </style>
    <body>
        <h1>WEBSOCKET----TEST</h1>
        <div id="div">
    
        </div>
    </script>
    <script type="text/javascript">
    var div = document.getElementById('div');
    var socket = new WebSocket('ws://127.0.0.1:8088/websocket'); 
    
    socket.onopen = function(event){
        console.log(event);
        socket.send('websocket client connect test');
    }
    
    socket.onclose = function(event){
        console.log(event);
    }
    
    socket.onerror = function(event){
        console.log(event);
    }
    
    socket.onmessage = function(event){
        console.log(event)
        div.innerHTML += (' @_@ ' + event.data + ' ~_~ ');
    }
    </script>
    </body>
    </html>

    其实在后台也可以进行websocket客户端的创建

    @Test
        public void connectTest(){
            WsWebSocketContainer wsWebSocketContainer = new WsWebSocketContainer();
            wsWebSocketContainer.setDefaultMaxSessionIdleTimeout(300);
            StandardWebSocketClient client = new StandardWebSocketClient(wsWebSocketContainer);
            WebSocketHandler webSocketHandler = new MyWebSocketHandler();
            String uriTemplate = "ws://127.0.0.1:8088/websocket?account=11111";
            Object uriVars = null;
            ListenableFuture<WebSocketSession> future = client.doHandshake(webSocketHandler, uriTemplate, uriVars);
            try {
                WebSocketSession session = future.get();
                session.sendMessage(new TextMessage("hello world"));
            } catch (InterruptedException | ExecutionException | IOException e) {
                e.printStackTrace();
            }
            
        }
        
        @Test
        public void connectTest2(){
            StandardWebSocketClient client = new StandardWebSocketClient();
            WebSocketHandler webSocketHandler = new MyWebSocketHandler();
            String uriTemplate = "ws://127.0.0.1:8088/websocket";
            UriComponentsBuilder fromUriString = UriComponentsBuilder.fromUriString(uriTemplate);
            fromUriString.queryParam("account","111111");
            /*
             * 作用同上,都是将请求参数填入到URI中
             * MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();
             * params.add("account","111111");
             * fromUriString.queryParams(params);
             * */
            URI uri = fromUriString.buildAndExpand().encode().toUri();
            WebSocketHttpHeaders headers = null;
            ListenableFuture<WebSocketSession> doHandshake = client.doHandshake(webSocketHandler, headers  , uri);
            try {
                WebSocketSession session = doHandshake.get();
                session.sendMessage(new TextMessage("hello world"));
            } catch (InterruptedException | ExecutionException | IOException e) {
                e.printStackTrace();
            }
            
        }

    这是我利用Junit进行的测试,实验证明是可以完成websocket的连接。

    注意:websocket在进行连接的时候是可以类似get请求一样,将参数拼接到url中。还可以自己将参数封装进URI中,利用另一个方法进行连接的握手操作。

  • 相关阅读:
    【转】2008年中国.NET技术应用趋势分析
    VB计算器(给上学需要应付作业的应个急)
    创业失败的18个原因
    使用ChilkatDotNet组件构建网络爬虫程序
    使用文本编辑器开发和部署一个ASP.NET Web应用程序
    优化 SQL Server 查询性能
    【转】sql性能优化方法
    使用 SOS 对 Linux 中运行的 .NET Core 进行问题诊断
    MultiThread Of Member Functions
    汇编 中断调用表 (中断向量表)
  • 原文地址:https://www.cnblogs.com/zzw-blog/p/8530083.html
Copyright © 2011-2022 走看看