Selaa lähdekoodia

Switch to stomp-js library

As stomp-websocket library is not maintained anymore and
as modern browser and proxies now have much better support
for WebSocket, this commit updates the guide to use stomp-js,
and disable the SockJS by default.

See https://stomp-js.github.io/guide/stompjs/rx-stomp/using-stomp-with-sockjs.html
for more details.

This commit also updates the project to use JS files available
on CDNs instead of using WebJar.

Closes gh-77
Márcio Paixão Dantas 2 vuotta sitten
vanhempi
commit
761d8c42fc

+ 7 - 74
README.adoc

@@ -47,72 +47,7 @@ NOTE: If your IDE has the Spring Initializr integration, you can complete this p
 
 NOTE: You can also fork the project from Github and open it in your IDE or other editor.
 
-== 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
 
@@ -240,10 +175,7 @@ designates the `/app` prefix for messages that are bound for methods annotated w
 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).
+The `registerStompEndpoints()` method registers the `/gs-guide-websocket` endpoint for websocket connections.
 
 == Create a Browser Client
 
@@ -260,7 +192,7 @@ include::complete/src/main/resources/static/index.html[]
 ----
 ====
 
-This HTML file imports the `SockJS` and `STOMP` javascript libraries that will be used to
+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 import `app.js`, which
 contains the logic of our client application. The following listing (from
 `src/main/resources/static/app.js`) shows that file:
@@ -272,11 +204,11 @@ include::complete/src/main/resources/static/app.js[]
 ----
 ====
 
