WebSocket实现消息推送
WebSocket的工作流程是这 样的:浏览器通过JavaScript向服务端发出建立WebSocket连接的请求,在WebSocket连接建立成功后,客户端和服务端就可以通过 TCP连接传输数据。因为WebSocket连接本质上是TCP连接,不需要每次传输都带上重复的头部数据,所以它的数据传输量比轮询和Comet技术小 了很多。本文不详细地介绍WebSocket规范,主要介绍下WebSocket在Java Web中的实现。
服务端代码
@ServerEndpoint(value = "/ws_chatroom/fh", configurator = HttpSessionConfigurator.class)
public class WSServer {
private static Logger logger = LoggerFactory.getLogger(WSServer.class);
// 已登录的所有的session。一个用户账号可以在多个地方登录,所以此处用list来存储
private static final ConcurrentMap<String, List<WSServer>> map = Maps.newConcurrentMap();
// 与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
// 当前会话的httpsession
private HttpSession httpSession;
/**
* 建立连接
*/
@OnOpen
public void onOpen(Session session, EndpointConfig config) {
try {
// 得到httpSession
List<WSServer> clients = map.get("-1");
if (clients == null) {
clients = new CopyOnWriteArrayList<>();
}
clients.add(this);
map.put("-1", clients);
this.session = session;
logger.info("建立连接时,从session中获取当前用户信息为空,可能是session已过期");
} catch (Exception e) {
logger.info("什么时候会走到这里来啊");
// 长时间不操作,session过期了。需要用户刷新页面重新建立连接
} finally {
// 连接数+1
addOnlineCount();
logger.debug("有新的连接,当前连接数为:" + getOnlineCount());
}
}
/**
* 关闭连接
*/
@OnClose
public void onClose() {
try {
// 这个session可能会过期
UserInfo userInfo = (UserInfo) this.httpSession.getAttribute("currentUser");
if (userInfo != null) {
List<WSServer> clients = map.get(userInfo.getUserCode());
if (clients != null && clients.size() > 0) {
clients.remove(this);// 要判断对象是不是同一个
}
} else {
logger.info("关闭连接时,从session中获取当前用户信息为空,可能是session已过期");
}
} catch (Exception e) {
// 关闭连接时,session可能已经过期
// session过期后,拿不到usercode了,放在map中的wsserver就无法被移除了,等它自动过期吧
} finally {
// 连接数-1
subOnlineCount();
logger.debug("有一连接断开,当前连接数为:" + getOnlineCount());
}
}
/**
* websocket系统异常处理
*
* @param t 异常
*/
@OnError
public void onError(Throwable t) {
logger.error("websocket系统异常处理", t);
}
public static void sendMsg(String userid, WebSocketBean data) {
// 通过用户ID获取当前用户登录的所有session
// 给所有的这些session发消息
List<WSServer> clients = map.get(userid);
if (clients != null) {
// 群发
Iterator<WSServer> it = clients.iterator();
while (it.hasNext()) {
WSServer client = it.next();
try {
if (!client.session.isOpen()) {
clients.remove(client);
continue;
}
if (client.session != null) {
client.session.getBasicRemote().sendText(JSON.toJSONString(data));
}
} catch (IOException e) {
logger.error("发送消息异常", e);
}
}
}
}
// 获取连接数
private static synchronized int getOnlineCount() {
return MessageConstant.onlineCount;
}
// 增加连接数
private static synchronized void addOnlineCount() {
MessageConstant.onlineCount++;
}
// 减少连接数
private static synchronized void subOnlineCount() {
MessageConstant.onlineCount--;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
WSServer that = (WSServer) o;
if (that.session.getId().equals(this.session.getId())) {
return true;
}
return false;
}
@Override
public int hashCode() {
int result = session != null ? session.hashCode() : 0;
result = 31 * result + (httpSession != null ? httpSession.hashCode() : 0);
return result;
}
}
**
*
* 消息内容JAVABEAN
*
*
*
*/
public class MessageDto {
/**
* 消息ID
*/
private String id;
/**
* 发送用户ID
*/
private String sender;
/**
* 接收用户ID
*/
private String[] receivers;
/**
* 聊天内容
*/
private String chatContent;
/**
* 发送时间
*/
private String time;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getSender() {
return sender;
}
public void setSender(String sender) {
this.sender = sender;
}
public String[] getReceivers() {
return receivers;
}
public void setReceivers(String[] receivers) {
this.receivers = receivers;
}
public String getChatContent() {
return chatContent;
}
public void setChatContent(String chatContent) {
this.chatContent = chatContent;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
@Override
public String toString() {
return JSON.toJSONString(this);
}
}