花了20分钟,给女朋友们写了一个web版群聊程序

10 阅读 作者:Java识堂 2020-03-30

WebSocket详解

在这里插入图片描述

WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。

WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。可以说WebSocket的出现,使得浏览器具备了实时双向通信的能力

在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。

原来为了实现推送,很多公司用的是Ajax 轮询,即按照特定的时间间隔,由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。而websocket就可以解决这些问题。

在Spring Boot中使用WebSocket

1.pom文件增加依赖

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

2.增加配置

@Configuration
public class WebSocketConfig {

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

}

3.Java代码

@Component
@ServerEndpoint("/websocket")
public class WebSocketServerController {

    // 收到消息调用的方法
    @OnMessage
    public void onMessage(String message) {
        System.out.println("收到的消息为 " + message);
    }

    // 建立连接调用的方法
    @OnOpen
    public void onOpen() {
        System.out.println("Client connected");
    }

    // 关闭连接调用的方法
    @OnClose
    public void onClose() {
        System.out.println("Connection closed");
    }

    // 传输消息错误调用的方法
    @OnError
    public void OnError(Throwable error) {
        System.out.println("Connection error");
    }
}

4.前端代码

<!DOCTYPE html>
<html>
<head>
<title>Testing websockets</title>
</head>
<body>
  <div>
	<textarea rows="3" cols="20" id="content"></textarea>
	<br>
    <input type="submit" value="Start" onclick="start()" />
  </div>
  <div id="messages"></div>
  <script type="text/javascript">
    var webSocket = 
      new WebSocket('ws://localhost:8080/websocket');

    webSocket.onerror = function(event) {
      onError(event)
    };

    webSocket.onopen = function(event) {
      onOpen(event)
    };

    webSocket.onmessage = function(event) {
      onMessage(event)
    };
	
	webSocket.onclose = function(event) {
      onClose(event)
    };
	

    function onMessage(event) {
      document.getElementById('messages').innerHTML 
        += '<br />' + event.data;
    }

    function onOpen(event) {
      document.getElementById('messages').innerHTML 
        = 'Connection established';
    }

    function onError(event) {
      alert(event);
    }
	
	function onClose(event) {
      alert(event);
    }

    function start() {
	  var text = document.getElementById('content').value;
      webSocket.send(text);
    }
  </script>
</body>
</html>

所以你看websocket其实很简单,前后端各写4个事件方法就行了(当然你也可以省略一些方法)

1.建立连接
2.收到消息
3.传输消息失败
4.关闭连接

事件和具体会话关联

如果事件想和具体会话关联,方法上只要加Session参数就行(4种事件类型的方法上都可加)

举个例子,直接将用户发送给服务端的话再返回给客户端

// 收到消息调用的方法
@OnMessage
public void onMessage(Session session, String message) {
	try {
		session.getBasicRemote().sendText(message);
	} catch (IOException e) {
		e.printStackTrace();
	}
}

在这里插入图片描述
传递参数

方法上加@PathParam参数即可

@Component
@ServerEndpoint("/websocket/{sid}")
public class WebSocketServerController
@OnOpen
public void onOpen(@PathParam("sid") String sid) {
	System.out.println("Client connected");
}

实现一个在线群聊

后端接口

@Slf4j
@Component
@ServerEndpoint("/groupChat/{sid}/{username}")
public class GroupChatController {

    // 保存 组id->组成员 的映射关系
    private static ConcurrentHashMap<String, List<Session>> groupMemberInfoMap = new ConcurrentHashMap<>();

    // 收到消息调用的方法,群成员发送消息
    @OnMessage
    public void onMessage(@PathParam("sid") String sid,
                          @PathParam("username") String username, String message) {
        List<Session> sessionList = groupMemberInfoMap.get(sid);
        // 先一个群组内的成员发送消息
        sessionList.forEach(item -> {
            try {
                String text = username + ": " + message;
                item.getBasicRemote().sendText(text);
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
    }

    // 建立连接调用的方法,群成员加入
    @OnOpen
    public void onOpen(Session session, @PathParam("sid") String sid) {
        List<Session> sessionList = groupMemberInfoMap.get(sid);
        if (sessionList == null) {
            sessionList = new ArrayList<>();
            groupMemberInfoMap.put(sid,sessionList);
        }
        sessionList.add(session);
        log.info("Connection connected");
        log.info("sid: {}, sessionList size: {}", sid, sessionList.size());
    }

    // 关闭连接调用的方法,群成员退出
    @OnClose
    public void onClose(Session session, @PathParam("sid") String sid) {
        List<Session> sessionList = groupMemberInfoMap.get(sid);
        sessionList.remove(session);
        log.info("Connection closed");
        log.info("sid: {}, sessionList size: {}", sid, sessionList.size());
    }

    // 传输消息错误调用的方法
    @OnError
    public void OnError(Throwable error) {
        log.info("Connection error");
    }
}

前端代码很简单,放github了
地址为:https://github.com/erlieStar/spring-boot-websocket

下面来看效果
在这里插入图片描述
注意先连接,后发送
在这里插入图片描述
在线开房地址:
http://www.javashitang.com:8090/

欢迎关注

在这里插入图片描述

参考博客

好文
[1]https://blog.csdn.net/moshowgame/article/details/80275084
[2]https://www.jianshu.com/p/d79bf8174196
[3]https://www.byteslounge.com/tutorials/java-ee-html5-websocket-example
一个群聊程序
[4]https://blog.csdn.net/moshowgame/article/details/80275084

原文地址:https://blog.csdn.net/zzti_erlie/article/details/101060892
广告一下
热门教程
PHP7报A non well formed numeric value encountered 0
Linux系统下关闭mongodb的几种命令分享 0
mongodb删除数据、删除集合、删除数据库的命令 0
Git&Github极速入门与攻坚实战课程 0
python爬虫教程使用Django和scrapy实现 0
libnetsnmpmibs.so.31: cannot open shared object file 0
数据结构和算法视频教程 0
redis的hash结构怎么删除数据呢? 0
C++和LUA解析器的数据交互实战视频 0
mongodb errmsg" : "too many users are authenticated 0
C++基础入门视频教程 0
用30个小时精通C++视频教程可能吗? 0
C++分布式多线程游戏服务器开发视频教程socket tcp boost库 0
C++培训教程就业班教程 0
layui的util工具格式时间戳为字符串 0
C++实战教程之远程桌面远程控制实战 1
网络安全培训视频教程 0
LINUX_C++软件工程师视频教程高级项目实战 0
C++高级数据结构与算法视频教程 0
跨域问题很头疼?通过配置nginx轻松解决ajax跨域问题 0
相关文章
【译】JavaScript数据结构(3):单向链表与双向链表 16
10个JavaScript难点 16
【译】苹果拒绝支持PWA,有损Web的未来 16
iView 一周年了,同时发布了 2.0 正式版,但这只是开始... 16
nodejs+mongodb构建一个简单登录注册功能 16
【译】JavaScript数据结构(4):树 16
组件化开发与黑箱 16
TypeScript - 不止稳,而且快 16
webpack3+anujs+ReactCSSTransitionGroup 16
原生js实现图片放大镜效果 16
WEB缓存探究第二弹——实战 16
纯笔记:vfork 的一些使用场景(顺便讲一下 fork 的原理) 16
Android APP 内部捐赠实现(支付宝&amp;微信) 16
WKWebView 的一些小总结 16
模型评价(一) AUC大法 16
开始使用GraphQL 16
Webpack模块化原理简析 16
gulp使用问题记录 16
使用Angular4动画为页面添彩 16
Python27 Matplotlib (win64 python2.7) 安装及简单使用 16