本章节主要是学习WebSocket, 目标快速入门, 能够回答以下问题:
- WebSocket和HTTP的区别. 
- WebSocket使用的是全双工通讯协议, 与其他类似协议有啥区别? 
- WebSocket中的常用注解有哪些? 
通过本章节的学习, 应该可以回答上来这几个问题.
8.1 WebSocket概念快速理解
WebSocket 是HTML5一种新的协议。 主要应用范围为实时通讯相关领域, 比如聊天软件, 实况更新和社交订阅等.
WebSocket 实现了浏览器与服务器全双工通信.
全双工通信就是我们现在的电话, 双方都可以讲话.
半双工通信就是指一个时间段内只有一个动作, 就是以前的对讲机, 同时只能有一个人说话, 说完需要加一个"over", 以便让别人说话.
单工通信更常见, 就是遥控 你的电视遥控只能发,不能收.
8.1.1 为什么HTML5提出WebSocket
思考这样一类问题, 现在有这样一类简单的需求需要你实现:
- 在网页不刷新的情况下, 搭建一个网页版聊天室; 
- 网页不刷新, 并刷新购物车内的商品个数 
- 网页不刷新, 实时更新朋友的位置. 
为什么一定要强调网页不刷新呢? 因为如果网页刷新,你就可以使用HTTP请求那套, 你发起一个请求, 服务器给你一个响应了.但是网页刷新在实时性要求较高的业务中根本没办法满足需求.
所以在HTML5之前. 通常的解决方案如下:
采用轮询的方式。即:通过js不断的请求服务器,查看是否有新数据,如果有,就获取到新数据
这种方案有很明显的缺点: js发出的大部分请求都没有获取到数据更新, 从而对双方机器造成了严重的资源浪费.
所以, 为了提出一个更好的方案, HTML5提出了WebSocket技术.
8.1.2 http与websocket的区别
http协议是短连接,每次请求之后,都会关闭连接,下次重新请求数据,需要再次打开链接.
WebSocket协议是一种长链接,只需要通过一次请求来初始化链接,然后所有的请求和响应都是通过这个TCP链接
进行通讯。
不理解的话,我举个例子.
HTTP就是发微信语音, 每次都需要先找到联系人, 然后按一下那个录音和发送.
WebSocket则与语音通话, 之后所有的对话都通过语音直接进行通讯. (双方只需要控制好发送的内容, 对流量也不会造成太大浪费)
8.2 WebSocket 的Java版demo快速实现
多说无益, 我们开始实战吧.
8.2.1 新建itcast-websocket工程(Maven工程)
首先先引入依赖
   
    - 
     
      
     
     
      
       <?xml version="1.0" encoding="UTF-8"?>
      
     
- 
     
      
     
     
      
       <project xmlns="http://maven.apache.org/POM/4.0.0"
      
     
- 
     
      
     
     
               
       xmlns:xsi=
       "http://www.w3.org/2001/XMLSchema-instance"
      
     
- 
     
      
     
     
               
       xsi:schemaLocation=
       "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      
     
- 
     
      
     
     
          
       <modelVersion>4.0.0
       </modelVersion>
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       <groupId>org.example
       </groupId>
      
     
- 
     
      
     
     
          
       <artifactId>itcast-websocket2
       </artifactId>
      
     
- 
     
      
     
     
          
       <version>1.0-SNAPSHOT
       </version>
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       <!-- 我们用的maven的tomcat插件运行, 所以在maven中一定要配置打包方式为为war包 -->
      
     
- 
     
      
     
     
          
       <packaging>war
       </packaging>
      
     
- 
     
      
     
     
          
       <dependencies>
      
     
- 
     
      
     
     
              
       <!-- websocket所需依赖 -->
      
     
- 
     
      
     
     
              
       <dependency>
      
     
- 
     
      
     
     
                  
       <groupId>javax
       </groupId>
      
     
- 
     
      
     
     
                  
       <artifactId>javaee-api
       </artifactId>
      
     
- 
     
      
     
     
                  
       <version>7.0
       </version>
      
     
- 
     
      
     
     
                  
       <scope>provided
       </scope>
      
     
- 
     
      
     
     
              
       </dependency>
      
     
- 
     
      
     
     
          
       </dependencies>
      
     
- 
     
      
     
     
          
       <build>
      
     
- 
     
      
     
     
              
       <plugins>
      
     
- 
     
      
     
     
                  
       <!-- java编译插件 -->
      
     
- 
     
      
     
     
                  
       <plugin>
      
     
- 
     
      
     
     
                      
       <groupId>org.apache.maven.plugins
       </groupId>
      
     
- 
     
      
     
     
                      
       <artifactId>maven-compiler-plugin
       </artifactId>
      
     
- 
     
      
     
     
                      
       <version>3.2
       </version>
      
     
- 
     
      
     
     
                      
       <configuration>
      
     
- 
     
      
     
     
                          
       <source>1.8
       </source>
      
     
- 
     
      
     
     
                          
       <target>1.8
       </target>
      
     
- 
     
      
     
     
                          
       <encoding>UTF-8
       </encoding>
      
     
- 
     
      
     
     
                      
       </configuration>
      
     
- 
     
      
     
     
                  
       </plugin>
      
     
- 
     
      
     
     
                  
       <!-- 配置Tomcat插件 -->
      
     
- 
     
      
     
     
                  
       <plugin>
      
     
- 
     
      
     
     
                      
       <groupId>org.apache.tomcat.maven
       </groupId>
      
     
- 
     
      
     
     
                      
       <artifactId>tomcat7-maven-plugin
       </artifactId>
      
     
- 
     
      
     
     
                      
       <version>2.2
       </version>
      
     
- 
     
      
     
     
                      
       <configuration>
      
     
- 
     
      
     
     
                          
       <port>8082
       </port>
      
     
- 
     
      
     
     
                          
       <path>/
       </path>
      
     
- 
     
      
     
     
                      
       </configuration>
      
     
- 
     
      
     
     
                  
       </plugin>
      
     
- 
     
      
     
     
              
       </plugins>
      
     
- 
     
      
     
     
          
       </build>
      
     
- 
     
      
     
     
      
       </project>
      
     
  然后新建一个demo类, 话都在注释里:
   
    - 
     
      
     
     
      
       package cn.itcast.websocket;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       import javax.websocket.*;
      
     
- 
     
      
     
     
      
       import javax.websocket.server.PathParam;
      
     
