For those who aren’t familiar, WebSockets are a long-lived, interactive, two-way channel between a client browser and end server that allows ongoing communication without polling. They’ve been around for a few years now ever since being proposed by RFC 6455 and pretty much all of the major browsers have gained support since then. Spring, the ever-popular Java MVC framework, gained built-in WebSocket support in version 4.0 and that support has since been incorporated into Spring Boot and Grails (Grails support is supplied by this helpful plugin). This article is a high level overview of some tinkering I did to familiarize myself with WebSockets while also learning about the relatively-recent shakeup of Grails as it advanced to 3.0.
Specifically, my use case was to examine ways to avoid manual server polling when sending data back and forth between a server and 1-n clients. For this I decided to use WebSockets managed by SockJS, a library that handles the nitty-gritty of establishing and maintaining those connections, and Stomp, a messaging protocol built for WebSockets. Being a developer with lots of Java experience, my initial reaction to this stack was “it’s JMS, but better”. Those who have worked with Java Message Service probably know what I’m referring to – JMS allows reliable, highly-customizable cross-system messaging but can be heavy, hard to configure, and definitely doesn’t have any graceful integration into the sort of web applications being developed these days. This stack supplies many of the same capabilities while being simpler, lighter-weight, and downright simple to integrate:
For this example I decided to setup a very simple test application. This application would generate (fake) stock quotes at a relatively high frequency, high enough that it would become burdensome to have clients poll often enough to keep up. On top of showcasing this poll-less approach I also wanted to look into the ability to allow clients to interact and decided to go for the tried-and-true chat room use case.
All the code for this example is available out on GitHub so I will just be highlighting the most important functional bits here. First up is the code that generates data for my faux stock ticker – this code runs in the background on the server pushing new quotes out to a Stomp topic that clients can subscribe to.
Next, we need some more server-side code to arbitrate chat messages – effectively, this code reflects any incoming messages out to all listeners.
Now that all the server code is in place, we create a basic webpage. The code below provides the ability for the user to subscribe and unsubscribe to stock quotes, send chat messages, and receive messages sent by other users.
Put it all together and launch as a Grails application and you get something like you see below. You can open any number of browser tabs and they will all receive the same stock quote data at the same time (provided they each subscribe) and they all can participate in a shared chat. The best part? No background AJAX requests barraging the server for the latest data.
Once you take out all the fluff, we were just able to put together a neat little app that handles some non-trivial interactions in just a few dozen lines of code. Of course, this is hardly a complex example of WebSockets or Grails but hopefully it has shown you a quick way to simplify a common use case using some neat tools. Take a look at the source out on GitHub, and happy coding!
One thought on “WebSockets in Grails 3.0”
Great post ,
Mike You could do a quick example of sending a message from the server to a specific client in chat
I’m glad you liked it. I’ve committed an update to the code out on GitHub that should give you a basic example of how this can work. Basically there’s now a /secure page you can login to as “user” or “user2” (password is “password”) which will determine whether you see messages the server is sending specifically to “user”.
Mike thanks for attention,
Your code helped a lot,
first class content.
do not hesitate to give feedback or raise issues if you see options for improvements reg. grails-spring-websocket. im sure theres a lot of room for that 🙂
and do you plan to keep that sample app up-to-date? if so, i would be glad to add it to some kind of “useful links” list in the grails-spring-websocket readme.
thanks, zyro
Thanks! I’m planning to add a few more features over the next couple weeks as an academic exercise (likely queue vs. topic and message-filtering examples) but wasn’t planning to turn it into an authoritative or exhaustive example. You’re welcome to link to it if you’d like, or you can copy the code to make an example project of your own.
super useful stuff – i’m going to use it right away 🙂 thx
hello, I’m inspired of your tutorial to use websockets in my grails project. At the views index.gsp, I replace section by g:form but this make the connection lost.
When I see the console, I get this error : The connection to ws://localhost:8080/stomp/414/h0jvmvej/websocket was interrupted while the page was loading. I need some help to continue in my project. Thank you. your tutorial is very useful.
Without seeing your code I don’t think I’ll be able to help you very much. If you’ve got it out in a public Git repo I’d be happy to pull it down and help you troubleshoot.
here are my codes (in the view):
Brainstorming
Send
so I want to replace “section” by “g:form url = [ ….]” and get recover the input in my controller.
I have this in the controller:
class BrainstormingController {
def index() { }
/**
* Accepts incoming chat messages sent by browsers and routes them
* to the ‘chat’ topic that all browser clients are subscribed to.
**/
@MessageMapping(“/brainstorming”)
@SendTo(“/topic/brainstorming”)
protected String brainstorming(String chatMsg) {
/**
* Use the awesome Groovy JsonBuilder to convert a dynamically-defined
* data structure to JSON.
**/
def builder = new JsonBuilder()
builder {
message(chatMsg)
timestamp(new Date().getTime())
}
builder.toString()
}
}
sorry: Here are the code in my view:
Brainstorming
Send
Apparently i can’t put my views code. So it the same that yours. juste an input field and a button to submit.
I updated the Git repo with an example of using a Grails form to submit a message to a controller that publishes it to a websocket topic. It can be accessed at “/formMessage” when running locally. Hopefully that helps!
Thanks you so much !
is there a possibility to reveal the chat when refrashing the page ? I mean to let appear the chat already made when we click on send button ?
The websockets themselves have no storage capability – they’re just a message broker. Using your Grails Form approach you would have to introduce your own persistence solution to store previously-sent messages either in a database server-side or client-side in something like LocalStorage. In my original example I used an AJAX listener instead of a Grails Form to prevent a page refresh when submitting messages to avoid this issue.
ok I understand better now. Thank you for your precision.
Is it possible to send to chat controller from the view index.gsp multiple value (or an array) by this call : client.send(“/app/chat”, {}, JSON.stringify($(“#chatMessage”).val()));
something like client.send(“/app/chat”, {}, JSON.stringify($(“#chatMessage”).val()), “other”); ?
Great post Mike !
Just a question, what can I do if a want to send a message to a specific user ?
Just to avoid the websocket’s broadcast.
thanks !
There’s already an example of that in the code, please reference the “Private Messages” section of the README.