国庆假期,整整七天,我使用SpringBoot终于做出了即时

小知识,大挑战!本文正在参与「程序员必备小知识」创作活动

本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。

前言:(本文用于辅助Flutter WebSocket的理解) 在这个假期,我完成了一个小Demo,Flutter 与 Springboot 进行websocket的通讯,为啥想要去做这个Demo呢,主要是在各大平台以及google搜索后发现,没有一个详细的例子来教大家进行一对一、一对多的通讯,大多数都是教你怎么连接,却没有教你怎么去进行下一步的功能实现,于是我利用了五天的假期,踩了无数的坑,终于是完成了它,所以,点个赞吧,不容易啊,兄弟们😭

github仓库还没有创建(可以看一下文末通知),前端界面也写好了,如果想要移动端的效果的话需要使用Flutter😎

Flutter移动端分析:Flutter WebSocket 即时通讯

先上效果图(我自己搜索这样功能性的问题时,没有效果图基本上都是不想看的):

屏幕截图 2021-10-08 122313.jpg

这个效果图为Flutter:

tt0.top-039531.gif

即时通讯最重要的功能是完成了(发送文字信息)

阅读本文的注意点:

本文参考www.zhihu.com/column/p/32…,在其基础上进行二次开发

1.需要一点WebSocket的原理知识

2.springboot使用WebSocket的方法,本章就是最普通的原生方法

WebSocket的原理知识在Flutter WebSocket这篇文章中已经讲了,这里就不再重复了

正文:

1.Springboot使用WebSocket的方法

juejin.cn/post/684490… 掘金里已经有大神详细的讲解了

这里推荐spring封装或者STOMP两种方式

讲几个注意的点(详细的步骤掘金里的大神都已经写过啦~):

  • pom.xml 配置websocket
1
2
3
4
xml复制代码<dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

如果需要用户存储功能可以使用Spring Security,用户授权非常方便

  • STOMP这个协议是非常优秀的,是一种简单的基于文本的消息传递协议

如果想学习的,我推荐这篇大佬的文章:juejin.cn/post/684490…

2.Springboot实现点对点通信

现在步入正文

  • 配置pom.xml

在默认的环境下,加上一个websocket即可,这里使用的是JDK8

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
xml复制代码<properties>
  <java.version>1.8</java.version>
</properties>
<dependencies>
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</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>
</dependencies>
  • 封装前端传入的信息,以及return的值:

因为使用json进行消息的发送,所以需要先创建一个消息对象,包含了消息发送者,消息接受者,消息类型

1
2
3
4
5
6
7
8
9
arduino复制代码//数据类型
public class SocketMsg {
  private int type;//聊天类型0:群聊,1:单聊.
  private String fromUser;//发送者.
  private String toUser;//接受者.
  private String msg;//消息

  ...省略了get 和 set方法,不想写的话可以尝试lombook
}
  • WebSocketConfig处理

这里就简单举了个例子,文章中其实没有怎么用到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
kotlin复制代码import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean;

@Configuration
public class WebSocketConfig {
   @Bean
   public ServletServerContainerFactoryBean createWebSocketContainer() {
       ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
       // ws 传输数据的时候,数据过大有时候会接收不到,所以在此处设置bufferSize
       container.setMaxTextMessageBufferSize(512000);
       container.setMaxBinaryMessageBufferSize(512000);
       container.setMaxSessionIdleTimeout(15 * 60000L);
       return container;
  }
}
  • 最重要的内容,逻辑处理部分MyWebSocket来啦!
  • 设置websocket连接点映射:
1
ini复制代码@ServerEndpoint(value = "/websocket/{nickname}")
  • 我们需要一个变量来存储每个客户端对应的MyWebSocket对象.
1
swift复制代码private static CopyOnWriteArraySet<MyWebSocket> webSocketSet = new CopyOnWriteArraySet<MyWebSocket>();

一个变量用来记录sessionId和该session之间的绑定关系.

1
arduino复制代码private static Map<String, Session> map = new HashMap<String, Session>();
  • 成功建立连接时
1
2
3
4
5
6
7
8
less复制代码@OnOpen
public void onOpen(Session session, @PathParam("nickname") String nickname) {
   this.session = session;
   this.nickname = nickname;
   map.put(session.getId(), session);
   webSocketSet.add(this);//加入set中.
   this.session.getAsyncRemote().sendText(nickname + "上线了,(我的频道号是" + 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
scss复制代码@OnMessage
public void onMessage(String message, Session session, @PathParam("nickname") String nickname) {
//message 不是普通的string ,而是我们定义的SocketMsg json字符串.
try {
SocketMsg socketMsg = new ObjectMapper().readValue(message, SocketMsg.class);
//一对一聊天
if (socketMsg.getType() == 1) {
//只需要找到发送者和接受者即可.
socketMsg.setFromUser(session.getId());//发送者.
//socketMsg.setToUser(toUser);//这个是由客户端进行设置.
Session fromSession = map.get(socketMsg.getFromUser());
Session toSession = map.get(socketMsg.getToUser());
if (toSession != null) {
//发送消息
fromSession.getAsyncRemote().sendText(nickname + ":" + socketMsg.getMsg());
toSession.getAsyncRemote().sendText(nickname + ":" + socketMsg.getMsg());
} else {
fromSession.getAsyncRemote().sendText("系统消息:对方不在线或者您输入的频道号有误");
}
} else {
//群发给每个客户端
broadcast(socketMsg, nickname);
}

} catch (JsonParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JsonMappingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
  • 发生错误时
1
2
3
4
csharp复制代码public void onError(Session session, Throwable error) {
System.out.println("发生错误");
error.printStackTrace();
}
  • 如果选择群发时(每个在线的客户都可以收到信息)
1
2
3
4
5
6
typescript复制代码private void broadcast(SocketMsg socketMsg, String nickname) {
for (MyWebSocket item : webSocketSet) {
//发送消息.
item.session.getAsyncRemote().sendText(nickname + ":" + socketMsg.getMsg());
}
}
  • 连接关闭
1
2
3
4
5
csharp复制代码@OnClose
public void onClose(Session session) {
webSocketSet.remove(this);//从set中移除.
map.remove(session.getId());
}

使用源码时注意,本章使用JDK8,websocket的版本可能略有不同,端口为9090,具体的使用方法可以参考Flutter WebSocket的文章最后~

通知:juejin.cn/pin/7034450…

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%