如何在 Spring MVC 中正确配置 Stomp 和 SockJS 端点?

How to properly configure Stomp and SockJS endpoint in Spring MVC?

此 is/may 与以下项重复:

我正在实施通知系统。并希望在用户登录时初始化套接字连接,并向他显示他的通知,以及是否发生某些事件。

我的代码片段如下。

websocket.js :

var stompClient = null;
function connect( temp ) {
    alert(temp);
    //var socket = new SockJS("/websock");
    //var socket = new SockJS("/websock"+temp);
    var socket = new SockJS(context_path+"/websock"+temp);
    //context_path == "/SupportCenter"
    stompClient = Stomp.over(socket);
    stompClient.connect({}, function( frame ){
        console.log( "Connected :- "+frame );
        stompClient.subscribe("/topic/notifications", function( notifications ) {
            alert( notifications );
        });
    }, function( error ) {
        alert( error );
    });
    alert();
    getNotifications();
}

function getNotifications() {
    stompClient.send("/app/hello", {}, "Hiiiiii");
}

WebSocketConfig.java :

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    /* (non-Javadoc)
     * @see org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer#registerStompEndpoints(org.springframework.web.socket.config.annotation.StompEndpointRegistry)
     */
    @Override
    public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
        stompEndpointRegistry.addEndpoint("/websock").withSockJS();
    }
    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        // TODO Auto-generated method stub
        config.enableSimpleBroker("/topic");
        config.setApplicationDestinationPrefixes("/app");
    }
}

WebSocketController.java :

@Controller
public class WebSocketController {

    @MessageMapping(value="/hello")
    @SendTo("/topic/notifications")
    public Notify hello() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        Notify notify = new Notify();
        notify.setMessage("Hello World !!!");
        return notify;
    }
}

一些代码 Hom.jsp :

<script type="text/javascript" src="<c:url value="/resources/js/sockjs.min.js"/>"></script>
<script type="text/javascript" src="<c:url value="/resources/js/stomp.min.js"/>"></script>
<script type="text/javascript" src="<c:url value="/resources/js/websocket.js"/>"></script>


<script type="text/javascript">
$(document).ready(function() {
    //...

    connect( '${nsec}');
});

为什么 Firefox 控制台 网络选项卡 中给出 XML Parsing Error: no root element found Location: 状态代码是 200 OK

控制台选项卡

网络选项卡

最初发布到 this question

这是因为stompClient.connect()方法是异步的。我不会暂停执行,直到建立连接。当您在 alert() 之后立即调用 getNotifications() 时,很可能尚未建立连接(如果 alert() 需要足够的时间进行连接,则可能会建立连接)。

您应该在 stompClient.connect() 回调中调用 getNotifications()(就像您对 stompClient.subscribe() 所做的那样)以确保在它被调用时建立连接。

例如:

stompClient.connect({}, function( frame ){
    console.log( "Connected :- "+frame );
    stompClient.subscribe("/topic/notifications", function( notifications ) {
        alert( notifications );
    });
    getNotifications();
}, function( error ) {
    alert( error );
});

除此之外,您可以考虑在 java 代码中使用 @SubscribeMapping 注释来摆脱来自 JavaScript 的显式消息,从而从服务器获取初始消息。这样,服务器会在订阅建立后立即发送初始消息。

例如:

@MessageMapping(value="/hello")
@SubscribeMapping("/notifications")
@SendTo("/topic/notifications")
public Notify hello() {
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    Notify notify = new Notify();
    notify.setMessage("Hello World !!!");
    return notify;
}

然后客户端代码如下所示:

stompClient.connect({}, function( frame ){
    console.log( "Connected :- "+frame );
    stompClient.subscribe("/topic/notifications", function( notifications ) {
        alert( notifications );
    });
}, function( error ) {
    alert( error );
});