Contents
- 1 Seems your browser doesn’t support Javascript! Websocket relies on Javascript being enabled. Please enable Javascript and reload this page!
- 2 Seems your browser doesn’t support Javascript! Websocket relies on Javascript being enabled. Please enable Javascript and reload this page!
- 3 Seems your browser doesn’t support Javascript! Websocket relies on Javascript being enabled. Please enable Javascript and reload this page!
- 4 Что вы будете строить
- 5 Что вам нужно
- 6 Как заполнить это руководство
- 7 Начиная с Spring Initializr
- 8 Добавление зависимостей
- 9 Seems your browser doesn't support Javascript! Websocket relies on Javascript being enabled. Please enable Javascript and reload this page!
- 10 Создайте класс представления ресурсов
- 11 Создайте контроллер обработки сообщений
- 12 Seems your browser doesn’t support Javascript! Websocket relies on Javascript being enabled. Please enable Javascript and reload this page!
- 13 Настройте Spring для обмена сообщениями STOMP
- 14 Seems your browser doesn’t support Javascript! Websocket relies on Javascript being enabled. Please enable Javascript and reload this page!
- 15 Создать браузерный клиент
- 16 Сделать приложение исполняемым
- 17 Протестируйте сервис
Seems your browser doesn’t support Javascript! Websocket relies on Javascript being
enabled. Please enable
Javascript and reload this page!
Seems your browser doesn’t support Javascript! Websocket relies on Javascript being
enabled. Please enable
Javascript and reload this page!
Seems your browser doesn’t support Javascript! Websocket relies on Javascript being
enabled. Please enable
Javascript and reload this page!
Это руководство проведет вас через процесс создания приложения «Hello, world», которое отправляет сообщения туда и обратно между браузером и сервером. WebSocket — это тонкий и легкий слой поверх TCP. Это делает его пригодным для использования «подпротоколов» для встраивания сообщений. В этом руководстве мы используем обмен сообщениями STOMP с Spring для создания интерактивного веб-приложения. STOMP — это подпротокол, работающий поверх WebSocket более низкого уровня.
Что вы будете строить
Вы создадите сервер, который принимает сообщение, содержащее имя пользователя. В ответ сервер поместит приветствие в очередь, на которую подписан клиент.
Что вам нужно
- Около 15 минут
- Любимый текстовый редактор или IDE
- JDK 1.8 или новее
- Gradle 4+ или Maven 3.2+
- Вы также можете импортировать код прямо в свою IDE:
Как заполнить это руководство
Как и в большинстве руководств Spring Getting Started , вы можете начать с нуля и выполнить каждый шаг или обойти уже знакомые вам основные этапы настройки. В любом случае вы получите рабочий код.
Чтобы начать с нуля , перейдите к разделу Starting with Spring Initializr .
Чтобы пропустить основы , сделайте следующее:
- Загрузите и разархивируйте исходный репозиторий для этого руководства или клонируйте его с помощью Git :
git clone
https://github.com/spring-guides/gs-messaging-stomp-websocket.git - компакт-диск в
gs-messaging-stomp-websocket/initial
- Перейдите к созданию класса представления ресурсов .
Когда вы закончите , вы можете сравнить свои результаты с кодом в gs-messaging-stomp-websocket/complete
.
Начиная с Spring Initializr
Вы можете использовать этот предварительно инициализированный проект и нажать «Создать», чтобы загрузить ZIP-файл. Этот проект настроен так, чтобы соответствовать примерам в этом руководстве.
Чтобы вручную инициализировать проект:
- Перейдите на https://start.spring.io . Этот сервис извлекает все зависимости, необходимые для приложения, и выполняет большую часть настройки за вас.
- Выберите Gradle или Maven и язык, который вы хотите использовать. В этом руководстве предполагается, что вы выбрали Java.
- Щелкните Зависимости и выберите Websocket .
- Нажмите «Создать» .
- Загрузите полученный ZIP-файл, представляющий собой архив веб-приложения, настроенного с учетом ваших предпочтений.
Если в вашей среде IDE есть интеграция с Spring Initializr, вы можете выполнить этот процесс в своей среде IDE. |
Вы также можете разветвить проект из Github и открыть его в своей среде IDE или другом редакторе. |
Добавление зависимостей
В этом случае Spring Initializr не предоставляет всего, что вам нужно. Для Maven нужно добавить следующие зависимости:
<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>
В следующем листинге показан готовый pom.xml
файл:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.1</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>messaging-stomp-websocket-complete</artifactId> <version>0.0.1-SNAPSHOT</version> <name>messaging-stomp-websocket-complete</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <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> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
Если вы используете Gradle, вам необходимо добавить следующие зависимости:
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'
В следующем листинге показан готовый build.gradle
файл:
plugins { id 'org.springframework.boot' version '2.7.1' id 'io.spring.dependency-management' version '1.0.11.RELEASE' id 'java' } group = 'com.example' version = '0.0.1-SNAPSHOT' sourceCompatibility = '1.8' repositories { mavenCentral() } 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' } test { useJUnitPlatform() }
Создайте класс представления ресурсов
Теперь, когда вы настроили проект и систему сборки, вы можете создать службу сообщений STOMP.
Начните процесс с размышлений о сервисных взаимодействиях.
Служба будет принимать сообщения, содержащие имя в сообщении STOMP, тело которого является объектом JSON. Если имя Fred
, сообщение может выглядеть следующим образом:
{
"name": "Fred"
}
Чтобы смоделировать сообщение, которое несет это имя, вы можете создать простой старый объект Java со name
свойством и соответствующим getName()
методом, как src/main/java/com/example/messagingstompwebsocket/HelloMessage.java
показано в следующем листинге (из ):
package com.example.messagingstompwebsocket;
public class HelloMessage {
private String name;
public HelloMessage() {
}
public HelloMessage(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
После получения сообщения и извлечения имени служба обработает его, создав приветствие и опубликовав это приветствие в отдельной очереди, на которую подписан клиент. Приветствие также будет объектом JSON, как показано в следующем листинге:
{
"content": "Hello, Fred!"
}
Чтобы смоделировать представление приветствия, добавьте еще один простой старый объект Java со content
свойством и соответствующим getContent()
методом, как src/main/java/com/example/messagingstompwebsocket/Greeting.java
показано в следующем листинге (из ):
package com.example.messagingstompwebsocket;
public class Greeting {
private String content;
public Greeting() {
}
public Greeting(String content) {
this.content = content;
}
public String getContent() {
return content;
}
}
Spring будет использовать библиотеку Jackson JSON для автоматического маршалинга экземпляров типа Greeting
в JSON.
Далее вы создадите контроллер для получения приветственного сообщения и отправки приветственного сообщения.
Создайте контроллер обработки сообщений
В подходе Spring к работе с обменом сообщениями STOMP сообщения STOMP могут направляться в @Controller
классы. Например, GreetingController
(from src/main/java/com/example/messagingstompwebsocket/GreetingController.java
) отображается для обработки сообщений /hello
адресату, как показано в следующем листинге:
package com.example.messagingstompwebsocket;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;
import org.springframework.web.util.HtmlUtils;
@Controller
public class GreetingController {
@MessageMapping("/hello")
@SendTo("/topic/greetings")
public Greeting greeting(HelloMessage message) throws Exception {
Thread.sleep(1000); // simulated delay
return new Greeting("Hello, " + HtmlUtils.htmlEscape(message.getName()) + "!");
}
}
Этот контроллер лаконичен и прост, но много чего происходит. Разбираем поэтапно.
Аннотация @MessageMapping
гарантирует, что при отправке сообщения /hello
получателю greeting()
вызывается метод.
Полезная нагрузка сообщения привязывается к HelloMessage
объекту, который передается в greeting()
.
Внутренне реализация метода имитирует задержку обработки, переводя поток в спящий режим на одну секунду. Это сделано для того, чтобы продемонстрировать, что после того, как клиент отправит сообщение, серверу может потребоваться столько времени, сколько потребуется для асинхронной обработки сообщения. Клиент может продолжать любую работу, которую ему необходимо выполнить, не дожидаясь ответа.
После задержки в одну секунду greeting()
метод создает Greeting
объект и возвращает его. Возвращаемое значение транслируется всем подписчикам /topic/greetings
, как указано в @SendTo
аннотации. Обратите внимание, что имя из входного сообщения очищается, так как в этом случае оно будет возвращено обратно и повторно отображено в DOM браузера на стороне клиента.
Seems your browser doesn’t support Javascript! Websocket relies on Javascript being
enabled. Please enable
Javascript and reload this page!
Настройте Spring для обмена сообщениями STOMP
Теперь, когда основные компоненты службы созданы, вы можете настроить Spring для включения обмена сообщениями WebSocket и STOMP.
Создайте класс Java с именем WebSocketConfig
, похожим на следующий листинг (из src/main/java/com/example/messagingstompwebsocket/WebSocketConfig.java
):
package com.example.messagingstompwebsocket;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/gs-guide-websocket").withSockJS();
}
}
WebSocketConfig
аннотируется @Configuration
, чтобы указать, что это класс конфигурации Spring. Он также снабжен аннотацией @EnableWebSocketMessageBroker
. Как следует из названия, @EnableWebSocketMessageBroker
включает обработку сообщений WebSocket, поддерживаемую брокером сообщений.
Метод configureMessageBroker()
реализует метод по умолчанию WebSocketMessageBrokerConfigurer
для настройки брокера сообщений. Он начинается с вызова enableSimpleBroker()
, чтобы позволить простому брокеру сообщений на основе памяти передавать приветственные сообщения обратно клиенту по пунктам назначения с префиксом /topic
. Он также обозначает /app
префикс для сообщений, связанных с методами, аннотированными с помощью @MessageMapping
. Этот префикс будет использоваться для определения всех сопоставлений сообщений. Например, /app/hello
это конечная точка, на которую GreetingController.greeting()
сопоставляется метод.
Метод registerStompEndpoints()
регистрирует /gs-guide-websocket
конечную точку, включая резервные варианты SockJS, чтобы можно было использовать альтернативные транспорты, если WebSocket недоступен. Клиент SockJS попытается подключиться /gs-guide-websocket
и использовать наилучший доступный транспорт (websocket, xhr-streaming, xhr-polling и т. д.).
Seems your browser doesn’t support Javascript! Websocket relies on Javascript being
enabled. Please enable
Javascript and reload this page!
Создать браузерный клиент
Разместив компоненты на стороне сервера, вы можете обратить внимание на клиент JavaScript, который будет отправлять и получать сообщения со стороны сервера.
Создайте index.html
файл, аналогичный следующему листингу (из src/main/resources/static/index.html
):
<!DOCTYPE html>
<html>
<head>
<title>Hello WebSocket</title>
<link href="/webjars/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<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="/app.js"></script>
</head>
<body>
<noscript><h2 style="color: #ff0000">Seems your browser doesn't support Javascript! Websocket relies on Javascript being
enabled. Please enable
Javascript and reload this page!</h2></noscript>
<div id="main-content" class="container">
<div class="row">
<div class="col-md-6">
<form class="form-inline">
<div class="form-group">
<label for="connect">WebSocket connection:</label>
<button id="connect" class="btn btn-default" type="submit">Connect</button>
<button id="disconnect" class="btn btn-default" type="submit" disabled="disabled">Disconnect
</button>
</div>
</form>
</div>
<div class="col-md-6">
<form class="form-inline">
<div class="form-group">
<label for="name">What is your name?</label>
<input type="text" id="name" class="form-control" placeholder="Your name here...">
</div>
<button id="send" class="btn btn-default" type="submit">Send</button>
</form>
</div>
</div>
<div class="row">
<div class="col-md-12">
<table id="conversation" class="table table-striped">
<thead>
<tr>
<th>Greetings</th>
</tr>
</thead>
<tbody id="greetings">
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>
Этот файл HTML импортирует библиотеки SockJS
и STOMP
библиотеки javascript, которые будут использоваться для связи с нашим сервером через STOMP через веб-сокет. Мы также импортируем app.js
, который содержит логику нашего клиентского приложения. Следующий листинг (из src/main/resources/static/app.js
) показывает этот файл:
var stompClient = null;
function setConnected(connected) {
$("#connect").prop("disabled", connected);
$("#disconnect").prop("disabled", !connected);
if (connected) {
$("#conversation").show();
}
else {
$("#conversation").hide();
}
$("#greetings").html("");
}
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);
});
});
}
function disconnect() {
if (stompClient !== null) {
stompClient.disconnect();
}
setConnected(false);
console.log("Disconnected");
}
function sendName() {
stompClient.send("/app/hello", {}, JSON.stringify({'name': $("#name").val()}));
}
function showGreeting(message) {
$("#greetings").append("<tr><td>" + message + "</td></tr>");
}
$(function () {
$("form").on('submit', function (e) {
e.preventDefault();
});
$( "#connect" ).click(function() { connect(); });
$( "#disconnect" ).click(function() { disconnect(); });
$( "#send" ).click(function() { sendName(); });
});
Основные части этого файла JavaScript, которые нужно понять, — это функции connect()
и sendName()
.
Функция connect()
использует SockJS и stomp.js для открытия соединения с /gs-guide-websocket
, где наш сервер SockJS ожидает соединений. При успешном соединении клиент подписывается на /topic/greetings
пункт назначения, где сервер будет публиковать приветственные сообщения. Когда приветствие получено в этом месте назначения, оно добавит элемент абзаца в DOM для отображения приветственного сообщения.
Функция sendName()
извлекает имя, введенное пользователем, и использует клиент STOMP, чтобы отправить его по /app/hello
назначению (где GreetingController.greeting()
оно будет получено).
Можно main.css
опустить, если хотите, или вы можете создать пустую, чтобы <link>
можно было разрешить.
Сделать приложение исполняемым
Spring Boot создает для вас класс приложения. В этом случае дальнейшая модификация не требуется. Вы можете использовать его для запуска этого приложения. В следующем листинге (из src/main/java/com/example/messagingstompwebsocket/MessagingStompWebsocketApplication.java
) показан класс приложения:
package com.example.messagingstompwebsocket;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MessagingStompWebsocketApplication {
public static void main(String[] args) {
SpringApplication.run(MessagingStompWebsocketApplication.class, args);
}
}
@SpringBootApplication
это удобная аннотация, которая добавляет все следующее:
@Configuration
: помечает класс как источник определений bean-компонентов для контекста приложения.@EnableAutoConfiguration
: Сообщает Spring Boot о начале добавления bean-компонентов на основе настроек пути к классам, других bean-компонентов и различных настроек свойств. Например, еслиspring-webmvc
он находится в пути к классам, эта аннотация помечает приложение как веб-приложение и активирует основные функции, такие как настройка файлаDispatcherServlet
.@ComponentScan
: говорит Spring искать другие компоненты, конфигурации и сервисы вcom/example
пакете, позволяя ему найти контроллеры.
Метод main()
использует метод Spring Boot SpringApplication.run()
для запуска приложения. Вы заметили, что не было ни одной строчки XML? web.xml
Файла тоже нет . Это веб-приложение на 100 % состоит из чистой Java, и вам не нужно заниматься настройкой какой-либо сантехники или инфраструктуры.
Создайте исполняемый файл JAR
Вы можете запустить приложение из командной строки с помощью Gradle или Maven. Вы также можете создать один исполняемый файл JAR, содержащий все необходимые зависимости, классы и ресурсы, и запустить его. Создание исполняемого jar-файла упрощает отправку, версию и развертывание службы как приложения на протяжении всего жизненного цикла разработки, в различных средах и т. д.
Если вы используете Gradle, вы можете запустить приложение с помощью ./gradlew bootRun
. Кроме того, вы можете создать файл JAR, используя ./gradlew build
и затем запустив файл JAR, следующим образом:
Если вы используете Maven, вы можете запустить приложение с помощью ./mvnw spring-boot:run
. Кроме того, вы можете создать файл JAR с помощью ./mvnw clean package
и затем запустить файл JAR следующим образом:
Описанные здесь шаги создают исполняемый файл JAR. Вы также можете создать классический файл WAR . |
Отображается вывод журнала. Служба должна быть запущена в течение нескольких секунд.
Протестируйте сервис
Теперь, когда служба запущена, укажите в браузере адрес http://localhost:8080 и нажмите кнопку « Подключиться ».
При открытии соединения вас попросят ввести ваше имя. Введите свое имя и нажмите Отправить . Ваше имя отправляется на сервер в виде сообщения JSON через STOMP. После имитации задержки в одну секунду сервер отправляет обратно сообщение с приветствием «Привет», которое отображается на странице. На этом этапе вы можете отправить другое имя или нажать кнопку « Отключить » , чтобы закрыть соединение.