6
votes

Trying to use Spring 4 WebSocket with STOMP over socket using sockjs. And i faced a problem.

My configuration:

websocket.xml - part of spring context

<websocket:message-broker application-destination-prefix="/app">  
    <websocket:stomp-endpoint path="/ws">                         
        <websocket:sockjs/>                                       
    </websocket:stomp-endpoint>                                   
    <websocket:simple-broker prefix="/topic"/>                    
</websocket:message-broker>       

Controller code:

@MessageMapping("/ws")
@SendTo("/topic/ws")
public AjaxResponse hello() throws Exception {
    AjaxResponse ajaxResponse = new AjaxResponse();
    ajaxResponse.setSuccess(true);
    ajaxResponse.addSuccessMessage("WEB SOCKET!!! HELL YEAH!");
    return ajaxResponse;
}

Client side:

var socket = new SockJS("<c:url value='/ws'/>");               
var stompClient = Stomp.over(socket);                             
stompClient.connect({}, function(frame) {                         
    alert('Connected: ' + frame);                                 
    stompClient.send("/app/ws", {}, {});                       
    stompClient.subscribe('/topic/ws', function(response){ 
        alert(response.success);                                  
    });                                                           
});                                                               

Output:

Opening Web Socket... stomp.js:130
GET http://localhost:8080/ws/info 404 (Not Found) sockjs-0.3.js:807
Whoops! Lost connection to undefined stomp.js:130

What i do wrong?

I've found examples in google (TickerStocks or something like that, greeting applications (example of Spring)) and all of them give me the same error. I trying use WebSocket with handshake (without sockjs) - same result).

ADDITION INFORMATION:

Method public AjaxResponse hello(); placed in IndexController on root context "/". So i can provide full path: http://localhost:8080/ws. To deploy tested tomcat7 and tomcat8.

4
Not really relevant but I would strongly suggest you abandon the use of XML based config files and adopt JavaConfig globally rather than mixing and matching. There is a complete tutorial on setting this up using JavaConfig and sockjs. More significantly, how is your app deployed? It is at the root of the webserver? because your URL in the Javascript is absolute.Boris the Spider
May i completely remove ALL xml config from my application? It wont decrease speed of my application? I can remove all XML and create one WebConfig for the whole application? This complete tutorial it is greeting app (example by Spring) which i mention in question, that i tried it.dikkini
Yes, you do not need any xml at all. It will definitely not slow down the application - it may even speed it up as your XML doesn't need to be "compiled" into configuration code. You just need to make sure to bootstrap your application with the root configuration class.Boris the Spider
Boris the Spider, write an answer about remove ALL xml (include web.xml - make WebInitializer instead) i will mark it as answer. After this, i write code with websocket, sockjs and stomp - and everything working.dikkini

4 Answers

3
votes

I follow Boris The Spider advice and i started use Java Configuration (AppConfig and WebInit files) instead of XML configuration files. When i finished migration - i tried websockets - and it is works! I thought that the main problem was in XML configuration for WebSocket.

0
votes

I think your issue can be the same of this one and its accepted answer can apply.

In short: check how you mapped your DispatcherServlet. For your endpoint URL to be http://localhost:8080/ws the DispatcherServlet and your application contexte root should be set as "/".

It should be something like this, in your web.xml:

<servlet>
  <servlet-name>WebSocketDispatcher</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
  <async-supported>true</async-supported>
</servlet>
<servlet-mapping>
  <servlet-name>WebSocketDispatcher</servlet-name>
  <url-pattern>/*</url-pattern>
</servlet-mapping>

This or you need to include context-root and dispatcher mapping in your end-point URL:

http://<server>:<port>/<context-root>/<dispatcher-mapping>/ws

I hope it can help you.

Regards.

Heleno

0
votes

firstly, you have set destination prefix with app, so you must add 'app' into your request url. e.g. if i wanted to request for '/ws', i should create SockJS with path '/server/app/ws', also you can code with var socket = new SockJS("<c:url value='/server/app/ws'/>") and you know the 'server' is your project name over springmvc.

secondly, you must add the path '/app/*' to org.springframework.web.servlet.DispatcherServlet so as to avoid the path with prefix '/app' intercepted by interceptor defined in web.xml.

0
votes

I arrived on this page and - thanks to Boris Accepted Answer was motivated to reconsider the java approach as opposed to the xml approach which was causing the - /info=34424 with 404 error...whoops lost connection - I have Spring 4.2 in my project and many SockJS Stomp implementations usually work well with Spring Boot implementations. This implementation from Baeldung worked(for me without changing from Spring 4.2 to 5 or Boot). After Using the dependencies mentioned in his blog, it still gave me ClassNotFoundError. I added the below dependency to fix it.

<dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.2.3.RELEASE</version>
    </dependency>

Baeldung's implementation curiously does not make any such calls

flow/websocket/add/info?t=1540813753999

What it does (on send and receive) is below. I am only pasting it in case people well-versed with these libraries can further add insights on this forum.

 >>> SEND
destination:/app/chat
content-length:38

{"from":"nicholas","text":"try again"}

<<< MESSAGE
destination:/topic/messages
content-type:application/json;charset=UTF-8
subscription:sub-0
message-id:m3p096zk-11
content-length:53

{"from":"nicholas","text":"try again","time":"13:46"}