2015-05-20 29 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。非常感谢。 :-) –