当我们创建JSF页面时,客户端请求使用Java代码和HTML的组合动态生成HTML。在使用JSF框架创建HTML页面时,我们是否可以引入钩子,使得服务器能够根据稍后在服务器上发生的异步事件(通常通过不同的线程)更新HTML页面?
当我们创建JSF页面时,客户端请求使用Java代码和HTML的组合动态生成HTML。在使用JSF框架创建HTML页面时,我们是否可以引入钩子,使得服务器能够根据稍后在服务器上发生的异步事件(通常通过不同的线程)更新HTML页面?
你可以使用@Push
和<f:websocket>
来实现这个功能。下面是一个启动示例,其中包含一个应用范围的socket,它在后端通过Event#fire()
触发的事件更新数据表,而这个事件由托管bean @Observes
处理。
<h:dataTable id="notifications" value="#{bean.notifications}" var="notification">
<h:column>#{notification.message}</h:column>
</h:dataTable>
<h:form>
<f:websocket channel="push">
<f:ajax event="updateNotifications" render=":notifications" />
</f:websocket>
</h:form>
@Named @ApplicationScoped
public class Bean {
private List<Notification> notifications;
@Inject
private NotificationService service;
@Inject @Push
private PushContext push;
@PostConstruct
public void load() {
notifications = service.list();
}
public void onNewNotification(@Observes Notification newNotification) {
notifications.add(0, newNotification);
push.send("updateNotifications");
}
public List<Notification> getNotifications() {
return notifications;
}
}
@Stateless
public class NotificationService {
@Inject
private EntityManager entityManager;
@Inject
private BeanManager beanManager;
public void create(String message) {
Notification newNotification = new Notification();
newNotification.setMessage(message);
entityManager.persist(newNotification);
beanManager.getEvent().fire(newNotification);
}
public List<Notification> list() {
return entityManager
.createNamedQuery("Notification.list", Notification.class)
.getResultList();
}
}
如果您还没有使用JSF 2.3,您需要转向第三方JSF库。
<o:socket>
(JSR356 WebSocket + CDI)<p:socket>
(Atmosphere)需要注意的是,<o:socket>
是JSF 2.3 <f:websocket>
的基础。因此,如果您发现了很多相似之处,那就是正确的。
OmniFaces使用本机JSR356 WebSocket API(支持所有Java EE 7服务器和Tomcat 7.0.27+)。因此,设置和使用起来也是最简单的(一个JAR文件,一个上下文参数,一个标签和一个注释)。它仅需要CDI(在Tomcat上安装也不难install on Tomcat),但它使您甚至可以从非JSF构件进行推送(例如,@WebServlet
)。出于安全性和JSF视图状态保持的原因,它仅支持单向推送(服务器到客户端),而不支持相反的方式。为此,您可以继续以通常的方式使用JSF ajax。JSF 2.3 <f:websocket>
在很大程度上基于OmniFaces <o:socket>
,因此它们的API中有很多相似之处(JSF - OmniFaces)。
或者,您还可以使用轮询而不是推送。几乎所有支持AJAX的JSF组件库都有一个<xxx:poll>
组件,例如PrimeFaces中的<p:poll>
。这允许您每隔X秒向服务器发送一个AJAX请求,并在必要时更新内容。与推送相比,效率稍低。
对于您来说最简单的可能是引入ajax4jsf库的“poll”组件: https://ajax4jsf.dev.java.net/nonav/documentation/ajax-documentation/entire.html#d0e1955
它不需要应用程序重新配置和JSF页面中的大量更改(仅添加a4j:poll组件)
在我的几个项目中,它表现得非常好。