GithubHelp home page GithubHelp logo

aspineon / spring-boot-websocket-client Goto Github PK

View Code? Open in Web Editor NEW

This project forked from nielsutrecht/spring-boot-websocket-client

0.0 1.0 0.0 20 KB

Demonstrates a Spring Boot Websocket + Stomp service with both a JavaScript and Java client

License: MIT License

Java 71.73% HTML 11.82% JavaScript 16.45%

spring-boot-websocket-client's Introduction

Spring Boot Websocket Example

In our current project we want to add a service that uses websockets to push messages to our mobile applications. While the documentation on Spring Websockets + STOMP is excellent when it comes to implementing a service that is consumed by a simple web application, the example on how to use the STOMP client doesn't really align very well with the short getting started guide. Since I hit a few snags in the implementation I'm creating this example so you don't have to.

Introduction

For the spike I'm working on now we want to have our mobile client communicate with our back end via websockets. On top of that we want to use the STOMP messaging protocol / broker since we are likely going to need a pub/sub mechanism anyway. The main difference from the Getting Started is that we don't need the SockJS compatibility layer since we control both the server and the client.

The service

Relative to the Getting Started there are a few key changes. First of all I prefer to use Lombok in my projects. You'll notice that the POJO's have generated getters and setters and the @Slf4j annotation creates a Logger for us.

Secondly I have removed the SockJS layer from the service. This is a really minor change in the endpoint configuration. Instead of this:

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
    registry.addEndpoint("/hello").withSockJS();
}

You do this:

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
    registry.addEndpoint("/hello");
}

I also added a TimeSender component that, unsurprisingly, broadcasts time updates every 5 seconds. It does this broadcast on the same '/topic/greeting' topic as the GreetingController responds on to keep the client simple. It's a Spring @Scheduled task so don't forget to enable task scheduling with @EnableScheduling in your configuration!

The rest of the service is more or less the same as the one in the Getting Started: Application is the main entry point, WebSocketConfig contains the configuration and GreetingController handled the receiving of the client's name and greeting them.

If you build the project using maven (mvn clean install) you can run the service standalone using java -jar target/spring-boot-websocket-1.0.jar. You can also run it from your IDE by simply running Application.

The JavaScript client

The only real change made on the JS client side was removing the SockJS compatibility layer. I removed the script tag loading the sockjs.js source and changed the bit where you create the client from this:

var socket = new SockJS('/gs-guide-websocket');
stompClient = Stomp.over(socket);

To this:

stompClient = Stomp.client('ws://localhost:8080/hello');

The Java client

The Java STOMP client was a bit less straightforward. It had me stumped (stomped?) for a while. Although I could connect to the service and send messages it would not allow me to receive any responses. Not just that; I wasn't getting any errors either. Why? Well what the documentation unfortunately does not make very clear is that the StompSessionHandlerAdapter you tend to extend has an empty implementation of handleException(). So whenever something goes wrong it just swallows the exception. That only took me like 2 hours to figure out :D. So the first order of business was to add 'proper' exception handling to MySessionHandler:

@Override
public void handleException(StompSession session, StompCommand command, StompHeaders headers, byte[] payload, Throwable exception) {
    exception.printStackTrace();
}

In my opinion this should be the default behavior. Note: you can't simply rethrow the exception here; it will disappear.

So now that we are actually seeing exceptions I found out I was doing something wrong:

org.springframework.messaging.converter.MessageConversionException: No suitable converter, payloadType=class com.nibado.example.websocket.service.Greeting, handlerType=class com.nibado.example.websocket.client.MySessionHandler
at org.springframework.messaging.simp.stomp.DefaultStompSession.invokeHandler(DefaultStompSession.java:443)

I went through different permutations of removing the StringMessageConverter, returning the Type of String inside session handler .getPayloadType(), etc. The problem was both a lack of understanding on my part and (again) unclear documentation. First of all; the STOMP 'frames' you receive will have a mime type. It's not really easy to spot (I found out by dumping all the headers to std out) but the service implementation, because we are returning Greeting objects from the controller, is using Jackson to serialize these objects to JSON. This will also result in those frames getting the application/json mimetype. The StringMessageConverter will only work on text/plain messages.

The second part that was confusing was the documentation. It claims that if Jackson is on the classpath it will use a Jackson message convertor. I don't know how it tries to figure this out but it didn't happen automatically, this is why I needed to add it myself:

stompClient.setMessageConverter(new MappingJackson2MessageConverter());

That got my basic client working: the ServiceClient configures the connection and adds a handler, MySessionHandler implements a handler that sends a message to the WS service and then subscribes to the 'topic/greeting' topic. It now will receive the same messages as the JS client does.

Conclusion

Although I do think the Spring documentation has some gaps here it was a fun journey of discovery! I hope this example is useful and save you some time. If you have any questions or feedback feel free to raise an issue in this repository!

spring-boot-websocket-client's People

Contributors

nielsutrecht avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.