原生SSM整合WebSocket
程序员文章站
2022-10-03 17:05:39
实现了消息的单发和群发,**Tomcat8**及以上版本才可使用,看清楚**util**工具类的格式,可以重新定义消息的格式,前端发消息也要按这个格式发,一段时间不访问服务器,服务器一般会断开连接,可以做一个心跳包,每隔几十秒访问一次服务器,这样服务器就不会断开连接了,心跳包是前端做的,最好再让前端做一个重连,防止意外情况。依赖 org.springframework
实现了消息的单发和群发,Tomcat8及以上版本才可使用,看清楚util工具类的格式,可以重新定义消息的格式,前端发消息也要按这个格式发,一段时间不访问服务器,服务器一般会断开连接,可以做一个心跳包,每隔几十秒访问一次服务器,这样服务器就不会断开连接了,心跳包是前端做的,最好再让前端做一个重连,防止意外情况。
依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>5.1.16.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-websocket</artifactId>
<version>8.5.31</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
Java代码
config
这个类controller里会用,但是里面不要写bean,写了在服务器上会报错
import org.springframework.context.annotation.Configuration;
@Configuration
public class WebSocketConfig {
//里面什么也不写,否则到服务器上会报错
}
controller
客户端的注册onOpen方法
客户端发送消息onMessage方法
客户端下线onClose方法
客户端异常断开连接(断网,强制中断连接等)onError方法
通知其他客户端noticeUser方法
import com.fasterxml.jackson.databind.ObjectMapper;
import com.web.chat.pojo.Message;
import com.web.chat.util.MessageUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.socket.server.standard.SpringConfigurator;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
//前端访问地址ws://..../chat.do/{当前客户端的标识}
@Controller
@ServerEndpoint(value = "/chat.do/{username}",configurator = SpringConfigurator.class)
public class ChatEndpoint {
private static Map<String, Session> onlineUsers= new ConcurrentHashMap<>();
/**
* 连接建立时调用
* @param session 长连接
* @param username 用户名
*/
@OnOpen
public void onOpen(Session session, @PathParam("username") String username){
//将对象存储到容器中
onlineUsers.put(username, session);
//通知其他客户端
noticeUser(username,onlineUsers);
}
/**
* 接收到客户端发送的数据时被调用
* @param message 消息的具体内容
* @param session 长连接
*/
@OnMessage
public void onMessage(String message, Session session){
try {
//将message转化成message对象
ObjectMapper mapper = new ObjectMapper();
Message mess = mapper.readValue(message, Message.class);
String username = mess.getUsername();
//获取发送目标
List<String> users = mess.getUsers();
//获取消息数据
String data = mess.getMessage();
//获取数据类型,是否是心跳包
String messageType = mess.getMessageType();
//不是心跳包
if (!Message.HEARTBEAT.equals(messageType)){
//保存数据到数据库
//这里可以写方法,把数据存到数据库中
//获取推送给指定用户的消息格式的数据
String resultMessage = MessageUtils.getMessage(false, username, data,"");
//发送数据
if (users .size()>0){
for (String user : users ) {
if (onlineUsers.get(user)!=null){
onlineUsers.get(user).getBasicRemote().sendText(resultMessage);
}
}
}
}
} catch (Exception e){
e.printStackTrace();
}
}
/**
* 连接断开时调用
* @param session 长连接
* @param username 用户名
*/
@OnClose
public void onClose(Session session, @PathParam("username") String username){
//从容器中删除当前的用户
onlineUsers.remove(username);
//通知所有客户端
noticeUser(username,onlineUsers);
}
/**
* 异常处理
* @param session 长连接
* @param error 异常
* @param username 用户名
*/
@OnError
public void onError(Session session, Throwable error, @PathParam("username")String username) {
//可以打印异常,可以把异常放到日志中
//error.printStackTrace();
//调用关闭链接方法,关闭链接
onClose(session,username);
}
/**
* 通知所有在线客户
* @param username 用户的唯一标识
* @param onlineUsers 缓存中用户
*/
public void noticeUser(String username,Map<String,Session> onlineUsers){
List<String> onlineNurseList = chatService.onlineNurseList(username,onlineUsers);
try {
if (onlineNurseList.size()>0){
for (String nurse : onlineNurseList) {
if (onlineUsers.get(nurse)!=null){
String resultMessage = MessageUtils.getMessage(true, null,username,"");
onlineUsers.get(nurse).getBasicRemote().sendText(resultMessage);
}
}
}
} catch (Exception e){
e.printStackTrace();
}
}
}
pojo
Message 类
接收前端传过来的参数
import java.io.Serializable;
import java.util.List;
public class Message implements Serializable {
//心跳包
public static final String HEARTBEAT="heartbeat";
//注册用户的唯一标识
private String username;
//要发送的目标
private List<String> users;
//消息内容
private String message;
//消息类型,判断是不是心跳包,
private String messageType;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public List<String> getUsers() {
return users;
}
public void setUsers(List<String> users) {
this.users = users;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getMessageType() {
return messageType;
}
public void setMessageType(String messageType) {
this.messageType = messageType;
}
}
ResultMessage 类
封装消息格式的类
import java.io.Serializable;
public class ResultMessage implements Serializable {
//判断是不是系统消息
private boolean isSystem;
//发送人
private String fromName;
//消息内容
private Object message;
//消息类型,这是判断心跳包的
private String messageType;
public boolean isSystem() {
return isSystem;
}
public void setSystem(boolean system) {
isSystem = system;
}
public String getFromName() {
return fromName;
}
public void setFromName(String fromName) {
this.fromName = fromName;
}
public Object getMessage() {
return message;
}
public void setMessage(Object message) {
this.message = message;
}
public String getMessageType() {
return messageType;
}
public void setMessageType(String messageType) {
this.messageType = messageType;
}
}
util
封装消息的工具类
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.web.chat.pojo.ResultMessage;
public class MessageUtils {
public static String getMessage(boolean isSystemMessage,String fromName,Object message,String messageType){
try {
ResultMessage result = new ResultMessage();
result.setSystem(isSystemMessage);
result.setMessage(message);
result.setMessageType(messageType);
if (fromName != null){
result.setFromName(fromName);
}
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(result);
} catch (JsonProcessingException e){
e.printStackTrace();
}
return null;
}
}
本文地址:https://blog.csdn.net/weixin_46765054/article/details/107490847