我尝试为一个基本的社交网络实现基本的通知系统,p:poll
在视图层和一个简单的NotificationService
类,它从DB获得新的通知,并刷新NotificationBean
的通知列表,这是每个用户的视图范围。类似于下面的流程:
-Poll calls NotificationBean.getNewNotifications for example every 15 sec.
--getNewNotifications calls NotificationService and DAO methods
---notificationList of user is refreshed
----DataTable on view layer shows new notifications
但是p:poll
关心的是它的性能,因为它在每个间隔过期时发送一个查询。
PrimeFaces有基于Atmosphere框架的PrimePush,它打开了web sockets,似乎更适合创建通知系统。
但是我不知道应该使用哪些组件和它们的哪些属性。它有p:socket
组件与channel
属性。我应该使用用户名作为channel
值吗?下面的代码来自PrimeFaces展示并总结了最后的句子:
<p:socket onMessage="handleMessage" channel="/notifications" />
据我所知,从这个演示示例中,p:socket
监听notifications
通道。push代码片段为:
PushContext pushContext = PushContextFactory.getDefault().getPushContext();
pushContext.push("/notifications", new FacesMessage(summary, detail));
但是这将通知所有的用户页面,我需要一个推送通知特定的用户。假设有2个用户,并假设User1将User2添加为好友。肯定有这样的事情:
pushContext.push("User2/notifications", new FacesMessage("friendship request", "from User1"));
但我不确定这是否是这种功能需求的正确用法。考虑到应用程序的可扩展性,每个进程打开如此多的通道可能会带来昂贵的成本。
谢谢你的帮助。
PrimeFaces push支持一个或多个通道推送。能够为特定原因创建专用通道;例如,对于像您这样的每个用户,您可以创建多个通道。为此,我使用了唯一id。
基本上,我已经实现了一个托管bean,它是应用程序范围,处理应该考虑的用户通道匹配。你可以用不同的方法来维护它。
@ManagedBean
@ApplicationScoped
public class ChannelsBean {
Map<String, String> channels = new HashMap<String, String>();
public void addChannel(String user, String channel) {
channels.put(user, channel);
}
public String getChannel(String user) {
return channels.get(user);
}
}
然后将这个bean注入到发送通知的后台bean中。
@ManagedBean
@SessionScoped
public class GrowlBean {
private String channel;
@ManagedProperty(value = "#{channelsBean}")
private ChannelsBean channels;
private String sendMessageUser;
private String user;
@PostConstruct
public void doPostConstruction() {
channel = "/" + UUID.randomUUID().toString();
channels.addChannel(user, channel);
}
public void send() {
PushContext pushContext = PushContextFactory.getDefault().getPushContext();
pushContext.push(channels.getChannel(sendMessageUser), new FacesMessage("Hi ", user));
}
//Getter Setters
}
你应该给p:socket通道值。下面是页面的启动示例;
<p:growl widgetVar="growl" showDetail="true" />
<h:form>
<p:panel header="Growl">
<h:panelGrid columns="2">
<p:outputLabel for="user" value="User: " />
<p:inputText id="user" value="#{growlBean.sendMessageUser}" required="true" />
</h:panelGrid>
<p:commandButton value="Send" actionListener="#{growlBean.send}" />
</p:panel>
</h:form>
<p:socket onMessage="handleMessage" channel="#{growlBean.channel}" />
<script type="text/javascript">
function handleMessage(facesmessage) {
facesmessage.severity = 'info';
growl.show([facesmessage]);
}
</script>
对于可伸缩性问题,您应该维护活动通道或非活动通道。您可以删除一个不在会话或非活动一段时间。当bean销毁时,使用@PreDestroy注释删除通道。在我的解决方案中,一个用户会话有一个通道。
我的建议是;不要在页面上明确地使用用户名。从安全角度考虑,这是不好的。