- 
     
      
     
     
      
       import javax.websocket.server.ServerEndpoint;
      
     
- 
     
      
     
     
      
       import java.io.IOException;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       /**
      
     
- 
     
      
     
     
      
        * Websocket快速入门demo, 阅读代码前最好理解'WebSocket生命周期概念'
      
     
- 
     
      
     
     
      
        * 连接->正常收发信息/异常消息->正常收发信息/异常消息->.....->正常收发信息/异常消息->断开连接
      
     
- 
     
      
     
     
      
        *
      
     
- 
     
      
     
     
      
        * @author 过道
      
     
- 
     
      
     
     
      
        */
      
     
- 
     
      
     
     
      
       // @ServerEndpoint 申明这是一个websocket服务, 可以简单类比为Controller注解
      
     
- 
     
      
     
     
      
       @ServerEndpoint("/websocket/{uid}")
      
     
- 
     
      
     
     
      
       public 
       class 
       MyWebsocket {
      
     
- 
     
      
     
     
          
       // @OnOpen 该注解标识的方法将在建立连接后执行
      
     
- 
     
      
     
     
          
       // @OnOpen 标识的方法可以接收到session对象,就是客户端与服务端建立的长连接通道
      
     
- 
     
      
     
     
          
       // @PathParam, 从路径中的{}中读取内容, 与SpringMVC一致.
      
     
- 
     
      
     
     
          
       @OnOpen
      
     
- 
     
      
     
     
          
       public 
       void 
       onOpen
       (Session session, @PathParam("uid") String uid) 
       throws
      
     
- 
     
      
     
     
      
                   IOException {
      
     
- 
     
      
     
     
              
       // 连接成功, 使用 session 的 api 发送文字
      
     
- 
     
      
     
     
      
               session.getBasicRemote().sendText(uid + 
       ",你好,欢迎连接WebSocket!");
      
     
- 
     
      
     
     
      
           }
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       // 关闭连接时, 会触发对这个注解@OnClose标识的方法的调用
      
     
- 
     
      
     
     
          
       @OnClose
      
     
- 
     
      
     
     
          
       public 
       void 
       onClose
       () {
      
     
- 
     
      
     
     
      
               System.out.println(
       this + 
       "关闭连接");
      
     
- 
     
      
     
     
      
           }
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       /**
      
     
- 
     
      
     
     
      
        * 该方法用于接收客户端发来的消息
      
     
- 
     
      
     
     
      
        *
      
     
- 
     
      
     
     
      
        * @param message 发来的消息数据
      
     
- 
     
      
     
     
      
        * @param session 会话对象(也是通道)
      
     
- 
     
      
     
     
      
        */
      
     
- 
     
      
     
     
          
       @OnMessage
      
     
- 
     
      
     
     
          
       public 
       void 
       onMessage
       (String message, Session session) 
       throws IOException {
      
     
- 
     
      
     
     
      
               System.out.println(
       "接收到消息:" + message);
      
     
- 
     
      
     
     
      
               session.getBasicRemote().sendText(
       "消息已收到.");
      
     
- 
     
      
     
     
      
           }
      
     
- 
     
      
     
     
      
       }
      
     
  写完之后, 我们使用maven的tomcat插件运行下项目:
 
 
   8.2.2 进行测试
打开网页: http://www.easyswoole.com/wstool.html
然后url改为
ws://localhost:8082/websocket/12
如图所示, 点击开始连接, 连接成功后发送就可以了.
 
 
   8.3 SpringBoot整合WebSocket
为了避免麻烦, 我们直接在8.2的demo项目上改进
pom.xml修改为下:
   
    - 
     
      
     
     
      
       <?xml version="1.0" encoding="UTF-8"?>
      
     
- 
     
      
     
     
      
       <project xmlns="http://maven.apache.org/POM/4.0.0"
      
     
- 
     
      
     
     
               
       xmlns:xsi=
       "http://www.w3.org/2001/XMLSchema-instance"
      
     
- 
     
      
     
     
               
       xsi:schemaLocation=
       "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      
     
- 
     
      
     
     
          
       <modelVersion>4.0.0
       </modelVersion>
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       <!--spring boot的支持-->
      
     
- 
     
      
     
     
          
       <parent>
      
     
- 
     
      
     
     
              
       <groupId>org.springframework.boot
       </groupId>
      
     
- 
     
      
     
     
              
       <artifactId>spring-boot-starter-parent
       </artifactId>
      
     
- 
     
      
     
     
              
       <version>2.1.0.RELEASE
       </version>
      
     
- 
     
      
     
     
          
       </parent>
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       <groupId>cn.itcast.websocket
       </groupId>
      
     
- 
     
      
     
     
          
       <artifactId>itcast-websocket
       </artifactId>
      
     
- 
     
      
     
     
          
       <version>1.0-SNAPSHOT
       </version>
      
     
- 
     
      
     
     
           
       <!-- 这里不用管, 我们之后会用boot的main方式启动 -->
      
     
- 
     
      
     
     
          
       <packaging>war
       </packaging>
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       <dependencies>
      
     
- 
     
      
     
     
              
       <!--<dependency>-->
      
     
- 
     
      
     
     
                  
       <!--<groupId>javax</groupId>-->
      
     
- 
     
      
     
     
                  
       <!--<artifactId>javaee-api</artifactId>-->
      
     
- 
     
      
     
     
                  
       <!--<version>7.0</version>-->
      
     
- 
     
      
     
     
                  
       <!--<scope>provided</scope>-->
      
     
- 
     
      
     
     
              
       <!--</dependency>-->
      
     
- 
     
      
     
     
               
       <!-- 修改为SpringBoot的webstocket -->
      
     
- 
     
      
     
     
              
       <dependency>
      
     
- 
     
      
     
     
                  
       <groupId>org.springframework.boot
       </groupId>
      
     
- 
     
      
     
     
                  
       <artifactId>spring-boot-starter-websocket
       </artifactId>
      
     
- 
     
      
     
     
              
       </dependency>
      
     
- 
     
      
     
     
          
       </dependencies>
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       <build>
      
     
- 
     
      
     
     
              
       <plugins>
      
     
- 
     
      
     
     
                  
       <!-- java编译插件 -->
      
     
- 
     
      
     
     
                  
       <plugin>
      
     
- 
     
      
     
     
                      
       <groupId>org.apache.maven.plugins
       </groupId>
      
     
