【问题标题】:Spring-MVC, Cometd : Broadcasting without @ListenerSpring-MVC,Cometd:没有@Listener 的广播
【发布时间】:2015-08-01 09:39:30
【问题描述】:

我正在开发一个 Spring-MVC 应用程序,感谢 SO 上的用户,我们已经有了一个可用的 Cometd 聊天功能。我们在应用程序中拥有的另一个功能是通知,但我们希望在它们发生时立即集成实时通知,有点像 Facebook 的功能。

基本上这个想法是,每当创建新通知时,它都会保存在数据库中,并且必须将来自后端的信息传递给每个用户在唯一通道上登录用户的通知。

我想知道这种方法是否可行,因为我需要做一些工作才能将通知路由到聊天类。请注意,我也没有 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);
    }
}

如果这种方法可行,请告诉我。非常感谢。

【问题讨论】:

    标签: java spring spring-mvc cometd reverse-ajax


    【解决方案1】:

    @Listener 注释适用于处理从远程客户端接收到的消息的方法。

    如果你只需要发送服务器到客户端的消息,你不需要用@Listener来注释任何方法:你检索你想要发布到的ServerChannel并使用它就足够了发布消息。

    在您的特定情况下,您似乎不需要在一个频道上为多个订阅者广播消息,但您只需要向特定客户端发送消息,由id 参数标识。

    如果是这样,那么以这种方式使用点对点消息传递可能会更好:

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

    此解决方案的优势在于创建的频道更少(您不需要每个id 的频道)。

    更好的是,您可以将/person/notification 频道(这是一个广播频道)替换为/service/notification 等服务频道。 这样一来,很明显用于传递通知的通道是用于点对点通信的(因为服务通道不能用于广播消息)。

    retrieveSessionFromId() 方法是您必须在用户登录时映射的东西,例如有关 CometD authentication 的文档。

    【讨论】:

    • 默认人已经使用 server.publish,但使用 .deliver 更有意义。你有任何通过 Spring-Security 使用 retrieveSessionFromId() 的代码吗?如果有任何问题,我会调查并发布问题。非常感谢。 :-)
    • 你能检查一下这个问题吗:stackoverflow.com/questions/31512310/…。非常感谢。 :-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-23
    • 1970-01-01
    • 2019-09-07
    • 2013-07-29
    相关资源
    最近更新 更多