1、WebSocket是HTML5开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。在WebSocket API中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
2、浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。
3、当你获取 Web Socket 连接后,你可以通过 send() 方法来向服务器发送数据,并通过 onmessage 事件来接收服务器返回的数据。
使用说明:
使用步骤:1、获取WebSocket客户端对象。
例如: var webSocket = new WebSocket(url);
使用步骤:2、获取WebSocket回调函数。
例如:webSocket.onmessage = function (event) {console.log('WebSocket收到消息:' + event.data);
事件类型 | WebSocket回调函数 | 事件描述 |
---|---|---|
open | webSocket.onopen | 当打开连接后触发 |
message | webSocket.onmessage | 当客户端接收服务端数据时触发 |
error | webSocket.onerror | 当通信异常时触发 |
close | webSocket.onclose | 当连接关闭时触发 |
使用步骤:3、发送消息给服务端
例如:webSokcet.send(jsonStr)
结合实际场景 本案例采用JSON字符串进行消息通信。
先引入websocket依赖
|-----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 | <!-- websocket消息推送 -->
<``dependency``>
``<``groupId``>org.springframework.boot</``groupId``>
``<``artifactId``>spring-boot-starter-websocket</``artifactId``>
</``dependency``>
|
添加 WebSocketConfig 配置
|----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 | import
org.springframework.context.annotation.Bean;
import
org.springframework.context.annotation.Configuration;
import
org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public
class
WebSocketConfig {
``@Bean
``public
ServerEndpointExporter serverEndpointExporter() {
``return
new
ServerEndpointExporter();
``}
|
实体bean接收客户端发过来的信息
|----------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | @Data
public
class
SocketMsg {
``/**
``* 聊天类型 0 群聊 1 单聊
``**/
``private
int
type;
``/**
``* 发送者
``**/
``private
String sendOutUser;
``/**
``* 接受者
``**/
``private
String receiveUser;
``/**
``* 消息
``**/
``private
String msg;
}
|
WebSocketUtil
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 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 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | import
cn.hutool.json.JSONUtil;
import
org.springframework.stereotype.Component;
import
javax.websocket.*;
import
javax.websocket.server.PathParam;
import
javax.websocket.server.ServerEndpoint;
import
java.util.concurrent.ConcurrentHashMap;
import
java.util.concurrent.CopyOnWriteArraySet;
/**
``* WebSocket 连接测试
``*/
@Component
@ServerEndpoint``(``"/web-socket/{userName}"``)
public
class
WebSocketUtil {
``private
String userName;
``private
Session session;
``/** 固定前缀 */
``private
static
final
String USER_NAME_PREFIX = ``"user_name_"``;
``/**
``* 用来存放每个客户端对应的MyWebSocket对象。
``**/
``private
static
CopyOnWriteArraySet<WebSocketUtil> webSocketSet = ``new
CopyOnWriteArraySet<>();
``/**
``* 存放Session集合,方便推送消息 (javax.websocket.Session)
``*/
``private
static
ConcurrentHashMap<String, Session> sessionMap = ``new
ConcurrentHashMap<>();
``/**
``* 私聊:向指定客户端推送消息
``*/
``public
synchronized
static
void
privateMessage(SocketMsg socketMsg) {
``//接收消息的用户
``Session receiveUser = sessionMap.get(USER_NAME_PREFIX + socketMsg.getReceiveUser());
``//发送给接收者
``if``(receiveUser != ``null``){
``//发送给接收者
``System.out.println(socketMsg.getSendOutUser()+``" 向 "``+socketMsg.getReceiveUser()+``" 发送了一条消息:"``+socketMsg.getMsg());
``receiveUser.getAsyncRemote().sendText(socketMsg.getSendOutUser()+``":"``+socketMsg.getMsg());
``}``else``{
``//发送消息的用户
``System.out.println(socketMsg.getSendOutUser()+``" 私聊的用户 "``+socketMsg.getReceiveUser()+``" 不在线或者输入的用户名不对"``);
``Session sendOutUser = sessionMap.get(USER_NAME_PREFIX + socketMsg.getSendOutUser());
``//将系统提示推送给发送者
``sendOutUser.getAsyncRemote().sendText(``"系统消息:对方不在线或者您输入的用户名不对"``);
``}
``}
``/**
``* 群聊:公开聊天记录
``* @param userName 发送者的用户名称(当前用户)
``* @param message 发送的消息
``* @param flag 用来标识 是否要将消息推送给 当前用户
``*/
``public
synchronized
static
void
publicMessage(String userName,String message,``boolean
flag) {
``for
(WebSocketUtil item : webSocketSet) {
``Session session = item.session;
``if
(flag){
``session.getAsyncRemote().sendText(message);
``}``else
{
``//获取发送这条消息的用户
``Session currentUser = sessionMap.get(USER_NAME_PREFIX + userName);
``//消息不用推送到发送者的客户端
``if
(!session.getId().equals(currentUser.getId())){
``session.getAsyncRemote().sendText(message);
``}
``}
``}
``System.out.println(``"公共频道接收了一条消息:"``+message);
``}
``/**
``* 监听:连接成功
``* @param session
``* @param userName 连接的用户名
``*/
``@OnOpen
``public
void
onOpen(Session session, ``@PathParam``(``"userName"``) String userName) {
``this``.userName = userName;
``this``.session = session;
``sessionMap.put(USER_NAME_PREFIX + userName, session);
``webSocketSet.add(``this``);
``//在线数加1
``String tips = userName+``" 加入聊天室。当前聊天室人数为"
+ webSocketSet.size();
``System.out.println(tips);
``publicMessage(userName,tips,``true``);
``}
``/**
``* 监听:收到客户端发送的消息
``* @param message 发送的信息(json格式,里面是 SocketMsg 的信息)
``*/
``@OnMessage
``public
void
onMessage(String message) {
``if
(JSONUtil.isTypeJSONObject(message)) {
``SocketMsg socketMsg = JSONUtil.toBean(message, SocketMsg.``class``);
``if``(socketMsg.getType() == ``1``){
``//单聊,需要找到发送者和接受者
``privateMessage(socketMsg);
``}``else``{
``//群发消息
``publicMessage(socketMsg.getSendOutUser(),socketMsg.getSendOutUser()+``": "``+socketMsg.getMsg(),``false``);
``}
``}
``}
``/**
``* 监听: 连接关闭
``*/
``@OnClose
``public
void
onClose() {
``if
(sessionMap.containsKey(USER_NAME_PREFIX + userName)) {
``//连接关闭后,将此websocket从set中删除
``sessionMap.remove(USER_NAME_PREFIX + userName);
``webSocketSet.remove(``this``);
``}
``String tips = userName+``" 退出聊天室。当前聊天室人数为"
+ webSocketSet.size();
``System.out.println(tips);
``publicMessage(userName,tips,``true``);
``}
``/**
``* 监听:发生异常
``* @param error
``*/
``@OnError
``public
void
onError(Throwable error) {
``System.out.println(``"userName为:"
+ userName + ``",发生错误:"
+ error.getMessage());
``error.printStackTrace();
``}
}
|
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 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 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | <!DOCTYPE html>
<``html
lang``=``"en"``>
``<``head``>
``<``meta
charset``=``"UTF-8"``>
``<``meta
http-equiv``=``"X-UA-Compatible"
content``=``"IE=edge"``>
``<``meta
name``=``"viewport"
content``=``"width=device-width, initial-scale=1.0"``>
``<``title``>聊天室</``title``>
``<``script
src``=``"https://code.jquery.com/jquery-3.3.1.min.js"``></``script``>
``<``style
type``=``"text/css"``>
``input{
``width: 150px;
``height: 30px;
``line-height: 25px;
``padding: 5px 10px;
``border-radius: 5px;
``border: 2px solid;
``font-size: 16px;
``}
``#msg{
``width: 300px;
``}
``button{
``width: 80px;
``height: 44px;
``padding: 5px 20px;
``border-radius: 5px;
``}
``</``style``>
``</``head``>
``<``body``>
``聊天室<``br``/><``br``/>
``<``input
type``=``"text"
id``=``"sendOutUser"
placeholder``=``"自己的用户名"``>
``<``button
onclick``=``"connectWebSocket()"``>上线</``button``>
``<``button
onclick``=``"closeWebSocket()"``>下线</``button``>
``<``br``/><``br``>
``<``input
type``=``"text"
id``=``"msg"
placeholder``=``"要发送的信息"``/>
``<``input
type``=``"text"
id``=``"receiveUser"
placeholder``=``"接收人的用户名"``/>
``<``button
onclick``=``"send()"``>发送</``button``>
``<``br``><``br``>
``<``hr``>
``<``div
id``=``"msgList"``></``div``>
``<``script
type``=``"text/javascript"``>
``var websocket = null;
``//连接WebSocket
``function connectWebSocket() {
``var sendOutUser = document.getElementById("sendOutUser").value;
``if (sendOutUser === "") {
``alert("请输入用户名");
``return;
``}
``//判断当前浏览器是否支持websocket
``if ('WebSocket' in window) {
``websocket = new WebSocket("ws://localhost:7070/web-socket/"+document.getElementById("sendOutUser").value);
``} else {
``alert('当前浏览器 not support websocket')
``}
``//连接发生错误的回调方法
``websocket.onerror = function () {
``alert("连接发生错误");
``};
``//连接成功建立的回调方法
``websocket.onopen = function () {
``var sendOutUser = document.getElementById("sendOutUser")
``sendOutUser.readOnly = true
``sendOutUser.style.backgroundColor='#ddd'
``}
``//接收到消息的回调方法
``websocket.onmessage = function (event) {
``console.log(event.data)
``innerdiv("",event.data)
``}
``//连接关闭的回调方法
``websocket.onclose = function () {
``innerdiv("","websocket连接关闭");
``}
``//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
``window.onbeforeunload = function () {
``closewebsocket();
``}
``}
``//关闭连接
``function closeWebSocket() {
``websocket.close();
``}
``//发送消息
``function send() {
``var m = new Map(); // 空Map
``var sendOutId = document.getElementById("sendOutUser") //发送者
``var msg = document.getElementById("msg").value //发送消息
``if (msg === "") {
``alert("请输入消息");
``return;
``}
``var receiveUser = document.getElementById("receiveUser").value //接收者
``m.set("sendOutUser",sendOutUser.value);
``m.set("msg",msg)
``// 接收者为空时,type为群聊,否则为私聊
``if (receiveUser === "") {
``m.set("type",0)
``}else{
``m.set("receiveUser",receiveUser)
``m.set("type",1)
``}
``json = mapToJson(m)
``websocket.send(json)
``innerdiv("我",msg)
``}
``//map转换为json
``function mapToJson(map) {
``var obj= Object.create(null);
``for (var[k,v] of map) {
``obj[k] = v;
``}
``return JSON.stringify(obj);
``}
``//显示聊天记录到页面
``function innerdiv(id,txt){
``var msgList = document.getElementById("msgList")
``if (id === "") {
``msgList.innerHTML += "<``div``>" + txt + "</``div``><``br``>"
``}else{
``msgList.innerHTML += "<``div``>"+ id +": "+txt+ "</``div``><``br``>"
``}
``}
``</``script``>
``</``body``>
</``html``>
|