容器会为每个客户端连接创建一个单独的终结点实例,因此您无法执行要执行的操作。但我认为您尝试做的是在事件发生时向所有活动的客户端连接发送消息,这相当简单。
该类具有检索表示与该会话关联的终结点的实例的方法。javax.websocket.Session
getBasicRemote
RemoteEndpoint.Basic
您可以通过调用 来检索所有打开的会话,然后循环访问它们。该循环将向每个客户端连接发送一条消息。下面是一个简单的示例:Session.getOpenSessions()
@ServerEndpoint("/myendpoint")
public class MyEndpoint {
@OnMessage
public void onMessage(Session session, String message) {
try {
for (Session s : session.getOpenSessions()) {
if (s.isOpen()) {
s.getBasicRemote().sendText(message);
}
} catch (IOException ex) { ... }
}
}
但在您的案例中,您可能希望使用 CDI 事件来触发对所有客户端的更新。在这种情况下,您将创建一个 CDI 事件,Websocket 端点类中的方法会观察到该事件:
@ServerEndpoint("/myendpoint")
public class MyEndpoint {
// EJB that fires an event when a new article appears
@EJB
ArticleBean articleBean;
// a collection containing all the sessions
private static final Set<Session> sessions =
Collections.synchronizedSet(new HashSet<Session>());
@OnOpen
public void onOpen(final Session session) {
// add the new session to the set
sessions.add(session);
...
}
@OnClose
public void onClose(final Session session) {
// remove the session from the set
sessions.remove(session);
}
public void broadcastArticle(@Observes @NewArticleEvent ArticleEvent articleEvent) {
synchronized(sessions) {
for (Session s : sessions) {
if (s.isOpen()) {
try {
// send the article summary to all the connected clients
s.getBasicRemote().sendText("New article up:" + articleEvent.getArticle().getSummary());
} catch (IOException ex) { ... }
}
}
}
}
}
上面示例中的 EJB 将执行如下操作:
...
@Inject
Event<ArticleEvent> newArticleEvent;
public void publishArticle(Article article) {
...
newArticleEvent.fire(new ArticleEvent(article));
...
}
请参阅 Java EE 7 教程中有关 WebSockets 和 CDI 事件的章节。
编辑:修改了使用事件作为参数的方法。@Observer
编辑2:将循环包装在广播文章中同步,按@gcvt。
编辑 3:更新了 Java EE 7 教程的链接。干得不错,甲骨文。嘘。