- 
     
      
     
     
                      
       <artifactId>maven-compiler-plugin
       </artifactId>
      
     
- 
     
      
     
     
                      
       <version>3.2
       </version>
      
     
- 
     
      
     
     
                      
       <configuration>
      
     
- 
     
      
     
     
                          
       <source>1.8
       </source>
      
     
- 
     
      
     
     
                          
       <target>1.8
       </target>
      
     
- 
     
      
     
     
                          
       <encoding>UTF-8
       </encoding>
      
     
- 
     
      
     
     
                      
       </configuration>
      
     
- 
     
      
     
     
                  
       </plugin>
      
     
- 
     
      
     
     
                  
       <!-- 配置Tomcat插件 -->
      
     
- 
     
      
     
     
                  
       <plugin>
      
     
- 
     
      
     
     
                      
       <groupId>org.apache.tomcat.maven
       </groupId>
      
     
- 
     
      
     
     
                      
       <artifactId>tomcat7-maven-plugin
       </artifactId>
      
     
- 
     
      
     
     
                      
       <version>2.2
       </version>
      
     
- 
     
      
     
     
                      
       <configuration>
      
     
- 
     
      
     
     
                          
       <port>8082
       </port>
      
     
- 
     
      
     
     
                          
       <path>/
       </path>
      
     
- 
     
      
     
     
                      
       </configuration>
      
     
- 
     
      
     
     
                  
       </plugin>
      
     
- 
     
      
     
     
              
       </plugins>
      
     
- 
     
      
     
     
          
       </build>
      
     
- 
     
      
     
     
      
       </project>
      
     
  8.3.1 快速接入SpringBoot
在Spring中,处理消息的具体业务逻辑需要实现WebSocketHandler接口。
   
    - 
     
      
     
     
      
       package cn.itcast.websocket.spring;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       import org.springframework.stereotype.Component;
      
     
- 
     
      
     
     
      
       import org.springframework.web.socket.CloseStatus;
      
     
- 
     
      
     
     
      
       import org.springframework.web.socket.TextMessage;
      
     
- 
     
      
     
     
      
       import org.springframework.web.socket.WebSocketSession;
      
     
- 
     
      
     
     
      
       import org.springframework.web.socket.handler.TextWebSocketHandler;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       import java.io.IOException;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       /**
      
     
- 
     
      
     
     
      
        * 在Spring中, 我们需要实现WebSocketHandler接口, 并且需要注册为组件,交给IOC池子维护.
      
     
- 
     
      
     
     
      
        */
      
     
- 
     
      
     
     
      
       @Component
      
     
- 
     
      
     
     
      
       public 
       class 
       MyHandler 
       extends 
       TextWebSocketHandler {
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       /**
      
     
- 
     
      
     
     
      
        * 这里就是我们demo版本的 @onMessage 哦,每次收到信息都会走这个方法.
      
     
- 
     
      
     
     
      
        */
      
     
- 
     
      
     
     
          
       @Override
      
     
- 
     
      
     
     
          
       public 
       void 
       handleTextMessage
       (WebSocketSession session, TextMessage message)
      
     
- 
     
      
     
     
                  
       throws IOException {
      
     
- 
     
      
     
     
      
               System.out.println(
       "获取到消息 >> " + message.getPayload());
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
              
       // 向客户端发送消息
      
     
- 
     
      
     
     
      
               session.sendMessage(
       new 
       TextMessage(
       "消息已收到"));
      
     
- 
     
      
     
     
              
      
     
- 
     
      
     
     
      		
       // 如果收到了 '10', 那么给另一方发送0,1,2,3,... 9
      
     
- 
     
      
     
     
              
       if(message.getPayload().equals(
       "10")){
      
     
- 
     
      
     
     
                  
       for (
       int 
       i 
       = 
       0; i < 
       10; i++) {
      
     
- 
     
      
     
     
      
                       session.sendMessage(
       new 
       TextMessage(
       "消息 -> " + i));
      
     
- 
     
      
     
     
                      
       try {
      
     
- 
     
      
     
     
      
                           Thread.sleep(
       100);
      
     
- 
     
      
     
     
      
                       } 
       catch (InterruptedException e) {
      
     
- 
     
      
     
     
      
                           e.printStackTrace();
      
     
- 
     
      
     
     
      
                       }
      
     
- 
     
      
     
     
      
                   }
      
     
- 
     
      
     
     
      
               }
      
     
- 
     
      
     
     
      
           }
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       /**
      
     
- 
     
      
     
     
      
        * 这个就是我们demo版本中的 @OnOpen 了, 建立连接后会调用这个.
      
     
- 
     
      
     
     
      
        */
      
     
- 
     
      
     
     
          
       @Override
      
     
- 
     
      
     
     
          
       public 
       void 
       afterConnectionEstablished
       (WebSocketSession session) 
       throws
      
     
- 
     
      
     
     
      
                   Exception {
      
     
- 
     
      
     
     
      
               session.sendMessage(
       new 
       TextMessage(
       " 你好!欢迎连接到ws服务"));
      
     
- 
     
      
     
     
      
           }
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       /**
      
     
- 
     
      
     
     
      
        * 这就是demo版本的 @OnClose 注解, 关闭连接后会触发这个.
      
     
- 
     
      
     
     
      
        */
      
     
- 
     
      
     
     
          
       @Override
      
     
- 
     
      
     
     
          
       public 
       void 
       afterConnectionClosed
       (WebSocketSession session, CloseStatus status)
      
     
- 
     
      
     
     
                  
       throws Exception {
      
     
- 
     
      
     
     
      
               System.out.println(
       "断开连接!");
      
     
- 
     
      
     
     
      
           }
      
     
- 
     
      
     
     
      
       }
      
     
  编写配置类
   
    - 
     
      
     
     
      
       package cn.itcast.websocket.spring;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       import org.springframework.beans.factory.annotation.Autowired;
      
     
- 
     
      
     
     
      
       import org.springframework.context.annotation.Configuration;
      
     
- 
     
      
     
     
      
       import org.springframework.web.socket.config.annotation.EnableWebSocket;
      
     
- 
     
      
     
     
      
       import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
      
     
- 
     
      
     
     
      
       import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       /**
      
     
- 
     
      
     
     
      
        * WebSocket相关配置类
      
     
- 
     
      
     
     
      
        */
      
     
- 
     
      
     
     
      
       @Configuration
      
     
