spring-guides / gs-messaging-stomp-websocket

Using WebSocket to build an interactive web application :: Learn how to the send and receive messages between a browser and the server over a WebSocket
http://spring.io/guides/gs/messaging-stomp-websocket/
Apache License 2.0
530 stars 474 forks source link

:spring_version: current :jackson: https://github.com/FasterXML/jackson :AtMessageMapping: https://docs.spring.io/spring/docs/{spring_version}/javadoc-api/org/springframework/messaging/handler/annotation/MessageMapping.html :AtController: https://docs.spring.io/spring/docs/{spring_version}/javadoc-api/org/springframework/stereotype/Controller.html :AtEnableWebSocketMessageBroker: https://docs.spring.io/spring/docs/{spring_version}/javadoc-api/org/springframework/messaging/simp/config/EnableWebSocketMessageBroker.html :Stomp_JS: http://jmesnil.net/stomp-websocket/doc/ :AtSendTo: https://docs.spring.io/spring/docs/{spring_version}/javadoc-api/org/springframework/messaging/handler/annotation/SendTo.html :toc: :icons: font :source-highlighter: prettify :project_id: gs-messaging-stomp-websocket

This guide walks you through the process of creating a "Hello, world" application that sends messages back and forth between a browser and a server. WebSocket is a thin, lightweight layer above TCP. This makes it suitable for using "subprotocols" to embed messages. In this guide, we use http://en.wikipedia.org/wiki/Streaming_Text_Oriented_Messaging_Protocol[STOMP] messaging with Spring to create an interactive web application. STOMP is a subprotocol operating on top of the lower-level WebSocket.

== What You Will Build

You will build a server that accepts a message that carries a user's name. In response, the server will push a greeting into a queue to which the client is subscribed.

== What You Need

include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/main/prereq_editor_jdk_buildtools.adoc[]

include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/main/how_to_complete_this_guide.adoc[]

[[scratch]] == Starting with Spring Initializr

You can use this https://start.spring.io/#!type=maven-project&groupId=com.example&artifactId=messaging-stomp-websocket&name=messaging-stomp-websocket&description=Demo%20project%20for%20Spring%20Boot&packageName=com.example.messaging-stomp-websocket&dependencies=websocket[pre-initialized project] and click Generate to download a ZIP file. This project is configured to fit the examples in this tutorial.

To manually initialize the project:

. Navigate to https://start.spring.io. This service pulls in all the dependencies you need for an application and does most of the setup for you. . Choose either Gradle or Maven and the language you want to use. This guide assumes that you chose Java. . Click Dependencies and select Websocket. . Click Generate. . Download the resulting ZIP file, which is an archive of a web application that is configured with your choices.

NOTE: If your IDE has the Spring Initializr integration, you can complete this process from your IDE.

NOTE: You can also fork the project from Github and open it in your IDE or other editor.

[[initial]] == Create a Resource Representation Class

Now that you have set up the project and build system, you can create your STOMP message service.

Begin the process by thinking about service interactions.

The service will accept messages that contain a name in a STOMP message whose body is a JSON object. If the name is Fred, the message might resemble the following:

==== [source,json]

{ "name": "Fred" }

====

To model the message that carries the name, you can create a plain old Java object with a name property and a corresponding getName() method, as the following listing (from src/main/java/com/example/messagingstompwebsocket/HelloMessage.java) shows:

==== [source,java,tabsize=2]

include::complete/src/main/java/com/example/messagingstompwebsocket/HelloMessage.java[]

====

Upon receiving the message and extracting the name, the service will process it by creating a greeting and publishing that greeting on a separate queue to which the client is subscribed. The greeting will also be a JSON object, which as the following listing shows:

==== [source,json]

{ "content": "Hello, Fred!" }

====

To model the greeting representation, add another plain old Java object with a content property and a corresponding getContent() method, as the following listing (from src/main/java/com/example/messagingstompwebsocket/Greeting.java) shows:

==== [source,java,tabsize=2]

include::complete/src/main/java/com/example/messagingstompwebsocket/Greeting.java[]

====

Spring will use the {jackson}[Jackson JSON] library to automatically marshal instances of type Greeting into JSON.

Next, you will create a controller to receive the hello message and send a greeting message.

== Create a Message-handling Controller

In Spring's approach to working with STOMP messaging, STOMP messages can be routed to {AtController}[@Controller] classes. For example, the GreetingController (from src/main/java/com/example/messagingstompwebsocket/GreetingController.java) is mapped to handle messages to the /hello destination, as the following listing shows:

==== [source,java,tabsize=2]

