spring对websocket的集成和使用

Posted 快乐的小乐

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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的配置

<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.MsgWebSocketHandler" />
    <!-- 握手接口/拦截器 ,看项目需求是否需要-->
    <bean id="handshakeInterceptor" class="com.test.websocket.HandshakeInterceptor" />
    <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>

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

public class HandshakeInterceptor 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);
    }
}

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

public class MsgWebSocketHandler 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 += ( @[email protected]  + 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中,利用另一个方法进行连接的握手操作。

以上是关于spring对websocket的集成和使用的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot 集成 WebSocket,轻松实现信息推送!

spring-mvc,websockets 推送集成

Spring Boot 集成 websocket(广播式)

springboot-集成WebSockets广播消息

Spring Boot 入门:集成 WebSocket, 实时显示系统日志

Spring boot集成Websocket,前端监听心跳实现