I'm currently using Websockets in a Spring-MVC webapp to send notifications to spring-security-authenticated users at any time. The point is to notify users without any page refresh or user interaction (like Facebook does for example).
Therefore, I'm using Spring's SimpMessagingTemplate
It looks (as seen in the browser console) like the client subscribes correctly, and that the SimpMessagingTemplate
actually sends a message (debugging the Spring code shows a happy flow happening, sent == true
etc). However, nothing happens at client-side - which is the issue.
After hours of re-reading the reference, other Stackoverflow posts etc (which do the same thing as here.. But seem to work !), I can't find an appropriate solution. The only difference is that I have a duplicated websocket configuration, which might be the cause of my troubles, but that I cannot get rid of (more on that hereunder : see dispatcher-servlet.xml
and applicationContext.xml
).
Client-side, I subscribe like this :
<script>
var socket = new SockJS('/stomp');
var client = Stomp.over(socket);
client.connect({}, function(s) {
client.subscribe('/user/queue/notify', function (msg) {
alert('SHOULD SEE THIS.. BUT DOES NOT WORK');
console.log("SHOULD SEE THIS.. BUT DOES NOT WORK");
});
});
</script>
I have a controller that sends a simple message to user "niilzon" every 10 seconds (this is just a simple test ofcourse)
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Controller;
@Controller
public class WebsocketTestController {
@Autowired
private SimpMessagingTemplate messagingTemplate;
@Scheduled(fixedDelay = 10000)
public void sendStuff() {
messagingTemplate.convertAndSendToUser("niilzon", "/queue/notify", "SEEING THIS WOULD BE GREAT");
}
}
Browser console, after the "niilzon" user logged in :
<<< CONNECTED
version:1.1
heart-beat:0,0
user-name:niilzon
connected to server undefined
>>> SUBSCRIBE
id:sub-0
destination:/user/queue/notify
And here is the XML configuration :
dispatcher-servlet.xml :
<!-- TODO this is duplicated in applicationContext !
If removing the websocket tag in dispatcher-servlet : 404 when client tries to connect to /stomp
If removing the websocket tag in applicationContext : cannot autowire SimpMessagingTemplate in WebsocketTestController
-->
<websocket:message-broker>
<websocket:stomp-endpoint path="/stomp">
<websocket:sockjs/>
</websocket:stomp-endpoint>
<websocket:simple-broker prefix="/topic,/queue"/>
</websocket:message-broker>
applicationContext.xml :
<websocket:message-broker>
<websocket:stomp-endpoint path="/stomp">
<websocket:sockjs/>
</websocket:stomp-endpoint>
<websocket:simple-broker prefix="/topic,/queue"/>
</websocket:message-broker>
As described in dispatcher-servlet.xml
, the websocket configuration is duplicated in applicationContext.xml
.
If I remove the tag in dispatcher-servlet.xml
, the client gets a 404 when trying to connect.
If I remove the tag in applicationContext.xml
, the SimpMessagingTemplate
cannot be autowired in WebsocketTestController
.
Could the configuration duplication be part of the issue ? That's the only lead I have left, but I am unable to fix it. An important thing to note is that some other config tags are duplicated between the 2 xml files. Here are ALL the duplications between the 2 config files, put next to each other (+ the websocket config as seen above) :
<import resource="spring-security.xml"/>
<context:component-scan base-package="com.beatboxnow.**"/>
<tx:annotation-driven />
<!-- TODO merge / inherit contexts instead of this dupe ? How ? same with tx:annotationDriven -->
<cache:annotation-driven />
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="ehcache"/>
</bean>
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache.xml"/>
<property name="shared" value="true"/>
</bean>
There are no issues with the rest of the webapp, which has alot of views, controllers, services, repositories etc.
Any help would be greatly appreciated !
Thanks to this StackOverflow post here Loading both mvc-dispatcher-servlet.xml and applicationContext.xml?, I managed to merge the duplicates in the dispatcher-servlet
and applicationContext
XML's.
The trick was simply to import the applicationContext
in the dispatcher-servlet
like this :
<import resource="applicationContext.xml" />
, and to remove all the duplicates (not touching any tag in applicationContext.xml
obviously).
I had this partial configuration duplication issue hanging since the beginning of this project and planned to remove it later on - tried the import at that time but I did not manage to do it back then. Now this Websocket issue forced me to try it again (duplicating was not blocking before), and surprisingly it worked perfectly, I suppose that I made a silly mistake during the first try, since it was in fact rather trivial :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With