- 引用WebSocket相关依赖
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>4.3.30.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>4.3.30.RELEASE</version>
</dependency>
- 后端代码实现,很简单分为消息封装和消息处理
package com.risen.brain.websocket;
import com.alibaba.fastjson.JSONObject;
import com.risen.brain.websocket.entity.Message;
import com.risen.brain.websocket.entity.MessageData;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author Administrator
*/
@ServerEndpoint("/public/xzdnTaskSocket/{platform}/{groupId}/{selfId}")
@Component
public class MessageWebSocket {
private static Map<String, MessageWebSocket> userMap = new ConcurrentHashMap<>();
private static Map<String, Set<MessageWebSocket>> roomMap = new ConcurrentHashMap<>();
private Session session;
private String selfId;
//建立连接成功调用
@OnOpen
public void onOpen(Session session, @PathParam(value = "platform") String platform, @PathParam(value = "groupId") String groupId, @PathParam(value = "selfId") String selfId) {
this.session = session;
this.selfId = selfId;
userMap.put(selfId, this);
if (!roomMap.containsKey(groupId)) {
Set<MessageWebSocket> set = new HashSet<>();
set.add(userMap.get(selfId));
roomMap.put(groupId, set);
} else {
roomMap.get(groupId).add(this);
}
MessageData messageData = new MessageData();
messageData.setSelfId(selfId);
messageData.setGroupId(groupId);
messageData.setPlatform(platform);
messageData.setType("meta");
messageData.setDetailType("online");
System.out.println(selfId + "加入了群聊!");
Message dataMessage = new Message(selfId + "加入了群聊!");
messageData.setMessages(Arrays.asList(dataMessage));
sendMessageTo(messageData, groupId, selfId);
}
//关闭连接时调用
@OnClose
public void onClose(@PathParam(value = "selfId") String selfId, @PathParam("groupId") String groupId) {
if (roomMap.containsKey(groupId)) {
Set<MessageWebSocket> set = roomMap.get(groupId);
for (MessageWebSocket item : set) {
if (item.selfId.equals(selfId)) {
set.remove(item);
}
}
}
}
//收到客户端信息
@OnMessage
public void onMessage(String message, @PathParam(value = "platform") String platform, @PathParam(value = "selfId") String selfId, @PathParam("groupId") String groupId) {
MessageData messageData = new MessageData();
List<Message> objects = new ArrayList<>();
Message mg = new Message();
mg.setData(message);
mg.setType("text");
objects.add(mg);
messageData.setMessages(objects);
messageData.setPlatform(platform);
sendMessageTo(messageData, groupId, selfId);
//根据bean名称获取对象,可以对消息进行记录
//IXzdnInvestigateCityService xzdnInvestigateCityService1 = SpringUtil.getBean("xzdnInvestigateCityService");
//XzdnInvestigateCity city = new XzdnInvestigateCity();
//List<Map> groupCityCount = xzdnInvestigateCityService1.findGroupCityCount(city);
System.out.println("2222");
/*TableDynaModel tableDynaModel = tableDynaDao.newDynaModel("xzdn_task_message_info");
tableDynaModel.set("xzdnMessageId", messageData.getId());
tableDynaModel.set("xzdnMessagePlatform", messageData.getPlatform());
tableDynaModel.set("xzdnMessageSelfid", messageData.getSelfId());
tableDynaModel.set("xzdnMessageSelfname", messageData.getSelfName());
tableDynaModel.set("xzdnMessageSelfdeptid", messageData.getSelfDeptId());
tableDynaModel.set("xzdnMessageSelfdeptname", messageData.getSelfDeptName());
tableDynaModel.set("xzdnMessageTime", messageData.getTime());
tableDynaModel.set("xzdnMessageType", messageData.getType());
tableDynaModel.set("xzdnMessageDetailtype", messageData.getDetailType());
tableDynaModel.set("xzdnMessageMessagetype", messageData.getMessageType());
tableDynaModel.set("xzdnMessageGroupid", messageData.getGroupId());
tableDynaModel.set("xzdnMessageMessages", JSONObject.toJSONString(messageData.getMessages()));
tableDynaDao.save(tableDynaModel);*/
}
//错误时调用
@OnError
public void onError(Session session, Throwable throwable) {
System.out.println("发生错误");
throwable.printStackTrace();
}
/**
* 群聊
*
* @param message 消息
* @param groupId 房间号
* @param selfId 发送人
*/
public static void sendMessageTo(MessageData message, String groupId, String selfId) {
message.setGroupId(groupId);
message.setSelfId(selfId);
if (roomMap.containsKey(groupId)) {
for (MessageWebSocket item : roomMap.get(groupId)) {
//if (!item.selfId.equals(selfId)) {
item.session.getAsyncRemote().sendText(JSONObject.toJSONString(message));
// }
}
}
}
/**
* 私聊
*
* @param message 消息
* @param toSelfId 接收人
*/
public void sendUserTo(String message, String toSelfId) {
if (userMap.containsKey(toSelfId)) {
userMap.get(toSelfId).session.getAsyncRemote().sendText(message);
}
}
}
- 消息封装,里面包含房间信息,用户信息、消息
package com.risen.brain.websocket.entity;
import lombok.Data;
@Data
public class Message {
/**
* 消息类型 text,json,image,audio,video,file,markdown,btn
*/
private String type;
/**
* 内容 媒体类容均为文件id/url/详情json
*/
private String data;
public Message() {
}
public Message(String data) {
this.data = data;
this.type = "text";
}
}
package com.risen.brain.websocket.entity;
import com.risen.brain.utils.SequenceUtils;
import lombok.Data;
import java.math.BigInteger;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.List;
/**
* Created with IntelliJ IDEA.
* * @Author: yxz
* @Date: 2021/10/18/10:21
* @Description:
*/
@Data
public class MessageData {
/**
* 事件唯一标识符
*/
private BigInteger id;
/**
* 实现平台名称,协议名称 web,dd
*/
private String platform;
/**
* 消息发送人 id
*/
private String selfId;
/**
* 消息发送人
*/
private String selfName;
/**
* 消息发送人部门id
*/
private String selfDeptId;
/**
* 消息发送人部门
*/
private String selfDeptName;
/**
* 事件发生时间(Unix 时间戳),单位:秒
*/
private Long time;
/**
* 事件类型,必须是 meta、message、notice、request 中的一个,分别表示元事件、消息事件、通知事件和请求事件
*/
private String type;
/**
* 事件详细类型
* meta: online,heartbeat 分别表示 首次连接,心跳包
* message:
* notice: remove 删除通知
* request:
*/
private String detailType;
/**
* 消息类型 1:群消息
*/
private String messageType;
/**
* 群消息时的群id
*/
private String groupId;
/**
* 消息段
*/
private List<Message> messages;
public MessageData() {
this.id = SequenceUtils.nextId();
this.time = LocalDateTime.now().toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
}
}
- 前端代码实现,本人不是专业前端,网上随便找个了页面做交互
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>My WebSocket</title>
<style>
#message {
margin-top: 40px;
border: 1px solid gray;
padding: 20px;
}
</style>
</head>
<body>
<button onclick="conectWebSocket()">连接WebSocket</button>
<button onclick="closeWebSocket()">断开连接</button>
<hr />
<br />
消息:<input id="text" type="text" />
<button onclick="send()">发送消息</button>
<div id="message"></div>
</body>
<script type="text/javascript">
//获取地址栏参数,key:参数名称
const urlParams = new URLSearchParams(window.location.search);
//发信息用户
const user = urlParams.get('user');
//房间名称
const type = urlParams.get('group');
var websocket = null;
function conectWebSocket() {
//判断当前浏览器是否支持WebSocket
if ('WebSocket' in window) {
websocket = new WebSocket("ws://localhost:8081/xzdn/public/xzdnTaskSocket/web/"+type+"/"+user);
} else {
alert('Not support websocket')
}
//连接发生错误的回调方法
websocket.onerror = function () {
setMessageInnerHTML("error");
};
//连接成功建立的回调方法
websocket.onopen = function (event) {
setMessageInnerHTML("tips: 连接成功!");
}
//接收到消息的回调方法
websocket.onmessage = function (event) {
setMessageInnerHTML(event.data);
}
//连接关闭的回调方法
websocket.onclose = function () {
setMessageInnerHTML("tips: 关闭连接");
}
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function () {
websocket.close();
}
}
//将消息显示在网页上
function setMessageInnerHTML(innerHTML) {
document.getElementById('message').innerHTML += innerHTML + '<br/>';
}
//关闭连接
function closeWebSocket() {
websocket.close();
}
//发送消息
function send() {
var message = document.getElementById('text').value;
websocket.send(message,"web",user,type);
}
</script>
</html>
- 最终效果
超人发送信息:房间号:加班放假
王亮在房间“加班放假”中,收到了超人信息,并进行回答
四环单独在“吃喝玩乐”房间并没有收到房间“加班放假”中的消息