
Bu makale, bir tarayıcı ile bir sunucu arasında ileri geri mesaj gönderen bir “Merhaba dünya” uygulaması oluşturma sürecinde size yol gösterir. WebSocket, TCP’nin üzerinde ince, hafif bir katmandır. Bu, mesajları gömmek için “alt protokoller” kullanmayı uygun hale getirir. Makalemizde etkileşimli bir web uygulaması oluşturmak için Spring ile STOMP mesajlaşmasını kullanıyoruz. STOMP, alt düzey WebSocket üzerinde çalışan bir alt protokoldür.
Ne inşa edeceğiz?
Bir kullanıcının adını taşıyan bir mesajı kabul eden bir sunucu oluşturacağız. Yanıt olarak sunucu, istemcinin abone olduğu bir kuyruğa selamlama gönderecektir.
Neye ihtiyacımız var?
- yaklaşık 15 dakika
- Favori bir metin editörü veya IDE
- Java 17 veya üstü
- Gradle 7.5+ veya Maven 3.5+
- Kodu doğrudan IDE’nize de aktarabilirsiniz:
Bu makale nasıl tamamlanır?
Spring’e Başlarken kılavuzlarının çoğunda olduğu gibi, sıfırdan başlayıp her adımı tamamlayabilir veya zaten aşina olduğunuz temel kurulum adımlarını atlayabilirsiniz. Her iki durumda da, sonunda çalışan bir kod elde edersiniz.
Sıfırdan başlamak için Spring Initializr ile Başlatma’ya geçin .
Temel bilgileri atlamak için aşağıdakileri yapın:
- Bu makalenin kaynak deposunu indirip açın veya Git’i kullanarak kopyalayın
git clone https://github.com/spring-guides/gs-messaging-stomp-websocket.git
- içine cd ile girin:
gs-messaging-stomp-websocket/initial
- Kaynak Gösterim Sınıfı Oluşturma bölümüne atlayın.
Bitirdiğinizde, sonuçlarınızı içindeki kodla karşılaştırabilirsiniz gs-messaging-stomp-websocket/complete
.
Spring Initializr ile Başlamak
Önceden başlatılmış projeyi kullanabilir ve bir ZIP dosyası indirmek için Oluştur’a tıklayabilirsiniz. Bu proje, bu eğitimdeki örneklere uyacak şekilde yapılandırılmıştır.
Projeyi manuel olarak başlatmak için:
- https://start.spring.io adresine gidin. Bu hizmet, bir uygulama için ihtiyaç duyduğunuz tüm bağımlılıkları çeker ve kurulumun çoğunu sizin yerinize yapar.
- Gradle veya Maven’i ve kullanmak istediğiniz dili seçin. Bu makale Java’yı seçtiğinizi varsayar.
- Bağımlılıklar’a tıklayın ve Websocket’ı seçin.
- Oluştur’u tıklayın.
- Seçimlerinizle yapılandırılmış bir web uygulamasının arşivi olan ortaya çıkan ZIP dosyasını indirin.
IDE’niz Spring Initializr entegrasyonuna sahipse, bu işlemi IDE’nizden tamamlayabilirsiniz. |
Ayrıca projeyi Github’dan çatallayabilir ve IDE’nizde veya başka bir düzenleyicide açabilirsiniz. |
Bağımlılıklar Ekleme
Spring Initializr, bu durumda ihtiyacınız olan her şeyi sağlamaz. Maven için aşağıdaki bağımlılıkları eklemeniz gerekir:
<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>
Aşağıdaki kod, tamamlanmış pom.xml
dosyasını gösterir:
<?xml version="1.0" kodlama="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> <ebeveyn> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.0.0</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>17</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>
Eğer Gradle’ı kullanıyorsanız, aşağıdaki bağımlılıkları da eklemelisiniz:
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'
Aşağıdaki kod tamamlanmış build.gradle
dosyasını gösterir:
plugins { id 'org.springframework.boot' version '3.0.0' id 'io.spring.dependency-management' version '1.1.0' id 'java' } group = 'com.example' version = '0.0.1-SNAPSHOT' sourceCompatibility = '17' 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() }
Kaynak Temsili Sınıf Oluşturma
Artık projeyi kurduğunuza ve sistemi kurduğunuza göre, STOMP mesaj hizmetinizi oluşturabilirsiniz.
Hizmet etkileşimlerini düşünerek sürece başlayın.
Hizmet, gövdesi bir JSON nesnesi olan bir STOMP iletisinde ad içeren iletileri kabul edecektir. Ad Fred
ise, mesaj aşağıdakine benzer:
{
"name": "Fred"
}
Adı taşıyan mesajı modellemek için, aşağıdaki kodda gösterildiği gibi, bir name
özelliği ve buna karşılık gelen bir metodu olan düz, eski bir Java nesnesi oluşturabilirsiniz:
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;
}
}
Mesajı aldıktan ve adı çıkardıktan sonra hizmet, bir selamlama oluşturarak ve bu selamlamayı istemcinin abone olduğu ayrı bir kuyrukta yayınlayarak işleyecektir. Karşılama ayrıca, aşağıdaki kodda gösterildiği gibi bir JSON nesnesi olacaktır:
{
"content": "Hello, Fred!"
}
Karşılama temsilini modellemek için, aşağıdaki kodda gösterildiği gibi, bir content
özelliği ve buna karşılık gelen bir metodu olan başka bir düz eski Java nesnesi ekleyin:
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, Greeting tür örneklerini otomatik olarak JSON’a sıralamak için Jackson JSON kitaplığını kullanacaktır.
Ardından, merhaba mesajını almak ve bir karşılama mesajı göndermek için bir denetleyici oluşturacaksınız.
İleti İşleme Denetleyicisi Oluşturma
Spring’in STOMP mesajlarıyla çalışma yaklaşımında, STOMP mesajları @Controller
sınıflara yönlendirilebilir. Örneğin, GreetingController
, aşağıdaki kodda (src/main/java/com/example/messagingstompwebsocket/GreetingController.java) gösterildiği gibi, hedefe giden mesajları işlemek için eşlenir:
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()) + "!");
}
}
Bu denetleyici özlü ve basit, ancak çok şey oluyor. Adım adım anlatıyorum.
@MessageMapping
açıklaması, /hello
hedefine bir mesaj gönderilirse greeting()
metodunun çağrılmasını sağlar.
Mesajın içeriği greeting()
metodunun message parametresindedir.
Dahili olarak, metodun uygulanması, iş parçacığının bir saniye uyku moduna geçmesine neden olarak bir işlem gecikmesini simüle eder. Bu, istemci bir mesaj gönderdikten sonra, sunucunun mesajı eşzamansız olarak işlemesi gerektiği sürece sürebileceğini göstermek içindir. İstemci yanıt beklemeden yapması gereken işe devam edebilir.
Bir saniyelik gecikmeden sonra, greeting()
metodu bir Greeting
nesnesi oluşturur ve onu döndürür. Dönen değer, açıklamada ( @SendTo
(“/topic/greetings
“)’te ) belirtildiği gibi tüm abonelere yayınlanır . Girdi mesajındaki adın sterilize edildiğini unutmayın, çünkü bu durumda, istemci tarafında tarayıcı DOM’unda yankılanacak ve yeniden oluşturulacaktır.
STOMP mesajlaşması için Spring’i yapılandırın
Artık hizmetin temel bileşenleri oluşturulduğundan, Spring’i WebSocket ve STOMP mesajlaşmasını etkinleştirecek şekilde yapılandırabilirsiniz.
Aşağıdaki kodda WebSocketConfig için bir Java sınıfı oluşturun (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();
}
}
@Configuration
bir Spring konfigürasyon sınıfı olduğunu belirtmek için gerekli açıklamalıdır, @EnableWebSocketMessageBroker
de eklenmiştir. Adından da anlaşılacağı gibi, @EnableWebSocketMessageBroker
bir mesaj aracısı tarafından desteklenen WebSocket mesaj işlemeyi etkinleştirir.
Message Broker’ı yapılandırmak için configureMessageBroker()
varsayılan metodunu uygular. Basit bir bellek tabanlı mesaj komisyoncusunun karşılama mesajlarını WebSocketMessageBrokerConfigurer ön eki olan hedeflerde istemciye geri taşımasını sağlamak için çağrı yaparak başlar. Ayrıca, açıklama eklenmiş metodlara bağlanan iletilerin önekini de belirler. Bu önek, tüm mesaj eşlemelerini tanımlamak için kullanılacaktır. Örneğin, metodu işlemek için eşlendiği bitiş noktasıdır: .enableSimpleBroker()/topic/app@MessageMapping/app/helloGreetingController.greeting()
registerStompEndpoints()
metodu, /gs-guide-websocket
uç noktayı kaydederek SockJS geri dönüş seçeneklerini etkinleştirerek WebSocket yoksa alternatif aktarımların kullanılabilmesini sağlar. /gs-guide-websocket
SockJS istemcisi, mevcut en iyi aktarıma (websocket, xhr-streaming, xhr-polling, vb.) bağlanmaya ve onu kullanmaya çalışacaktır.
Bir Tarayıcı İstemcisi Oluşturun
Sunucu tarafı parçaları yerinde olduğunda, dikkatinizi sunucu tarafına mesaj gönderecek ve sunucu tarafından mesaj alacak JavaScript istemcisine çevirebilirsiniz.
Aşağıdaki koda benzer bir dosya oluşturun (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>
Bu HTML dosyası, websocket üzerinden STOMP aracılığıyla sunucumuzla iletişim kurmak için kullanılacak SockJS
ve javascript kitaplıklarını içe aktarır. Ayrıca app.js
client uygulamamızın mantığını içeren stomp’u import ediyoruz. Aşağıdaki kod (src/main/resources/static/app.js
) bu dosyayı gösterir:
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(); });
});
Bu JavaScript dosyasının anlaşılması gereken ana parçaları connect()
ve sendName()
işlevleridir.
İşlev connect(), SockJS sunucumuzun bağlantıları beklediği yerde bir bağlantı açmak için SockJS ve stomp.js’yi kullanır. Başarılı bir bağlantının ardından istemci, sunucunun karşılama mesajlarını yayınlayacağı hedefe abone olur. Bu hedefte bir karşılama alındığında, karşılama mesajını görüntülemek için DOM’a bir paragraf öğesi eklenir.
İşlev sendName(), kullanıcı tarafından girilen adı alır ve onu hedefe ( alacağı yer) göndermek için STOMP istemcisini kullanır.
İsterseniz main.css atlanabilir veya <link>
çözülebilmesi için boş bir tane css dosyası oluşturabilirsiniz.
Uygulamayı Yürütülebilir Hale Getirin
Spring Boot sizin için bir uygulama sınıfı oluşturur. Bu durumda, daha fazla değişikliğe ihtiyaç duymaz. Bu uygulamayı çalıştırmak için kullanabilirsiniz. Aşağıdaki kod (src/main/java/com/example/messagingstompwebsocket/MessagingStompWebsocketApplication.java
) uygulama sınıfını gösterir:
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
aşağıdakilerin tümünü ekleyen bir kolaylık ek açıklamasıdır:
@Configuration
: Sınıfı, uygulama bağlamı için bean tanımlarının kaynağı olarak etiketler.@EnableAutoConfiguration
: Spring Boot’a sınıf yolu ayarlarına, diğer bean ve çeşitli özellik ayarlarına göre bean eklemeye başlamasını söyler. Örneğin,spring-webmvc
sınıf yolundaysa bu ek açıklama, uygulamayı bir web uygulaması ve birDispatcherServlet
olarak işaretler.@ComponentScan
: Spring’ecom/example
paketteki diğer bileşenleri, yapılandırmaları ve hizmetleri aramasını söyleyerek denetleyicileri bulmasına izin verir.
Yöntem main(), bir uygulamayı başlatmak için Spring Boot’un SpringApplication.run() yöntemini kullanır. web.xml’de tek bir XML satırı olmadığını fark ettiniz mi? Bu web uygulaması %100 saf Java’dır ve herhangi bir altyapı yapılandırması ile uğraşmak zorunda kalmazsınız.
Yürütülebilir bir JAR oluşturun
Uygulamayı Gradle veya Maven ile komut satırından çalıştırabilirsiniz. Ayrıca gerekli tüm bağımlılıkları, sınıfları ve kaynakları içeren tek bir yürütülebilir JAR dosyası oluşturabilir ve onu çalıştırabilirsiniz. Yürütülebilir bir jar oluşturmak, hizmeti geliştirme yaşam döngüsü boyunca, farklı ortamlarda vb. bir uygulama olarak göndermeyi, sürümlendirmeyi ve dağıtmayı kolaylaştırır.
Gradle kullanıyorsanız, ./gradlew bootRun
kullanarak uygulamayı çalıştırabilirsiniz. Alternatif olarak, JAR dosyasını aşağıdaki gibi ./gradlew build kullanarak oluşturabilir ve ardından JAR dosyasını çalıştırabilirsiniz:
java -jar build/libs/gs-messaging-stomp-websocket-0.1.0.jar
Maven kullanıyorsanız, ./mvnw spring-boot:run kullanarak uygulamayı çalıştırabilirsiniz. Alternatif olarak, JAR dosyasını ./mvnw clean package
ile oluşturabilir ve ardından JAR dosyasını çalıştırabilirsiniz:
java -jar hedefi/gs-messaging-stomp-websocket-0.1.0.jar
Burada açıklanan adımlar çalıştırılabilir bir JAR oluşturur. Klasik bir WAR dosyası da oluşturabilirsiniz . |
Günlük çıktısı görüntülenir. Hizmet birkaç saniye içinde çalışır durumda olmalıdır.
Hizmeti test edin
Artık hizmet çalışıyor, tarayıcınızı http://localhost:8080 adresine getirin ve Bağlan düğmesini tıklayın.
Bir bağlantı açtığınızda, adınız sorulur. Adınızı girin ve Gönder’i tıklayın. Adınız sunucuya STOMP üzerinden JSON mesajı olarak gönderilir. Bir saniyelik simüle edilmiş bir gecikmenin ardından sunucu, sayfada görüntülenen bir “Merhaba” selamlaması içeren bir mesaj gönderir. Bu noktada başka bir isim gönderebilir veya bağlantıyı kesmek için Bağlantıyı Kes düğmesine tıklayabilirsiniz.
Özet
Tebrikler! Java’da Spring ile STOMP tabanlı bir mesajlaşma servisi geliştirdiniz. Bu makale .NET’deki SingalR’a alternatif olarak Java’da WebSocket çalışmasının Spring ile nasıl yapıldığını anlatmaktadır.
İstemciniz React, React Native vb. ise SockJS kütüphanesini kullanmalısınız.