123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345 |
- :spring_version: current
- :spring_boot_version: 2.3.2.RELEASE
- :jackson: https://wiki.fasterxml.com/JacksonHome
- :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.
- == 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
- :java_version: 1.8
- include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/master/prereq_editor_jdk_buildtools.adoc[]
- include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/master/how_to_complete_this_guide.adoc[]
- [[scratch]]
- == Starting with Spring Initializr
- For all Spring applications, you should start with the https://start.spring.io[Spring
- Initializr]. The Initializr offers a fast way to pull in all the dependencies you need for
- an application and does a lot of the set up for you. This example needs only the Websocket
- dependency.
- The following listing shows the `pom.xml` file that is created when you choose Maven:
- ====
- [src,xml]
- ----
- include::initial/pom.xml[]
- ----
- ====
- The following listing shows the `build.gradle` file that is created when you choose Gradle:
- ====
- [src,java]
- ----
- include::initial/build.gradle[]
- ----
- ====
- == Adding Dependencies
- The Spring Initializr does not provide everything you need in this case. For Maven, you
- need to add the following dependencies:
- ====
- [source,xml]
- ----
- <dependency>
- <groupId>org.webjars</groupId>
- <artifactId>webjars-locator-core</artifactId>
- </dependency>
- <dependency>
- <groupId>org.webjars</groupId>
- <artifactId>sockjs-client</artifactId>
- <version>1.0.2</version>
- </dependency>
- <dependency>
- <groupId>org.webjars</groupId>
- <artifactId>stomp-websocket</artifactId>
- <version>2.3.3</version>
- </dependency>
- <dependency>
- <groupId>org.webjars</groupId>
- <artifactId>bootstrap</artifactId>
- <version>3.3.7</version>
- </dependency>
- <dependency>
- <groupId>org.webjars</groupId>
- <artifactId>jquery</artifactId>
- <version>3.1.1-1</version>
- </dependency>
- ----
- ====
- The following listing shows the finished `pom.xml` file:
- ====
- [src,xml]
- ----
- include::complete/pom.xml[]
- ----
- ====
- If you use Gradle, you need to add the following dependencies:
- ====
- [source,java]
- ----
- implementation 'org.webjars:webjars-locator-core'
- implementation 'org.webjars:sockjs-client:1.0.2'
- implementation 'org.webjars:stomp-websocket:2.3.3'
- implementation 'org.webjars:bootstrap:3.3.7'
- implementation 'org.webjars:jquery:3.1.1-1'
- ----
- ====
- The following listing shows the finished `build.gradle` file:
- ====
- [src,java]
- ----
- include::complete/build.gradle[]
- ----
- ====
- [[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,
- enabling SockJS fallback options so that alternate transports can be used if WebSocket is
- not available. The SockJS client will attempt to connect to `/gs-guide-websocket` and use
- the best available transport (websocket, xhr-streaming, xhr-polling, and so on).
- == 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 `SockJS` and `STOMP` javascript libraries that will be used to
- communicate with our server through STOMP over websocket. We also import `app.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 `connect()` and `sendName()`
- functions.
- The `connect()` function uses https://github.com/sockjs[SockJS] and {Stomp_JS}[stomp.js]
- to open a connection to `/gs-guide-websocket`, which is where our SockJS 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/master/spring-boot-application-new-path.adoc[]
- include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/master/build_an_executable_jar_subhead.adoc[]
- include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/master/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:
- * https://spring.io/guides/gs/serving-web-content/[Serving Web Content with Spring MVC]
- * https://spring.io/guides/gs/spring-boot/[Building an Application with Spring Boot]
- include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/master/footer.adoc[]
|