- 
     
      
     
     
      
       @EnableWebSocket
      
     
- 
     
      
     
     
      
       public 
       class 
       WebSocketConfig 
       implements 
       WebSocketConfigurer {
      
     
- 
     
      
     
     
          
       // 从IOC池子中取出我们自定义的socket处理器
      
     
- 
     
      
     
     
          
       @Autowired
      
     
- 
     
      
     
     
          
       private MyHandler myHandler;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       @Override
      
     
- 
     
      
     
     
          
       public 
       void 
       registerWebSocketHandlers
       (WebSocketHandlerRegistry registry) {
      
     
- 
     
      
     
     
              
       // 将webSocket收到的所有路径中带有 '/ws'的交给myHandler处理
      
     
- 
     
      
     
     
      
               registry.addHandler(myHandler, 
       "/ws").setAllowedOrigins(
       "*");
      
     
- 
     
      
     
     
      
           }
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       }
      
     
  编写启动类
   
    - 
     
      
     
     
      
       package cn.itcast.websocket;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       import org.springframework.boot.SpringApplication;
      
     
- 
     
      
     
     
      
       import org.springframework.boot.autoconfigure.SpringBootApplication;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       @SpringBootApplication
      
     
- 
     
      
     
     
      
       public 
       class 
       MyApplication {
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       public 
       static 
       void 
       main
       (String[] args) {
      
     
- 
     
      
     
     
      
               SpringApplication.run(MyApplication.class, args);
      
     
- 
     
      
     
     
      
           }
      
     
- 
     
      
     
     
      
       }
      
     
然后运行后打开测试网站http://www.easyswoole.com/wstool.html
 
 
   8.3.2 websocket拦截器
在Spring中提供了websocket拦截器,可以在建立连接之前写些业务逻辑,比如校验登录等。
新建一个 MyHandshakeInterceptor 拦截器
   
    - 
     
      
     
     
      
       package cn.itcast.websocket.spring;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       import org.springframework.http.server.ServerHttpRequest;
      
     
- 
     
      
     
     
      
       import org.springframework.http.server.ServerHttpResponse;
      
     
- 
     
      
     
     
      
       import org.springframework.stereotype.Component;
      
     
- 
     
      
     
     
      
       import org.springframework.web.socket.WebSocketHandler;
      
     
- 
     
      
     
     
      
       import org.springframework.web.socket.server.HandshakeInterceptor;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       import java.util.Map;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       @Component
      
     
- 
     
      
     
     
      
       public 
       class 
       MyHandshakeInterceptor 
       implements 
       HandshakeInterceptor {
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       /**
      
     
- 
     
      
     
     
      
        * 握手之前,若返回false,则不建立链接
      
     
- 
     
      
     
     
      
        */
      
     
- 
     
      
     
     
          
       @Override
      
     
- 
     
      
     
     
          
       public 
       boolean 
       beforeHandshake
       (ServerHttpRequest request, ServerHttpResponse
      
     
- 
     
      
     
     
      
        response, WebSocketHandler wsHandler, Map<String, Object> attributes) 
       throws
      
     
- 
     
      
     
     
      
                   Exception {
      
     
- 
     
      
     
     
              
       //将用户id放入socket处理器的会话(WebSocketSession)中
      
     
- 
     
      
     
     
      
               attributes.put(
       "uid", 
       1001);
      
     
- 
     
      
     
     
      
               System.out.println(
       "开始握手。。。。。。。");
      
     
- 
     
      
     
     
              
       return 
       true;
      
     
- 
     
      
     
     
      
           }
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       @Override
      
     
- 
     
      
     
     
          
       public 
       void 
       afterHandshake
       (ServerHttpRequest request, ServerHttpResponse
      
     
- 
     
      
     
     
      
        response, WebSocketHandler wsHandler, Exception exception) {
      
     
- 
     
      
     
     
      
               System.out.println(
       "握手成功啦。。。。。。");
      
     
- 
     
      
     
     
      
           }
      
     
- 
     
      
     
     
      
       }
      
     
  修改WebSocketConfig类注册拦截器
   
    - 
     
      
     
     
      
       package cn.itcast.websocket.spring;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       import org.springframework.beans.factory.annotation.Autowired;
      
     
- 
     
      
     
     
      
       import org.springframework.context.annotation.Configuration;
      
     
- 
     
      
     
     
      
       import org.springframework.web.socket.config.annotation.EnableWebSocket;
      
     
- 
     
      
     
     
      
       import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
      
     
- 
     
      
     
     
      
       import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       /**
      
     
- 
     
      
     
     
      
        * WebSocket相关配置类
      
     
- 
     
      
     
     
      
        */
      
     
- 
     
      
     
     
      
       @Configuration
      
     
- 
     
      
     
     
      
       @EnableWebSocket
      
     
- 
     
      
     
     
      
       public 
       class 
       WebSocketConfig 
       implements 
       WebSocketConfigurer {
      
     
- 
     
      
     
     
          
       // 从IOC池子中取出我们自定义的socket处理器
      
     
- 
     
      
     
     
          
       @Autowired
      
     
- 
     
      
     
     
          
       private MyHandler myHandler;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       @Autowired
      
     
- 
     
      
     
     
          
       private MyHandshakeInterceptor myHandshakeInterceptor;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       @Override
      
     
- 
     
      
     
     
          
       public 
       void 
       registerWebSocketHandlers
       (WebSocketHandlerRegistry registry) {
      
     
- 
     
      
     
     
      
               registry.addHandler(
       this.myHandler, 
       "/ws")
      
     
- 
     
      
     
     
      
                       .setAllowedOrigins(
       "*")
      
     
- 
     
      
     
     
                      
       // 追加注册一个拦截器的代码
      
     
- 
     
      
     
     
      
                       .addInterceptors(
       this.myHandshakeInterceptor);
      
     
- 
     
      
     
     
      
           }
      
     
- 
     
      
     
     
      
       }
      
     
  然后为了证明我们再在MyHandler的afterConnectionEstablished 修改下, 加上对方的uid
   
    - 
     
      
     
     
          
       /**
      
     
- 
     
      
     
     
      
        * 这个就是我们demo版本中的 @OnOpen 了, 建立连接后会调用这个.
      
     
- 
     
      
     
     
      
        */
      
     
- 
     
      
     
     
          
       @Override
      
     
- 
     
      
     
     
          
       public 
       void 
       afterConnectionEstablished
       (WebSocketSession session) 
       throws
      
     
- 
     
      
     
     
      
                   Exception {
      
     
- 
     
      
     
     
              
       // 获取uid
      
     
- 
     
      
     
     
              
       Integer 
       uid 
       = (Integer) session.getAttributes().get(
       "uid");
      
     
- 
     
      
     
     
      
               session.sendMessage(
       new 
       TextMessage(uid + 
       ", 你好!欢迎连接到ws服务"));
      
     
- 
     
      
     
     
      
           }
      
     
再次启动并测试, 发现ok
 
 
   8.4 使用WebSocket搭建即时通讯系统
在这里我们不连接数据库, 只做简单的缓存, 之后在其他一章节中连接数据库.
8.4.1 引入依赖
pom.xml文件如下.
   
    - 
     
      
     
     
      
       <?xml version="1.0" encoding="UTF-8"?>
      
     
- 
     
      
     
     
      
       <project xmlns="http://maven.apache.org/POM/4.0.0"
      
     
- 
     
      
     
     
               
       xmlns:xsi=
       "http://www.w3.org/2001/XMLSchema-instance"
      
     
- 
     
      
     
     
               
       xsi:schemaLocation=
       "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      
     
- 
     
      
     
     
          
       <modelVersion>4.0.0
       </modelVersion>
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       <groupId>org.example
       </groupId>
      
     
- 
     
      
     
     
          
       <artifactId>itcast-haoke-im-webstocket
       </artifactId>
      
     
- 
     
      
     
     
          
       <version>1.0-SNAPSHOT
       </version>
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       <parent>
      
     
- 
     
      
     
     
              
       <groupId>org.springframework.boot
       </groupId>
      
     
- 
     
      
     
     
              
       <artifactId>spring-boot-starter-parent
       </artifactId>
      
     
- 
     
      
     
     
              
       <version>2.1.0.RELEASE
       </version>
      
     
- 
     
      
     
     
          
       </parent>
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       <dependencies>
      
     
- 
     
      
     
     
              
       <dependency>
      
     
- 
     
      
     
     
                  
       <groupId>org.springframework.boot
       </groupId>
      
     
- 
     
      
     
     
                  
       <artifactId>spring-boot-starter-web
       </artifactId>
      
     
- 
     
      
     
     
              
       </dependency>
      
     
- 
     
      
     
     
              
       <dependency>
      
     
- 
     
      
     
     
                  
       <groupId>org.springframework.boot
       </groupId>
      
     
- 
     
      
     
     
                  
       <artifactId>spring-boot-starter-websocket
       </artifactId>
      
     
- 
     
      
     
     
              
       </dependency>
      
     
- 
     
      
     
     
              
       <dependency>
      
     
- 
     
      
     
     
                  
       <groupId>org.springframework.boot
       </groupId>
      
     
- 
     
      
     
     
                  
       <artifactId>spring-boot-starter-test
       </artifactId>
      
     
- 
     
      
     
     
                  
       <scope>test
       </scope>
      
     
- 
     
      
     
     
              
       </dependency>
      
     
- 
     
      
     
     
              
       <dependency>
      
     
- 
     
      
     
     
                  
       <groupId>junit
       </groupId>
      
     
- 
     
      
     
     
                  
       <artifactId>junit
       </artifactId>
      
     
- 
     
      
     
     
                  
       <version>4.12
       </version>
      
     
- 
     
      
     
     
                  
       <scope>test
       </scope>
      
     
- 
     
      
     
     
              
       </dependency>
      
     
- 
     
      
     
     
              
       <dependency>
      
     
- 
     
      
     
     
                  
       <groupId>org.projectlombok
       </groupId>
      
     
- 
     
      
     
     
                  
       <artifactId>lombok
       </artifactId>
      
     
- 
     
      
     
     
                  
       <version>1.18.4
       </version>
      
     
- 
     
      
     
     
              
       </dependency>
      
     
- 
     
      
     
     
              
       <dependency>
      
     
- 
     
      
     
     
                  
       <groupId>org.apache.commons
       </groupId>
      
     
- 
     
      
     
     
                  
       <artifactId>commons-lang3
       </artifactId>
      
     
- 
     
      
     
     
              
       </dependency>
      
     
- 
     
      
     
     
          
       </dependencies>
      
     
- 
     
      
     
     
          
       <build>
      
     
- 
     
      
     
     
              
       <plugins>
      
     
- 
     
      
     
     
                  
       <!-- java编译插件 -->
      
     
- 
     
      
     
     
                  
       <plugin>
      
     
- 
     
      
     
     
                      
       <groupId>org.apache.maven.plugins
       </groupId>
      
     
- 
     
      
     
     
                      
       <artifactId>maven-compiler-plugin
       </artifactId>
      
     
- 
     
      
     
     
                      
       <version>3.2
       </version>
      
     
- 
     
      
     
     
                      
       <configuration>
      
     
- 
     
      
     
     
                          
       <source>1.8
       </source>
      
     
- 
     
      
     
     
                          
       <target>1.8
       </target>
      
     
- 
     
      
     
     
                          
       <encoding>UTF-8
       </encoding>
      
     
- 
     
      
     
     
                      
       </configuration>
      
     
- 
     
      
     
     
                  
       </plugin>
      
     
- 
     
      
     
     
              
       </plugins>
      
     
- 
     
      
     
     
          
       </build>
      
     
- 
     
      
     
     
      
       </project>
      
     
  项目结构图如下所示 :
 
 
   我们先只实现WebSocket相关内容
8.4.2 搭建pojo和对应的DAO层
   
    - 
     
      
     
     
      
       package cn.itcast.haoke.im.pojo;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       import lombok.AllArgsConstructor;
      
     
- 
     
      
     
     
      
       import lombok.Builder;
      
     
- 
     
      
     
     
      
       import lombok.Data;
      
     
- 
     
      
     
     
      
       import lombok.NoArgsConstructor;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       import java.util.Date;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       @Data
      
     
- 
     
      
     
     
      
       @AllArgsConstructor
      
     
- 
     
      
     
     
      
       @NoArgsConstructor
      
     
- 
     
      
     
     
      
       @Builder
      
     
