12

我尝试为具有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频道。推送代码片段是:

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"));

但我不确定这是否是这种功能需求的正确用法。考虑到应用程序的可扩展性,每个进程打开如此多的通道可能会产生昂贵的成本。

感谢您的帮助。

4

1 回答 1

8

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 注释删除通道。在我的解决方案中,一个用户会话有一个通道。

My suggestion is; do not use usernames explicitly on the pages. It is not good for security reasons.

于 2013-04-17T08:20:44.430 回答