首页 > 解决方案 > 奇怪的行为 - websocket spring - 使用监听/通知 postgresql 向用户发送消息

问题描述

我的 spring boot websocket 设置出现了奇怪的行为。有时有效,有时无效,只是感觉很随意。我已经尝试了几种设置,但没有一个被证明是可靠的:我将最后一段代码移动到应用程序主类中的命令行运行程序中,最后一个选择是带有 @Component 注释的不同类。

我的设置如下:我使用 jdbc 驱动程序 (pgjdbc-ng) 来使用 postgres 的监听通知功能。我有一个函数和一个触发器来监听特定的 postgres 表以进行插入。如果发生任何情况,通知将通过 websocket 发送。另一个是一个角度应用程序,它使用 ng2-stompjs 来收听 /topic/notificari 的通知。我没有发布代码,因为通知没有脱离春天,角度不是问题。

亲切的问候,

这是我的 WebSocketConfiguration

Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
    registry.enableSimpleBroker("/topic", "/queue", "/user", "/notificari");
    registry.setApplicationDestinationPrefixes("/app");
    registry.setUserDestinationPrefix("/user");
}

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
    registry.addEndpoint("/socket").setAllowedOrigins("*")
            .setHandshakeHandler(new CustomHandshakeHandler());
}

我正在使用类 ListenNotify 和 JDBC 驱动程序 pgjdbc-ng 连接到 postgresql 数据库并使用监听通知功能

public class ListenNotify {

private BlockingQueue queue = new ArrayBlockingQueue(20);

PGConnection connection;

public ListenNotify() {


    PGNotificationListener listener = new PGNotificationListener() {
        @Override
        public void notification(int processId, String channelName, String payload) {
            queue.add(payload);
        }
    };

    try {
        PGDataSource dataSource = new PGDataSource();
        dataSource.setHost("localhost");
        dataSource.setDatabase("db");
        dataSource.setPort(5432);
        dataSource.setUser("user");
        dataSource.setPassword("pass");
        connection = (PGConnection) dataSource.getConnection();

        connection.addNotificationListener(listener);

        Statement statement = connection.createStatement();
        statement.execute("LISTEN n_event");
        statement.close();
    } catch (SQLException e) {
        e.printStackTrace();
        }
}

public BlockingQueue getQueue() {
    return queue;
}

}

最后,这是实例化 ListenNotify 对象并侦听 postgres 中可能触发必须使用 websocket 发送的通知的事件的代码。

@Component
public class InstantaNotificari {

@Autowired
SimpMessagingTemplate template;

@EventListener(ApplicationReadyEvent.class)
public void runn() {
    System.out.println("invocare met");
    ListenNotify ln = new ListenNotify();

    BlockingQueue queue = ln.getQueue();

    System.out.println("the que ies "+ queue);

    while (true) {
        try {
            String msg = (String) queue.take();
            System.out.println("msg " + msg);
            template.convertAndSend("/topic/notificari", msg);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

}

标签: springpostgresqlspring-bootwebsocket

解决方案


我没有使用 Spring,所以我无法测试您的代码。这是我测试过的版本。我认为这总结了差异 -

  1. 更改为尝试使用资源块。这将在销毁类时关闭连接。
  2. 将您的 while(true) 移动到侦听器上的 try 块中,以便 try 块内的行永远不会超出执行范围。
  3. while(true) 是阻塞的,所以它需要在另一个线程上。ListenNotify extends Thread

我确信还有其他实施方式,欢迎对我的任何假设进行更正。

我测试过的运行代码在这个答案JMS Websocket 延迟交付中。


推荐阅读