1、什么是Websocket?
websocket采用W3C国际标准,完美支持HTML5的新协议,采用双全工通信,摆脱传统http连接轮询的窘况,它于http没有关系,
http不支持持久连接,websocket只是能够兼容现有浏览器的握手规范,是HTML5开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
在WebSocket API中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
2、websocket创建过程
客户端创建过程
1、浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求。
2、连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。
3、当获取 Web Socket 连接后,可以通过 send() 方法来向服务器发送数据
4、然后可通过 onmessage 事件来接收服务器返回的数据。
服务端同理
3、创建WebSocket聊天服务端
加入pom.xml依赖
<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-thymeleaf</artifactId>
</dependency>
application.xml
server:
port: 8083
resources:
static-locations: classpath:/templates/
thymeleaf:
suffix: .html
首先开启WebSocket服务端的自动注册
ServerEndpointExporter类是由Spring官方提供的标准实现,用于扫描ServerEndpointConfig配置类和@ServerEndpoint注解实例。
使用规则也很简单:
1.如果使用默认的嵌入式容器 比如Tomcat 则必须手工在上下文提供ServerEndpointExporter。
2.如果使用外部容器部署war包,则不要提供提供ServerEndpointExporter,因为此时SpringBoot默认将扫描服务端的行为交给外部容器处理。
我们此文是采用方式1
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
相关注解使用
通过注解@ServerEndpoint来声明实例化WebSocket服务端。
通过注解@OnOpen、@OnMessage、@OnClose、@OnError 来声明回调函数。
注解含义 注解于方法上方
//当打开连接后触发
@OnOpen
//当连接关闭时触发
@OnClose
//当通信异常时触发
@OnError
//当接收客户端信息时触发
@OnMessage
通过ConcurrentHashMap保存全部在线会话对象。
服务器具体代码
//创建连接使用的URL
@ServerEndpoint("/websocket/{name}")
@RestController
public class WebSocketServer {
// 通过ConcurrentHashMap保存全部在线会话对象。
//存储客户端的连接对象,每个客户端连接都会产生一个连接对象
private static ConcurrentHashMap<String,WebSocketServer> map=new ConcurrentHashMap();
//每个连接都会有自己的会话
private Session session;
//客户端名
private String name;
//当打开连接后触发
@OnOpen
public void open(@PathParam("name") String name, Session session){
map.put(name,this);
System.out.println(name+"连接服务器成功");
System.out.println("客户端连接个数:"+getConnetNum());
this.session=session;
this.name=name;
}
//当连接关闭时触发
@OnClose
public void close(){
map.remove(name);
System.out.println(name+"断开了服务器连接");
}
// 当通信异常时触发
@OnError
public void error(Throwable error){
error.printStackTrace();
System.out.println(name+"出现了异常");
}
//当接收客户端信息时触发 私聊
@OnMessage
public void getMessage(String message) throws IOException {
String[] str = message.split(":");
System.out.println("收到" + name + ":" + str[1]);
System.out.println("客户端连接个数:" + getConnetNum());
//判断是私聊还是群聊
if ("0".equals(str[2])) {
//群聊
Set<Map.Entry<String, WebSocketServer>> entries1 = map.entrySet();
for (Map.Entry<String, WebSocketServer> entry : entries1) {
if (!entry.getKey().equals(name)) {//将消息转发到其他非自身客户端
entry.getValue().send(message);
}
}
}else
{
//匹配消息需要发送的对象
//私聊
Set<Map.Entry<String, WebSocketServer>> entries = map.entrySet();
for (Map.Entry<String, WebSocketServer> entry : entries) {
if (entry.getKey().equals(str[2])) {//将消息转发到指定客户端
entry.getValue().send(str[1]);
}
}
}
}
//消息发送
public void send(String message) throws IOException {
if(session.isOpen()){
session.getBasicRemote().sendText(message);
}
}
//获取客户端连接数
public int getConnetNum(){
return map.size();
}
}
4、客户端创建
WebSocket客户端可直接用过js进行创建和连接
使用说明:
1、WebSocket客户端通过回调函数来接收服务端消息。例如:webSocket.onmessage();
2、WebSocket客户端通过send方法来发送消息给服务端。例如:webSocket.send();
3、WebSocket客户端通过onopen方法来监听连接状态。例如: websocket.onopen();
4、WebSocket客户端连接异常调用的还函数onerror()。例如:websocket.onerror();
5、WebSocket客户端连接断开调用的还函数onclose()。例如:websocket.onclose();
代码实现:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>当前用户client1</title>
</head>
<style>
#message{
width: 50%;
height: 500px;
border: 1px solid black;
background-color: darkgray;
}
#inputVal{
width: 50%;
}
input{
width: 92%;
}
</style>
<body>
<h1>当前用户client</h1>
<div id="message">
</div>
<div id="inputVal">
<input type="text" name="text">
<button onclick="send()">发送</button>
</div>
<select id="user">
<option value ="0">群聊</option>
<option value ="client2">client2</option>
<option value ="client3">client3</option>
</select>
<script>
/**
* WebSocket客户端
*
* 使用说明:
* 1、WebSocket客户端通过回调函数来接收服务端消息。例如:webSocket.onmessage
* 2、WebSocket客户端通过send方法来发送消息给服务端。例如:webSocket.send();
* 3、WebSocket客户端通过onopen方法来监听连接状态。例如: websocket.onopen();
* 4、WebSocket客户端连接异常调用的还函数onerror()。例如:websocket.onerror();
* 5、WebSocket客户端连接断开调用的还函数onclose()。例如:websocket.onclose();
*
*/
//获取框对象用户连小心刷新
var messageEl = document.getElementById("message");
//获取输入消息内容
var inputEl = document.getElementsByTagName("input")[0];
//创建Websocket客户端对象
var websocket = null;
//判断浏览器是否支持
if ('WebSocket' in window) {
//URL-ws开头表示WebSocket协议 中间是域名端口 结尾是服务端映射地址
websocket = new WebSocket("ws:localhost:8083/websocket/client1");
} else {
alert("浏览器不支持");
}
//当打开连接后触发 创建websocket对象即可打开
websocket.onopen = function () {
console.log("webscoket已经连接成功");
addMessage("webscoket已经连接成功");
};
//当连接关闭时触发
websocket.onclose = function () {
console.log("webscoket连接失败");
addMessage("webscoket连接失败");
};
//回调函数来接收服务端消息
websocket.onmessage = function (event) {
addMessage(event.data);
};
//当通信异常时触发
websocket.onerror = function () {
console.log("webscoket连接失败");
addMessage("webscoket连接失败");
};
//将客户端传过来的消息打印于消息框
function addMessage(message) {
messageEl.innerHTML += message + "</br>";
}
//发送消息
function send() {
var toname=$("#user").val();
websocket.send("client2:" + inputEl.value+":"+toname);
messageEl.innerHTML += "我:" + inputEl.value + "</br>";
}
</script>
<script src="/js/jquery-2.2.4.min.js"></script>
</body>
</html>
以上代码复制三份分别取名client1.html、client2.html、client3.html
启动程序访问三个页面,有其中之一通过下拉框选择群聊或者私聊对象即可进行聊天
如图之一