include::complete/src/main/java/com/example/messagingstompwebsocket/GreetingController.java[]

====

This controller is concise and simple, but plenty is going on. We break it down step by step.

The {AtMessageMapping}[@MessageMapping] annotation ensures that, if a message is sent to the /hello destination, the greeting() method is called.

The payload of the message is bound to a HelloMessage object, which is passed into greeting().

Internally, the implementation of the method simulates a processing delay by causing the thread to sleep for one second. This is to demonstrate that, after the client sends a message, the server can take as long as it needs to asynchronously process the message. The client can continue with whatever work it needs to do without waiting for the response.

After the one-second delay, the greeting() method creates a Greeting object and returns it. The return value is broadcast to all subscribers of /topic/greetings, as specified in the {AtSendTo}[@SendTo] annotation. Note that the name from the input message is sanitized, since, in this case, it will be echoed back and re-rendered in the browser DOM on the client side.

== Configure Spring for STOMP messaging

Now that the essential components of the service are created, you can configure Spring to enable WebSocket and STOMP messaging.

Create a Java class named WebSocketConfig that resembles the following listing (from src/main/java/com/example/messagingstompwebsocket/WebSocketConfig.java):

==== [source,java,tabsize=2]

include::complete/src/main/java/com/example/messagingstompwebsocket/WebSocketConfig.java[]

====

WebSocketConfig is annotated with @Configuration to indicate that it is a Spring configuration class. It is also annotated with {AtEnableWebSocketMessageBroker}[@EnableWebSocketMessageBroker]. As its name suggests, @EnableWebSocketMessageBroker enables WebSocket message handling, backed by a message broker.

The configureMessageBroker() method implements the default method in WebSocketMessageBrokerConfigurer to configure the message broker. It starts by calling enableSimpleBroker() to enable a simple memory-based message broker to carry the greeting messages back to the client on destinations prefixed with /topic. It also designates the /app prefix for messages that are bound for methods annotated with @MessageMapping. This prefix will be used to define all the message mappings. For example, /app/hello is the endpoint that the GreetingController.greeting() method is mapped to handle.

The registerStompEndpoints() method registers the /gs-guide-websocket endpoint for websocket connections.

== Create a Browser Client

With the server-side pieces in place, you can turn your attention to the JavaScript client that will send messages to and receive messages from the server side.

Create an index.html file similar to the following listing (from src/main/resources/static/index.html):

==== [source,html]

include::complete/src/main/resources/static/index.html[]

====

This HTML file imports the https://stomp-js.github.io/[`StompJS] javascript library that will be used to communicate with our server through STOMP over websocket. We also importapp.js, which contains the logic of our client application. The following listing (from src/main/resources/static/app.js`) shows that file:

==== [source,javascript,tabsize=2]

include::complete/src/main/resources/static/app.js[]

====

The main pieces of this JavaScript file to understand are the stompClient.onConnect and sendName functions.

stompClient is initialized with brokerURL referring to path /gs-guide-websocket, which is where our websockets server waits for connections. Upon a successful connection, the client subscribes to the /topic/greetings destination, where the server will publish greeting messages. When a greeting is received on that destination, it will append a paragraph element to the DOM to display the greeting message.

The sendName() function retrieves the name entered by the user and uses the STOMP client to send it to the /app/hello destination (where GreetingController.greeting() will receive it).

The main.css can be omitted if you like, or you can create an empty one, just so the <link> can be resolved.

== Make the Application Executable

Spring Boot creates an application class for you. In this case, it needs no further modification. You can use it to run this application. The following listing (from src/main/java/com/example/messagingstompwebsocket/MessagingStompWebsocketApplication.java) shows the application class:

==== [source,java,tabsize=2]

include::complete/src/main/java/com/example/messagingstompwebsocket/MessagingStompWebsocketApplication.java[]

====

include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/main/spring-boot-application-new-path.adoc[]

include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/main/build_an_executable_jar_subhead.adoc[]

include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/main/build_an_executable_jar_with_both.adoc[]

Logging output is displayed. The service should be up and running within a few seconds.

== Test the service

Now that the service is running, point your browser at http://localhost:8080 and click the Connect button.

Upon opening a connection, you are asked for your name. Enter your name and click Send. Your name is sent to the server as a JSON message over STOMP. After a one-second simulated delay, the server sends a message back with a "Hello" greeting that is displayed on the page. At this point, you can send another name or you can click the Disconnect button to close the connection.

== Summary

Congratulations! You have just developed a STOMP-based messaging service with Spring.

== See Also

The following guides may also be helpful:

include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/main/footer.adoc[]