2015-05-20 65 views
1

我正在開發一個Spring-MVC應用程序,並感謝所有用戶,因此我們已經有了一個可以工作的Cometd聊天功能。我們在應用程序中的另一個功能是通知,但是我們希望在實時通知發生時儘快集成它,就像Facebook一樣。Spring-MVC,Cometd:沒有@Listener的廣播

基本上這個想法是,無論何時創建新通知,它都會保存在數據庫中,並且其後端的信息必須傳遞給每個用戶在唯一通道上登錄用戶的通知。

我想知道這種方法是否可行,因爲我需要做一些工作來將通知路由到聊天類。請注意,我沒有用於ChatServiceImpl類的接口。可以嗎?夠交談,這裏的代碼:

ChatServiceImpl:

@Named 
@Singleton 
@Service 
public class ChatServiceImpl { 
    @Inject 
    private BayeuxServer bayeux; 

    @Session 
    private ServerSession serverSession; 


    public void sendNotification(Notification notification,int id 
// And then I send notification here like below, by extracting information from the notification object. 

ServerChannel serverChannel = bayeux.createChannelIfAbsent("/person/notification/" + id).getReference(); 
     serverChannel.setPersistent(true); 
     serverChannel.publish(serverSession, output); 
     } 
    } 

上述類沒有接口,所以我正打算使用的方法如下:

@Service 
@Transactional 
public class GroupCanvasServiceImpl implements GroupCanvasService{ 
    private ChatServiceImpl chatService; 

    public void someMethod(){ 
    chatService.sendNotification(notification, id); 
} 
} 

BayeuxInitializer:

@Component 
public class BayeuxInitializer implements DestructionAwareBeanPostProcessor, ServletContextAware 
{ 
    private BayeuxServer bayeuxServer; 
    private ServerAnnotationProcessor processor; 

    @Inject 
    private void setBayeuxServer(BayeuxServer bayeuxServer) 
    { 
     this.bayeuxServer = bayeuxServer; 
    } 

    @PostConstruct 
    private void init() 
    { 

     this.processor = new ServerAnnotationProcessor(bayeuxServer); 
    } 

    @PreDestroy 
    private void destroy() 
    { 
     System.out.println("Bayeux in PreDestroy"); 
    } 

    public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException 
    { 
     processor.processDependencies(bean); 
     processor.processConfigurations(bean); 
     processor.processCallbacks(bean); 
     return bean; 
    } 

    public Object postProcessAfterInitialization(Object bean, String name) throws BeansException 
    { 
     return bean; 
    } 

    public void postProcessBeforeDestruction(Object bean, String name) throws BeansException 
    { 
     processor.deprocessCallbacks(bean); 
    } 

    @Bean(initMethod = "start", destroyMethod = "stop") 
    public BayeuxServer bayeuxServer() 
    { 
     return new BayeuxServerImpl(); 
    } 

    public void setServletContext(ServletContext servletContext) 
    { 
     servletContext.setAttribute(BayeuxServer.ATTRIBUTE, bayeuxServer); 
    } 
} 

請讓我知道這種方法是否可行。非常感謝。

回答

2

@Listener註釋用於處理從遠程客戶端接收的消息的方法。

如果您只需發送服務器到客戶端的消息,則不必嚴格按照@Listener註釋任何方法:只需檢索要發佈到的ServerChannel即可,並用它來發布信息。

在您的具體情況下,似乎您並不需要在多個訂閱者的頻道上廣播消息,但您只需將消息發送到由id參數標識的特定客戶端。

如果是這樣的話,那麼它可能會更好只使用對等網絡通訊以這樣的方式

public void sendNotification(Notification notification, int id) 
{ 
    ServerSession remoteClient = retrieveSessionFromId(id); 
    remoteClient.deliver(serverSession, "/person/notification", notification); 
} 

該解決方案的優點創造少了很多渠道(你不需要一個頻道每id)。

更好的是,您可以使用服務頻道(如/service/notification)替換/person/notification頻道(這是一個廣播頻道)。 通過這種方式,很明顯,用於傳送通知的信道用於對等通信(因爲服務信道不能用於廣播消息)。

retrieveSessionFromId()方法是用戶登錄時必須映射的方法,請參閱有關CometD authentication的文檔。

+0

通過使用server.publish,默認的人已經工作了,但使用.deliver會更有意義。你有通過Spring-Security使用retrieveSessionFromId()的代碼嗎?我會研究它併發布任何問題。非常感謝。 :-) –

+0

你可以請檢查這個問題:http://stackoverflow.com/questions/31512310/cometd-multiple-tabs-for-online-users-management-creating-false-online-status。非常感謝。 :-) –