- 
     
      
     
     
      
       public 
       class 
       Message {
      
     
- 
     
      
     
     
          
      
     
- 
     
      
     
     
          
       private 
       long id;
      
     
- 
     
      
     
     
          
       // 消息体暂不支持复杂消息.
      
     
- 
     
      
     
     
          
       private String msg;
      
     
- 
     
      
     
     
          
       /**
      
     
- 
     
      
     
     
      
        * 消息状态,1-未读,2-已读
      
     
- 
     
      
     
     
      
        */
      
     
- 
     
      
     
     
          
       private Integer status;
      
     
- 
     
      
     
     
          
      
     
- 
     
      
     
     
          
       // 发送的时间和已读的时间
      
     
- 
     
      
     
     
          
       private Date sendDate;
      
     
- 
     
      
     
     
          
       private Date readDate;
      
     
- 
     
      
     
     
          
       // 发送方和接收方
      
     
- 
     
      
     
     
          
       private User from;
      
     
- 
     
      
     
     
          
       private User to;
      
     
- 
     
      
     
     
      
       }
      
     
  用到的User类代码如下:
   
    - 
     
      
     
     
      
       package cn.itcast.haoke.im.pojo;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       import lombok.AllArgsConstructor;
      
     
- 
     
      
     
     
      
       import lombok.Builder;
      
     
- 
     
      
     
     
      
       import lombok.Data;
      
     
- 
     
      
     
     
      
       import lombok.NoArgsConstructor;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       @Data
      
     
- 
     
      
     
     
      
       @AllArgsConstructor
      
     
- 
     
      
     
     
      
       @NoArgsConstructor
      
     
- 
     
      
     
     
      
       @Builder
      
     
- 
     
      
     
     
      
       public 
       class 
       User {
      
     
- 
     
      
     
     
          
       private Long id;
      
     
- 
     
      
     
     
          
       private String username;
      
     
- 
     
      
     
     
      
       }
      
     
  MessageDao如下, 我这里先用HashMap模拟数据库
   
    - 
     
      
     
     
      
       package cn.itcast.haoke.im.dao;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       import cn.itcast.haoke.im.pojo.Message;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       import java.util.List;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       public 
       interface 
       MessageDAO {
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       /**
      
     
- 
     
      
     
     
      
        * 查询点对点聊天记录
      
     
- 
     
      
     
     
      
        */
      
     
- 
     
      
     
     
      
           List<Message> 
       findListByFromAndTo
       (Long fromId, Long toId, Integer page, Integer
      
     
- 
     
      
     
     
      
        rows);
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       /**
      
     
- 
     
      
     
     
      
        * 根据id查询数据
      
     
- 
     
      
     
     
      
        */
      
     
- 
     
      
     
     
      
           Message 
       findMessageById
       (Long id);
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       /**
      
     
- 
     
      
     
     
      
        * 新增消息数据*
      
     
- 
     
      
     
     
      
        * * @param message
      
     
- 
     
      
     
     
      
        * * @return
      
     
- 
     
      
     
     
      
        */
      
     
- 
     
      
     
     
      
           Message 
       saveMessage
       (Message message);
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       void 
       updateMessageState
       (long id, int i);
      
     
- 
     
      
     
     
      
       }
      
     
  具体实现如下:
   
    - 
     
      
     
     
      
       package cn.itcast.haoke.im.dao.impl;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       import cn.itcast.haoke.im.dao.MessageDAO;
      
     
- 
     
      
     
     
      
       import cn.itcast.haoke.im.pojo.Message;
      
     
- 
     
      
     
     
      
       import org.springframework.stereotype.Component;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       import java.util.*;
      
     
- 
     
      
     
     
      
       import java.util.concurrent.atomic.AtomicLong;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       /**
      
     
- 
     
      
     
     
      
        * 我们在内存中简单实现一个查询类, 之后使用数据库替换.
      
     
- 
     
      
     
     
      
        */
      
     
- 
     
      
     
     
      
       @Component
      
     
- 
     
      
     
     
      
       public 
       class 
       MessageDAOImpl 
       implements 
       MessageDAO {
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       private 
       static 
       AtomicLong 
       ID_BUILDER 
       = 
       new 
       AtomicLong(
       1L);
      
     
- 
     
      
     
     
      
           Map<Long, Message> db = 
       new 
       HashMap<>();
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       @Override
      
     
- 
     
      
     
     
          
       public List<Message> 
       findListByFromAndTo
       (Long fromId, Long toId, Integer page, Integer rows) {
      
     
- 
     
      
     
     
              
       // 遍历所有信息, 找到满足的信息
      
     
- 
     
      
     
     
      
               Collection<Message> values = db.values();
      
     
- 
     
      
     
     
              
       // 先查出所有内容
      
     
- 
     
      
     
     
      
               List<Message> messageList = 
       new 
       ArrayList<>();
      
     
- 
     
      
     
     
              
       for (Message value : values) {
      
     
- 
     
      
     
     
                  
       if (value.getFrom() != 
       null && Objects.equals(value.getFrom().getId(), fromId)) {
      
     
- 
     
      
     
     
                      
       if (value.getTo() != 
       null && Objects.equals(value.getTo().getId(), toId)) {
      
     
- 
     
      
     
     
      
                           messageList.add(value);
      
     
- 
     
      
     
     
      
                       }
      
     
- 
     
      
     
     
      
                   }
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
               }
      
     
- 
     
      
     
     
              
       // 处理分页
      
     
- 
     
      
     
     
              
       return messageList.subList(page * rows, rows);
      
     
- 
     
      
     
     
      
           }
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       @Override
      
     
- 
     
      
     
     
          
       public Message 
       findMessageById
       (Long id) {
      
     
- 
     
      
     
     
              
       return db.get(id);
      
     
- 
     
      
     
     
      
           }
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       @Override
      
     
- 
     
      
     
     
          
       public Message 
       saveMessage
       (Message message) {
      
     
- 
     
      
     
     
              
       // 按照调用顺序生成一个id
      
     
- 
     
      
     
     
      
               message.setId(ID_BUILDER.getAndIncrement());
      
     
- 
     
      
     
     
      
               db.put(message.getId(), message);
      
     
- 
     
      
     
     
              
       return message;
      
     
- 
     
      
     
     
      
           }
      
     
- 
     
      
     
     
          
      
     
- 
     
      
     
     
          
       @Override
      
     
- 
     
      
     
     
          
       public 
       void 
       updateMessageState
       (long id, int i) {
      
     
- 
     
      
     
     
              
       Message 
       messageById 
       = findMessageById(id);
      
     
- 
     
      
     
     
              
       if (messageById != 
       null) {
      
     
- 
     
      
     
     
                  
       // 因为是在map中操作, 所以直接修改状态就可以了.
      
     
- 
     
      
     
     
      
                   messageById.setStatus(i);
      
     
- 
     
      
     
     
      
               }
      
     
- 
     
      
     
     
      
           }
      
     
- 
     
      
     
     
      
       }
      
     
  因为我们用的是假数据, 所以再写一些默认的假数据
   
    - 
     
      
     
     
      
       package cn.itcast.haoke.im.pojo;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       import java.util.HashMap;
      
     