-The main pieces of this JavaScript file to understand are the `connect()` and `sendName()`
+The main pieces of this JavaScript file to understand are the `stompClient.onConnect` 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
+`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
@@ -330,6 +262,7 @@ Congratulations! You have just developed a STOMP-based messaging service with Sp
 
 The following guides may also be helpful:
 
+* https://stomp-js.github.io/[StompJS client library docs]
 * 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]
 

+ 0 - 5
complete/build.gradle

@@ -14,11 +14,6 @@ repositories {
 
 dependencies {
 	implementation 'org.springframework.boot:spring-boot-starter-websocket'
-	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'
 	testImplementation 'org.springframework.boot:spring-boot-starter-test'
 }
 

+ 0 - 25
complete/pom.xml

@@ -21,31 +21,6 @@
 			<groupId>org.springframework.boot</groupId>
 			<artifactId>spring-boot-starter-websocket</artifactId>
 		</dependency>
-		<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>
-
 		<dependency>
 			<groupId>org.springframework.boot</groupId>
 			<artifactId>spring-boot-starter-test</artifactId>

+ 1 - 1
complete/src/main/java/com/example/messagingstompwebsocket/WebSocketConfig.java

@@ -18,7 +18,7 @@ public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
 
 	@Override
 	public void registerStompEndpoints(StompEndpointRegistry registry) {
-		registry.addEndpoint("/gs-guide-websocket").withSockJS();
+		registry.addEndpoint("/gs-guide-websocket");
 	}
 
 }

+ 30 - 20
complete/src/main/resources/static/app.js

@@ -1,4 +1,23 @@
-var stompClient = null;
+const stompClient = new StompJs.Client({
+    brokerURL: 'ws://localhost:8080/gs-guide-websocket'
+});
+
+stompClient.onConnect = (frame) => {
+    setConnected(true);
+    console.log('Connected: ' + frame);
+    stompClient.subscribe('/topic/greetings', (greeting) => {
+        showGreeting(JSON.parse(greeting.body).content);
+    });
+};
+
+stompClient.onWebSocketError = (error) => {
+    console.error('Error with websocket', error);
+};
+
+stompClient.onStompError = (frame) => {
+    console.error('Broker reported error: ' + frame.headers['message']);
+    console.error('Additional details: ' + frame.body);
+};
 
 function setConnected(connected) {
     $("#connect").prop("disabled", connected);
@@ -13,27 +32,20 @@ function setConnected(connected) {
 }
 
 function connect() {
-    var socket = new SockJS('/gs-guide-websocket');
-    stompClient = Stomp.over(socket);
-    stompClient.connect({}, function (frame) {
-        setConnected(true);
-        console.log('Connected: ' + frame);
-        stompClient.subscribe('/topic/greetings', function (greeting) {
-            showGreeting(JSON.parse(greeting.body).content);
-        });
-    });
+    stompClient.activate();
 }
 
 function disconnect() {
-    if (stompClient !== null) {
-        stompClient.disconnect();
-    }
+    stompClient.deactivate();
     setConnected(false);
     console.log("Disconnected");
 }
 
 function sendName() {
-    stompClient.send("/app/hello", {}, JSON.stringify({'name': $("#name").val()}));
+    stompClient.publish({
+        destination: "/app/hello",
+        body: JSON.stringify({'name': $("#name").val()})
+    });
 }
 
 function showGreeting(message) {
@@ -41,11 +53,9 @@ function showGreeting(message) {
 }
 
 $(function () {
-    $("form").on('submit', function (e) {
-        e.preventDefault();
-    });
-    $( "#connect" ).click(function() { connect(); });
-    $( "#disconnect" ).click(function() { disconnect(); });
-    $( "#send" ).click(function() { sendName(); });
+    $("form").on('submit', (e) => e.preventDefault());
+    $( "#connect" ).click(() => connect());
+    $( "#disconnect" ).click(() => disconnect());
+    $( "#send" ).click(() => sendName());
 });
 

+ 3 - 4
complete/src/main/resources/static/index.html

@@ -2,11 +2,10 @@
 <html>
 <head>
     <title>Hello WebSocket</title>
-    <link href="/webjars/bootstrap/css/bootstrap.min.css" rel="stylesheet">
+    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
     <link href="/main.css" rel="stylesheet">
-    <script src="/webjars/jquery/jquery.min.js"></script>
-    <script src="/webjars/sockjs-client/sockjs.min.js"></script>
-    <script src="/webjars/stomp-websocket/stomp.min.js"></script>
+    <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
+    <script src="https://cdn.jsdelivr.net/npm/@stomp/stompjs@7.0.0/bundles/stomp.umd.min.js"></script>
     <script src="/app.js"></script>
 </head>
 <body>

+ 5 - 14
complete/src/test/java/com/example/messagingstompwebsocket/GreetingIntegrationTests.java

@@ -3,8 +3,6 @@ package com.example.messagingstompwebsocket;
 import static org.junit.jupiter.api.Assertions.*;
 
 import java.lang.reflect.Type;
-import java.util.ArrayList;
-import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
@@ -21,11 +19,9 @@ import org.springframework.messaging.simp.stomp.StompSession;
 import org.springframework.messaging.simp.stomp.StompSessionHandler;
 import org.springframework.messaging.simp.stomp.StompSessionHandlerAdapter;
 import org.springframework.web.socket.WebSocketHttpHeaders;
+import org.springframework.web.socket.client.WebSocketClient;
 import org.springframework.web.socket.client.standard.StandardWebSocketClient;
 import org.springframework.web.socket.messaging.WebSocketStompClient;
-import org.springframework.web.socket.sockjs.client.SockJsClient;
-import org.springframework.web.socket.sockjs.client.Transport;
-import org.springframework.web.socket.sockjs.client.WebSocketTransport;
 import org.springframework.beans.factory.annotation.Value;
 
 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@@ -34,19 +30,14 @@ public class GreetingIntegrationTests {
 	@Value(value="${local.server.port}")
 	private int port;
 
-	private SockJsClient sockJsClient;
-
 	private WebSocketStompClient stompClient;
 
 	private final WebSocketHttpHeaders headers = new WebSocketHttpHeaders();
 
 	@BeforeEach
 	public void setup() {
-		List<Transport> transports = new ArrayList<>();
-		transports.add(new WebSocketTransport(new StandardWebSocketClient()));
-		this.sockJsClient = new SockJsClient(transports);
-
-		this.stompClient = new WebSocketStompClient(sockJsClient);
+		WebSocketClient webSocketClient = new StandardWebSocketClient();
+		this.stompClient = new WebSocketStompClient(webSocketClient);
 		this.stompClient.setMessageConverter(new MappingJackson2MessageConverter());
 	}
 
@@ -88,7 +79,7 @@ public class GreetingIntegrationTests {
 			}
 		};
 
-		this.stompClient.connect("ws://localhost:{port}/gs-guide-websocket", this.headers, handler, this.port);
+		this.stompClient.connectAsync("ws://localhost:{port}/gs-guide-websocket", this.headers, handler, this.port);
 
 		if (latch.await(3, TimeUnit.SECONDS)) {
 			if (failure.get() != null) {
@@ -101,7 +92,7 @@ public class GreetingIntegrationTests {
 
 	}
 
-	private class TestSessionHandler extends StompSessionHandlerAdapter {
+	private static class TestSessionHandler extends StompSessionHandlerAdapter {
 
 		private final AtomicReference<Throwable> failure;