1

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

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

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

贝叶初始化器:

@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);
    }
}

请让我知道这种方法是否可行。非常感谢。

4

1 回答 1

2

@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 身份验证的文档。

于 2015-05-20T09:31:25.037 回答