websocket系列基于spring-boot-starter-websocket实现

况明贤
2023-12-01

websocket系列基于spring-boot-starter-websocket实现
前言
本篇主要是介绍怎么基于spring-boot-starter-websocket来实现websocket。

一、项目结构

二、具体说明
1.引入maven依赖


org.springframework.boot
spring-boot-starter-websocket

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2.实现WebSocketConfigurer配置类
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

@Autowired
private MyWsHandler myWsHandler;

@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
    registry
            .addHandler(myWsHandler, "myWs")
            //允许跨域
            .setAllowedOrigins("*");
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
说明:
通过实现WebSocketConfigurer配置类,重写registerWebSocketHandlers方法,注册自定义的WebSocketHandler的实现类MyWsHandler,并指定类对应的websocket访问的ServerEndpoint为/myWs。
通过@EnableWebSocket注解,启动spring-boot-starter-websocket的自动化配置。

3.自定义WebSocketHandler
/**

  • ws消息处理类
    */
    @Component
    @Slf4j
    public class MyWsHandler extends AbstractWebSocketHandler {

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
    log.info(“建立ws连接”);
    WsSessionManager.add(session.getId(),session);
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
    log.info(“发送文本消息”);
    // 获得客户端传来的消息
    String payload = message.getPayload();
    log.info("server 接收到消息 " + payload);
    session.sendMessage(new TextMessage("server 发送给的消息 " + payload + “,发送时间:” + LocalDateTime.now().toString()));
    }

    @Override
    protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception {
    log.info(“发送二进制消息”);
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
    log.error(“异常处理”);
    WsSessionManager.removeAndClose(session.getId());
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
    log.info(“关闭ws连接”);
    WsSessionManager.removeAndClose(session.getId());
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    说明:
    通过继承 AbstractWebSocketHandler 类并覆盖相应方法,可以对 websocket 的事件进行处理,这里可以同原生注解的那几个注解连起来看
    afterConnectionEstablished 方法是在 socket 连接成功后被触发,同原生注解里的 @OnOpen 功能。
    afterConnectionClosed方法是在 socket 连接关闭后被触发,同原生注解里的 @OnClose 功能。
    handleTextMessage方法是在客户端发送普通文件信息时触发,同原生注解里的 @OnMessage 功能。
    handleBinaryMessage 方法是在客户端发送二进制信息时触发,同原生注解里的 @OnMessage 功能。
    handleTransportError方法同原生注解里的@OnError。

除了继承AbstractWebSocketHandler类外,还有以下WebSocketHandler可供选择。
AbstractWebSocketHandler可以同时支持普通文本和二进制的消息处理。
BinaryWebSocketHandler只支持二进制消息。
TextWebSocketHandler只支持普通文本消息。

4.定时消息推送MessageJob
/**

  • 消息生成job
    */
    @Slf4j
    @Component
    public class MessageJob {
    @Autowired
    WsService wsService;

    /**

    • 每5s发送
      /
      @Scheduled(cron = "0/5 * * * * ")
      public void run(){
      try {
      wsService.broadcastMsg("自动生成消息 " + LocalDateTime.now().toString());
      } catch (IOException e) {
      e.printStackTrace();
      }
      }
      }
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      5.消息推送服务类WsService
      /
  • ws操作相关服务
    */
    @Service
    @Slf4j
    public class WsService {

    /**

    • 发送消息
    • @param session
    • @param text
    • @return
    • @throws IOException
      */
      public void sendMsg(WebSocketSession session, String text) throws IOException {
      session.sendMessage(new TextMessage(text));
      }

    /**

    • 广播消息
    • @param text
    • @return
    • @throws IOException
      */
      public void broadcastMsg(String text) throws IOException {
      for (WebSocketSession session: WsSessionManager.SESSION_POOL.values()) {
      session.sendMessage(new TextMessage(text));
      }
      }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
6.Session管理类WsSessionManager
@Slf4j
public class WsSessionManager {
/**
* 保存连接 session 的地方
*/
public static ConcurrentHashMap<String, WebSocketSession> SESSION_POOL = new ConcurrentHashMap<>();

/**
 * 添加 session
 *
 * @param key
 */
public static void add(String key, WebSocketSession session) {
    // 添加 session
    SESSION_POOL.put(key, session);
}

/**
 * 删除 session,会返回删除的 session
 *
 * @param key
 * @return
 */
public static WebSocketSession remove(String key) {
    // 删除 session
    return SESSION_POOL.remove(key);
}

/**
 * 删除并同步关闭连接
 *
 * @param key
 */
public static void removeAndClose(String key) {
    WebSocketSession session = remove(key);
    if (session != null) {
        try {
            // 关闭连接
            session.close();
        } catch (IOException e) {
            // todo: 关闭出现异常处理
            e.printStackTrace();
        }
    }
}

/**
 * 获得 session
 *
 * @param key
 * @return
 */
public static WebSocketSession get(String key) {
    // 获得 session
    return SESSION_POOL.get(key);
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
7.启动类SpringWsApplication
@SpringBootApplication
@EnableScheduling
public class SpringWsApplication {

public static void main(String[] args) {
    SpringApplication.run(SpringWsApplication.class, args);
}

}
1
2
3
4
5
6
7
8
9
8.首页index.html
发现很多小伙伴不知道调用WebSocket的前端页面怎么写,这里重新补充一下。

My WebSocket Send Close
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 9.测试

总结
基于spring-boot-starter-websocket实现也非常简单,主要是3个实现步骤:
1.通过继承AbstractWebSocketHandler自定义WebSocketHandler,重写afterConnectionEstablished、handleTextMessage、handleBinaryMessage、handleTransportError、afterConnectionClosed等方法,都能和jdk的原生websocket注解对应上。
2.通过实现WebSocketConfigurer进行WebSocket的相关配置,利用WebSocketHandlerRegistry注册自定义的WebSocketHandler。
3.消息的发送主要是通过WebSocketSession来实现。

 类似资料: