Spring-MVC, Cometd: вещание без @Listener
Я работаю над приложением 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);
}
}
Пожалуйста, дайте мне знать, если этот подход в порядке. Большое спасибо.
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.