- 
     
      
     
     
      
       import java.util.Map;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       public 
       class 
       UserData {
      
     
- 
     
      
     
     
          
       public 
       static 
       final Map<Long, User> USER_MAP = 
       new 
       HashMap<>();
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       static {
      
     
- 
     
      
     
     
      
               USER_MAP.put(
       1001L, User.builder().id(
       1001L).username(
       "zhangsan").build());
      
     
- 
     
      
     
     
      
               USER_MAP.put(
       1002L, User.builder().id(
       1002L).username(
       "lisi").build());
      
     
- 
     
      
     
     
      
               USER_MAP.put(
       1003L, User.builder().id(
       1003L).username(
       "wangwu").build());
      
     
- 
     
      
     
     
      
               USER_MAP.put(
       1004L, User.builder().id(
       1004L).username(
       "zhaoliu").build());
      
     
- 
     
      
     
     
      
               USER_MAP.put(
       1005L, User.builder().id(
       1005L).username(
       "sunqi").build());
      
     
- 
     
      
     
     
      
           }
      
     
- 
     
      
     
     
      
       }
      
     
  8.4.3 接入WebSocket
首先, 我们按照之前的demo版流程, 编写一个Handler来处理WebSocket的几个生命周期.
   
    - 
     
      
     
     
      
       package cn.itcast.haoke.im.websocket;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       import cn.itcast.haoke.im.dao.MessageDAO;
      
     
- 
     
      
     
     
      
       import cn.itcast.haoke.im.pojo.Message;
      
     
- 
     
      
     
     
      
       import cn.itcast.haoke.im.pojo.UserData;
      
     
- 
     
      
     
     
      
       import com.fasterxml.jackson.databind.JsonNode;
      
     
- 
     
      
     
     
      
       import com.fasterxml.jackson.databind.ObjectMapper;
      
     
- 
     
      
     
     
      
       import org.springframework.beans.factory.annotation.Autowired;
      
     
- 
     
      
     
     
      
       import org.springframework.stereotype.Component;
      
     
- 
     
      
     
     
      
       import org.springframework.web.socket.TextMessage;
      
     
- 
     
      
     
     
      
       import org.springframework.web.socket.WebSocketSession;
      
     
- 
     
      
     
     
      
       import org.springframework.web.socket.handler.TextWebSocketHandler;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       import java.util.HashMap;
      
     
- 
     
      
     
     
      
       import java.util.Map;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       /**
      
     
- 
     
      
     
     
      
        * webSocket 消息处理器
      
     
- 
     
      
     
     
      
        *
      
     
- 
     
      
     
     
      
        * @author 过道
      
     
- 
     
      
     
     
      
        */
      
     
- 
     
      
     
     
      
       @Component
      
     
- 
     
      
     
     
      
       public 
       class 
       MessageHandler 
       extends 
       TextWebSocketHandler {
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       @Autowired
      
     
- 
     
      
     
     
          
       private MessageDAO messageDAO;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       private 
       static 
       final 
       ObjectMapper 
       MAPPER 
       = 
       new 
       ObjectMapper();
      
     
- 
     
      
     
     
          
       // 记录所有在线的终端, 并配置唯一标识.
      
     
- 
     
      
     
     
          
       private 
       static 
       final Map<Long, WebSocketSession> SESSIONS = 
       new 
       HashMap<>();
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       @Override
      
     
- 
     
      
     
     
          
       public 
       void 
       afterConnectionEstablished
       (WebSocketSession session) {
      
     
- 
     
      
     
     
              
       // 将当前用户的session放置到map中,后面会使用相应的session通信
      
     
- 
     
      
     
     
              
       Long 
       uid 
       = (Long) session.getAttributes().get(
       "uid");
      
     
- 
     
      
     
     
      
               SESSIONS.put(uid, session);
      
     
- 
     
      
     
     
      
           }
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       @Override
      
     
- 
     
      
     
     
          
       protected 
       void 
       handleTextMessage
       (WebSocketSession session, TextMessage
      
     
- 
     
      
     
     
      
        textMessage) 
       throws Exception {
      
     
- 
     
      
     
     
              
       // 解析消息中的发送方, 接收方, 消息内容.
      
     
- 
     
      
     
     
              
       Long 
       uid 
       = (Long) session.getAttributes().get(
       "uid");
      
     
- 
     
      
     
     
              
       JsonNode 
       jsonNode 
       = MAPPER.readTree(textMessage.getPayload());
      
     
- 
     
      
     
     
              
       Long 
       toId 
       = jsonNode.get(
       "toId").asLong();
      
     
- 
     
      
     
     
              
       String 
       msg 
       = jsonNode.get(
       "msg").asText();
      
     
- 
     
      
     
     
              
       Message 
       message 
       = Message.builder()
      
     
- 
     
      
     
     
                      
       // 假装发送用户和接受用户都是从数据库中查出来的
      
     
- 
     
      
     
     
      
                       .from(UserData.USER_MAP.get(uid))
      
     
- 
     
      
     
     
      
                       .to(UserData.USER_MAP.get(toId))
      
     
- 
     
      
     
     
      
                       .msg(msg)
      
     
- 
     
      
     
     
      
                       .build();
      
     
- 
     
      
     
     
              
       // 存入数据库
      
     
- 
     
      
     
     
      
               message = 
       this.messageDAO.saveMessage(message);
      
     
- 
     
      
     
     
              
       // 判断to用户是否在线
      
     
- 
     
      
     
     
              
       WebSocketSession 
       toSession 
       = SESSIONS.get(toId);
      
     
- 
     
      
     
     
              
       if (toSession != 
       null && toSession.isOpen()) {
      
     
- 
     
      
     
     
                  
       // 在线且可收消息的话, 实时发送给接收方.
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
                  
       //TODO 具体格式需要和前端对接
      
     
- 
     
      
     
     
      
                   toSession.sendMessage(
       new 
       TextMessage(MAPPER.writeValueAsString(message)));
      
     
- 
     
      
     
     
                  
       // 更新消息状态为已读
      
     
- 
     
      
     
     
                  
       this.messageDAO.updateMessageState(message.getId(), 
       2);
      
     
- 
     
      
     
     
      
               }
      
     
- 
     
      
     
     
      
           }
      
     
- 
     
      
     
     
      
       }
      
     
  为了简单起见,我们直接使用url来传当前用户的id, 格式如下
