springbootboot配置websocket
java
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Component
@Slf4j
@ServerEndpoint("/websocketHandler/{userId}")
public class MyWebSocketHandler {
/**
* 线程安全Map
*/
private static ConcurrentHashMap<String, Session> sessionPool = new ConcurrentHashMap<>();
/**
* Redis触发监听名字
*/
public static final String REDIS_TOPIC_NAME = "socketHandlerReport";
//==========【websocket接受、推送消息等方法 ------ 具体服务节点推送ws消息】========================================================================================
@OnOpen
public void onOpen(Session session, @PathParam(value = "userId") String userId) {
try {
sessionPool.put(userId, session);
log.info("【系统 WebSocket】有新的连接,总数为:" + sessionPool.size());
} catch (Exception e) {
}
}
@OnClose
public void onClose(@PathParam("userId") String userId) {
try {
sessionPool.remove(userId);
log.info("【系统 WebSocket】连接断开,总数为:" + sessionPool.size());
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* ws推送消息
*
* @param userId
* @param message
*/
public void pushMessage(String userId, String message) {
for (Map.Entry<String, Session> item : sessionPool.entrySet()) {
//userId key值= {用户id + "_"+ 登录token的md5串}
if (item.getKey().contains(userId)) {
Session session = item.getValue();
try {
//update-begin-author:taoyan date:20211012 for: websocket报错 https://gitee.com/jeecg/jeecg-boot/issues/I4C0MU
synchronized (session) {
log.info("【系统 WebSocket】推送单人消息:" + message);
session.getBasicRemote().sendText(message);
}
//update-end-author:taoyan date:20211012 for: websocket报错 https://gitee.com/jeecg/jeecg-boot/issues/I4C0MU
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
}
}
/**
* ws遍历群发消息
*/
public void pushMessage(String message) {
try {
for (Map.Entry<String, Session> item : sessionPool.entrySet()) {
try {
item.getValue().getAsyncRemote().sendText(message);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
log.info("【系统 WebSocket】群发消息:" + message);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
/**
* ws接受客户端消息
*/
@OnMessage
public void onMessage(String message, @PathParam(value = "userId") String userId) {
if (!"ping".equals(message) && !WebsocketConst.CMD_TOPIC.equals(message)) {
log.info("【系统 WebSocket】收到客户端消息:" + message);
} else {
log.debug("【系统 WebSocket】收到客户端消息:" + message);
}
//------------------------------------------------------------------------------
// JSONObject obj = new JSONObject();
// //业务类型
// obj.put(WebsocketConst.MSG_CMD, WebsocketConst.CMD_CHECK);
// //消息内容
// obj.put(WebsocketConst.MSG_TXT, "心跳响应");
// this.pushMessage(userId, obj.toJSONString());
//------------------------------------------------------------------------------
//--------PC端消息推送--------
Session session = sessionPool.get(userId);
if (session != null && session.isOpen()) {
try {
log.info("【websocket消息】 单点消息:" + message);
session.getAsyncRemote().sendText(message);
} catch (Exception e) {
e.printStackTrace();
}
}
//--------增加APP端消息推送--------
Session session_app = sessionPool.get(userId + APP_SESSION_SUFFIX);
if (session_app != null && session_app.isOpen()) {
try {
log.info("【websocket移动端消息】 单点消息:" + message);
session_app.getAsyncRemote().sendText(message);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 配置错误信息处理
*
* @param session
* @param t
*/
@OnError
public void onError(Session session, Throwable t) {
log.warn("【系统 WebSocket】消息出现错误");
//t.printStackTrace();
}
//==========【系统 WebSocket接受、推送消息等方法 ------ 具体服务节点推送ws消息】========================================================================================
//==========【采用redis发布订阅模式------推送消息】========================================================================================
/**
* 后台发送消息到redis
*
* @param message
*/
public void sendMessage(String message) {
//log.info("【系统 WebSocket】广播消息:" + message);
// BaseMap baseMap = new BaseMap();
// baseMap.put("userId", "");
// baseMap.put("message", message);
// jeecgRedisClient.sendMessage(REDIS_TOPIC_NAME, baseMap);
}
/**
* 此为单点消息 redis
*
* @param userId
* @param message
*/
public void sendMessage(String userId, String message) {
// BaseMap baseMap = new BaseMap();
// baseMap.put("userId", userId);
// baseMap.put("message", message);
// jeecgRedisClient.sendMessage(REDIS_TOPIC_NAME, baseMap);
}
/**
* 此为单点消息(多人) redis
*
* @param userIds
* @param message
*/
public void sendMessage(String[] userIds, String message) {
for (String userId : userIds) {
sendMessage(userId, message);
}
}
//=======【采用redis发布订阅模式------推送消息】==========================================================================================
//1.增加app端标识
private String APP_SESSION_SUFFIX = "_app";
public void sendOneMessage(String userId, String message) {
//--------PC端消息推送--------
Session session = sessionPool.get(userId);
if (session != null && session.isOpen()) {
try {
log.info("【websocket消息】 单点消息:" + message);
session.getAsyncRemote().sendText(message);
} catch (Exception e) {
e.printStackTrace();
}
}
//--------增加APP端消息推送--------
Session session_app = sessionPool.get(userId + APP_SESSION_SUFFIX);
if (session_app != null && session_app.isOpen()) {
try {
log.info("【websocket移动端消息】 单点消息:" + message);
session_app.getAsyncRemote().sendText(message);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* 开启WebSocket支持
*/
@Configuration
@EnableWebSocket
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
java
public class WebsocketConst {
/**
* 消息json key:cmd
*/
public static final String MSG_CMD = "cmd";
/**
* 消息json key:msgId
*/
public static final String MSG_ID = "msgId";
/**
* 消息json key:msgTxt
*/
public static final String MSG_TXT = "msgTxt";
/**
* 消息json key:userId
*/
public static final String MSG_USER_ID = "userId";
/**
* 消息json key:chat
*/
public static final String MSG_CHAT = "chat";
/**
* 消息类型 heartcheck
*/
public static final String CMD_CHECK = "heartcheck";
/**
* 消息类型 user 用户消息
*/
public static final String CMD_USER = "user";
/**
* 消息类型 topic 系统通知
*/
public static final String CMD_TOPIC = "topic";
/**
* 消息类型 email
*/
public static final String CMD_EMAIL = "email";
/**
* 消息类型 meetingsign 会议签到
*/
public static final String CMD_SIGN = "sign";
/**
* 消息类型 新闻发布/取消
*/
public static final String NEWS_PUBLISH = "publish";
}
项目启动后遇到如下错误:
java
Invocation of init method failed; nested exception is java.lang.IllegalStateException: javax.websocket.server.ServerContainer not available
用IDEA启动项目,所报的异常,打jar包服务器上运行则不报,原因是spring boot内带tomcat,tomcat中的websocket会有冲突出现问题。我的解决办法:
注释掉WebSocketConfig中的
java
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}