之前写了两篇关于websocket消息推送的,忽略了一个离线消息处理的问题,今天补上,其实思路很简单:发送消息的时候若对方不在线,先暂存消息,等对方在线的时候再进行推送。
前文连接
我这里写的只是思路,相对比较简单,若真实做系统还需要考虑大量session会话如何保持、多条消息先后顺序,不同人推送给同一个人如何标记,消息如何格式化等等。
@Component
@ServerEndpoint(value = "/mos/websocket/{userId}")
@Slf4j
public class WebSocket {
private static Map<String, Session> livingSession = new ConcurrentHashMap<>();
private static Map<String, String> CACHE_MESSAGE = new ConcurrentHashMap<>();
/**
* 客户端与服务端连接成功
*
* @param session
*/
@OnOpen
public void onOpen(Session session, @PathParam("userId") String userId) {
livingSession.put(userId, session);
// 判断是否有离线消息,再进行推送
String offLineMessage = CACHE_MESSAGE.get(userId);
if (offLineMessage != null) {
session.getAsyncRemote().sendText(offLineMessage + " 看到消息时间:" + DateUtil.now());
// 清空消息,避免下次上线重复推送
CACHE_MESSAGE.remove(userId);
}
}
/**
* 客户端与服务端连接关闭
*
* @param session
*/
@OnClose
public void onClose(Session session, @PathParam("userId") String userId) {
livingSession.remove(userId);
}
/**
* 客户端与服务端连接异常
*
* @param error
* @param session
*/
@OnError
public void onError(Throwable error, Session session) {
error.printStackTrace();
}
/**
* 客户端向服务端发送消息
*
* @param message
* @throws IOException
*/
@OnMessage
public void onMsg(String msg) throws IOException {
MsgEntity msgEntity = JSONUtil.toBean(msg,MsgEntity.class);
Session session = livingSession.get(msgEntity.getReceiveUserId());
String msgFmt = "%s --来自【%s】的消息,现在时间:%s";
String formatMsg = String.format(msgFmt,msgEntity.getMsg(),msgEntity.getUserId(), DateUtil.now());
if (session != null) {
session.getAsyncRemote().sendText(formatMsg);
}else{
// 消息暂存
CACHE_MESSAGE.put(msgEntity.getReceiveUserId(),formatMsg);
}
}
}