ws://{服务器url}:{服务器端口}/ws/{当前用户id}
示例如下:
ws://localhost:8080/ws/1002
ws://localhost:8080/ws/1001
约定好id传输格式,我们需要在每个连接建立时, 将uid放入到attributes中, 所以需要用到拦截器
   
    - 
     
      
     
     
      
       package cn.itcast.haoke.im.websocket;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       import org.apache.commons.lang3.StringUtils;
      
     
- 
     
      
     
     
      
       import org.springframework.http.server.ServerHttpRequest;
      
     
- 
     
      
     
     
      
       import org.springframework.http.server.ServerHttpResponse;
      
     
- 
     
      
     
     
      
       import org.springframework.stereotype.Component;
      
     
- 
     
      
     
     
      
       import org.springframework.web.socket.WebSocketHandler;
      
     
- 
     
      
     
     
      
       import org.springframework.web.socket.server.HandshakeInterceptor;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       import java.util.Map;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       @Component
      
     
- 
     
      
     
     
      
       public 
       class 
       MessageHandshakeInterceptor 
       implements 
       HandshakeInterceptor {
      
     
- 
     
      
     
     
          
       /**
      
     
- 
     
      
     
     
      
        * 解析路径中的uid, 并放入 attributes 中, 以便之后使用
      
     
- 
     
      
     
     
      
        */
      
     
- 
     
      
     
     
          
       @Override
      
     
- 
     
      
     
     
          
       public 
       boolean 
       beforeHandshake
       (ServerHttpRequest request, ServerHttpResponse
      
     
- 
     
      
     
     
      
        response, WebSocketHandler wsHandler, Map<String, Object> attributes) 
       throws
      
     
- 
     
      
     
     
      
                   Exception {
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
              
       String 
       path 
       = request.getURI().getPath();
      
     
- 
     
      
     
     
      
               String[] ss = StringUtils.split(path, 
       '/');
      
     
- 
     
      
     
     
              
       if (ss.length != 
       2) {
      
     
- 
     
      
     
     
                  
       return 
       false;
      
     
- 
     
      
     
     
      
               }
      
     
- 
     
      
     
     
              
       if (!StringUtils.isNumeric(ss[
       1])) {
      
     
- 
     
      
     
     
                  
       return 
       false;
      
     
- 
     
      
     
     
      
               }
      
     
- 
     
      
     
     
      
               attributes.put(
       "uid", Long.valueOf(ss[
       1]));
      
     
- 
     
      
     
     
              
       return 
       true;
      
     
- 
     
      
     
     
      
           }
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
          
       @Override
      
     
- 
     
      
     
     
          
       public 
       void 
       afterHandshake
       (ServerHttpRequest request, ServerHttpResponse
      
     
- 
     
      
     
     
      
        response, WebSocketHandler wsHandler, Exception exception) {
      
     
- 
     
      
     
     
      
           }
      
     
- 
     
      
     
     
      
       }
      
     
  现在, 只需要我们将我们自定义的拦截器和Handler配置到Spring中, 让Spring将接收到的请求转发给我们就ok了
   
    - 
     
      
     
     
      
       package cn.itcast.haoke.im.websocket;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       import org.springframework.beans.factory.annotation.Autowired;
      
     
- 
     
      
     
     
      
       import org.springframework.context.annotation.Configuration;
      
     
- 
     
      
     
     
      
       import org.springframework.web.socket.config.annotation.EnableWebSocket;
      
     
- 
     
      
     
     
      
       import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
      
     
- 
     
      
     
     
      
       import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       @Configuration
      
     
- 
     
      
     
     
      
       @EnableWebSocket
      
     
- 
     
      
     
     
      
       public 
       class 
       WebSocketConfig 
       implements 
       WebSocketConfigurer {
      
     
- 
     
      
     
     
          
       @Autowired
      
     
- 
     
      
     
     
          
       private MessageHandler messageHandler;
      
     
- 
     
      
     
     
          
       @Autowired
      
     
- 
     
      
     
     
          
       private MessageHandshakeInterceptor messageHandshakeInterceptor;
      
     
- 
     
      
     
     
          
       @Override
      
     
- 
     
      
     
     
          
       public 
       void 
       registerWebSocketHandlers
       (WebSocketHandlerRegistry registry) {
      
     
- 
     
      
     
     
      
               registry.addHandler(
       this.messageHandler, 
       "/ws/{uid}")
      
     
- 
     
      
     
     
      
                       .setAllowedOrigins(
       "*")
      
     
- 
     
      
     
     
      
                       .addInterceptors(
       this.messageHandshakeInterceptor);
      
     
- 
     
      
     
     
      
           }
      
     
- 
     
      
     
     
      
       }
      
     
  8.4.4 编写启动类并测试
   
    - 
     
      
     
     
      
       package cn.itcast.haoke.im;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       import org.springframework.boot.SpringApplication;
      
     
- 
     
      
     
     
      
       import org.springframework.boot.autoconfigure.SpringBootApplication;
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       @SpringBootApplication
      
     
- 
     
      
     
     
      
       public 
       class 
       ImApplication {
      
     
- 
     
      
     
     
          
       public 
       static 
       void 
       main
       (String[] args) {
      
     
- 
     
      
     
     
      
               SpringApplication.run(ImApplication.class, args);
      
     
- 
     
      
     
     
      
           }
      
     
- 
     
      
     
     
      
       }
      
     
启动项目, 启动成功;
这次还是打开在线测试工具 http://www.easyswoole.com/wstool.html
注意要打开两份
一份的url : ws://localhost:8080/ws/1001
另一份的url: ws://localhost:8080/ws/1002
点击连接, 都连接成功.
我们打开url是 1001的页面, 发送内容
{
"toId":1002,
"msg" : "你好, 1002"
}
然后看一眼url为1002的页面, 确实收到了内容. 如此测试就可以了.
 
 
   转载:https://blog.csdn.net/m0_37961948/article/details/128761995
 
					