Jsf 带有p:poll/push的通知系统
我已经尝试为一个基本的社交网络实现基本通知系统,在视图层上使用Jsf 带有p:poll/push的通知系统,jsf,jsf-2,primefaces,Jsf,Jsf 2,Primefaces,我已经尝试为一个基本的社交网络实现基本通知系统,在视图层上使用p:poll,以及一个简单的NotificationService类,该类从DB获取新通知,并刷新NotificationBean的通知列表,该列表为每个用户设置了查看范围。工艺流程与此类似: -Poll calls NotificationBean.getNewNotifications for example every 15 sec. --getNewNotifications calls NotificationService
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框架的应用程序,它打开了web套接字,似乎更适合创建通知系统
但我不知道应该使用哪些组件以及它们的哪些属性。它有p:socket
组件,具有channel
属性。我应该使用用户名作为频道
值吗?以下代码来自PrimeFaces showcase,总结了最后几句话:
<p:socket onMessage="handleMessage" channel="/notifications" />
但这将通知所有用户页面,我需要一个推送通知特定用户。假设有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);
}
}
您应该将通道值指定给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>
函数handleMessage(facesmessage){
facesmessage.severity='info';
咆哮秀([facesmessage]);
}
对于可伸缩性问题,您应该维护活动或非活动通道。您可以删除一段时间内未处于会话或非活动状态的。当bean正在销毁时,使用@PreDestroy注释删除通道。在我的解决方案中,一个用户会话只有一个通道
我的建议是,;不要在页面上明确使用用户名。出于安全原因,这不太好。您想让一个用户立即向其他用户发送消息吗?@ronnk这取决于您对
消息的理解方式。在问题中,我提到了包含通知的列表。如果user1将user2添加为好友或对其状态的注释,则应将通知附加到user2的通知列表中,该列表可以是普通字符串列表,也可以是更适合我的实现的模型类列表。所以,是的,这必须是立即的。(对不起我的英语)好的,我想你们不想使用轮询,所以服务器将广播消息,每个客户端将进行筛选,或者服务器必须存储客户端的地址并发送到特定的地址,我认为。让专业人士来解决您的问题:)是的,这正是我需要的:)这似乎是正确的,但我仍然很少担心它的性能,是否有其他预防措施?顺便说一句,感谢您的回答,正如您可能想象的那样,我将等待赏金到期,而不是蛋糕。我知道JSF本身的性能问题,很多人对存储用户的视图状态有偏见,这会降低性能。但它提供了很多功能,实际上我想亲自体验一下,当我这么做的时候,它应该被灵活地实现,以获得最大的性能。这就是为什么我问了这个问题,这就是为什么我想摆脱p:poll
@erencan这个应用程序范围的bean线程安全吗?由于有多个并发用户,您应该注意这一点。@oko应用程序范围的bean不是线程安全的。此外,hashmap put方法不是原子的。所以可能会出现一些问题。正如我所建议的,这是一个实现细节。您可以通过使用事务在数据库中保持通道,或使addChannel方法同步。@ÖmerFarukAlmalı就我跟踪atmosphere的源代码而言,有一个查找表,可以像您想象的那样维护ip和通道匹配。唯一的可能是重载此查找表。该表位于org.atmosphere.cpr.DefaultBroadcasterFactory中,并存储在store hashmap中。应该需要对大气进行一些实现才能刷新此表。
@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: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>