最近参加实训,负责的相关工作要求实现一个聊天室,因为给的资料里有用WebSocket做聊天室的示例,所以便选择了WebSocket。
原理
WebSocket是一个网络协议,有别于HTTPS协议,它提供一个客户端到服务器的长连接。事实上,就做这个功能而言,我们知道这么多就够了,然后知道它怎么连,就可以实现实时聊天。
但我还是讲讲我的理解,我这只小萌新并不太了解WebSocket的内部工作机制,但还是知道HTTPS和WebSocket的区别的。首先,以前的HTTPS协议是怎么工作的呢,它的服务器是被动的,也就是说我每次要请求什么服务,我就向服务器发出询问,然后等待服务器回应,这必然导致一个延迟。而WebSocket呢,我和你连上了,只要没人提分手,也没出现啥不可抗力的意外(故障,错误),咱就一直连着,你有啥直接和我说,我也一样,也就是说相比HTTPS省去了一次又一次的沟通成本,所以它快,能做实时聊天。
依赖项
我用的是Maven管理项目,要用WebSocket,所以你在正常的配置springboot项目后,在pom.xml里添这个依赖项:`
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
WebSocket使用
先上代码:
import com.gzws.service.MessageService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.websocket.RemoteEndpoint;
import javax.websocket.Session;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public final class WebSocketUtils {
private static final Logger logger = LoggerFactory.getLogger(WebSocketUtils.class);
public static MessageService messageService;
// 存储 websocket session
public static final Map<String, Session> ONLINE_USER_SESSIONS = new ConcurrentHashMap<>();
/**
* @param session 用户 session
* @param message 发送内容
*/
public static void sendMessage(Session session, String message) {//发送消息
if (session == null) {
return;
}
final RemoteEndpoint.Basic basic = session.getBasicRemote();
if (basic == null) {
return;
}
try {
basic.sendText(message);
} catch (IOException e) {
logger.error("sendMessage IOException ",e);
}
}
public static void sendMessageToId(Long tid,Long sid, String message){//发送消息给特定ID
Session session=ONLINE_USER_SESSIONS.get(String.valueOf(tid));
if(session==null){
messageService.reply(tid,sid,message);
}else {
sendMessage(session,message);
messageService.onLineReply(tid,sid,message);
}
}
public static void sendMessageAll(String message) {//发送消息给全体
ONLINE_USER_SESSIONS.forEach((sessionId, session) -> sendMessage(session, message));
}
我这里做成了一个工具类,我们看到里面的方法和成员变量都做成了静态,它本身也不可继承。方法的用处大家都能看出来,这里我们看参数session,很明显WebSocket这里使用session在传消息。我们知道当我们访问一台服务器时,该服务器会为每个用户生成专属的session。
所以我们不妨多想一想:假如我们不在同一个服务器呢?假如对方不在线呢?WebSocket能解决这些问题吗?很显然,不能。它只是一个网络协议,你不能要求它做完所有事。事实上,你得想办法做session共享;还有要在对方不在线时,想办法把消息存起来,然后对方一上线就能看到。
这里得说一下,相信很多人也遇到了在WebSocket里Service注入的问题,咋解决呢,将在WebSocket里的Service设为static,为什么呢:
本质原因:spring管理的都是单例(singleton),和 websocket (多对象)相冲突。