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

时间:2017-11-29 11:01:49

标签: spring-mvc websocket stomp spring-websocket sockjs

这可能是重复的:
Websocket - InvalidStateError: The connection has not been established yet

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

我的代码段如下。

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

控制台标签 enter image description here

网络标签

enter image description here

1 个答案:

答案 0 :(得分:2)

原始发布到this question

这是因为stompClient.connect()方法是异步的。在建立连接之前,我不会暂停执行。在getNotifications()之后立即呼叫alert()时,很可能还没有建立连接(如果alert()需要足够的时间来连接,则可能会建立连接)。

您应该在getNotifications()回调中调用stompClient.connect()(就像使用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 );
});