Spring WebSockets: Mengirim Pesan ke Pengguna Tertentu

1. Perkenalan

Dalam tutorial ini, kami akan menjelaskan cara menggunakan Spring WebSockets untuk mengirim pesan STOMP ke satu pengguna. Itu penting karena terkadang kami tidak ingin menyiarkan setiap pesan ke setiap pengguna. Selain itu, kami akan mendemonstrasikan cara mengirim pesan ini dengan cara yang aman.

Untuk pengantar WebSockets, lihat tutorial hebat ini tentang cara menyiapkan dan menjalankan. Dan, untuk lebih mendalami keamanan, lihat artikel ini untuk mengamankan implementasi WebSockets Anda.

2. Antrian, Topik, dan Titik Akhir

Ada tiga cara utama untuk mengatakan ke mana pesan dikirim dan bagaimana mereka berlangganan menggunakan Spring WebSockets dan STOMP:

  1. Topik - percakapan umum atau topik obrolan terbuka untuk semua klien atau pengguna
  2. Antrian - dipesan untuk pengguna tertentu dan sesi mereka saat ini
  3. Endpoint - endpoints generik

Sekarang, mari kita lihat sekilas contoh jalur konteks untuk masing-masing:

  • “/ Topic / movies”
  • “/ Pengguna / antrian / pengguna-khusus”
  • “/ Secure / chat”

Penting untuk diperhatikan bahwa kita harus menggunakan antrian untuk mengirim pesan ke pengguna tertentu, karena topik dan titik akhir tidak mendukung fungsi ini .

3. Konfigurasi

Sekarang, mari pelajari cara mengkonfigurasi aplikasi kita sehingga kita dapat mengirim pesan ke pengguna tertentu:

public class SocketBrokerConfig extends AbstractWebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker("/secured/user/queue/specific-user"); config.setApplicationDestinationPrefixes("/spring-security-mvc-socket"); config.setUserDestinationPrefix("/secured/user"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/secured/room").withSockJS(); } }

Mari pastikan untuk menyertakan tujuan pengguna karena itu menentukan titik akhir mana yang disediakan untuk pengguna tunggal.

Kami juga memberi awalan pada semua antrian dan tujuan pengguna kami dengan "/ dijamin" untuk membuatnya memerlukan otentikasi. Untuk titik akhir yang tidak dilindungi, kita dapat menghilangkan awalan "/ dijamin" (sebagai hasil dari pengaturan keamanan lainnya).

Dari sudut pandang pom.xml , tidak diperlukan dependensi tambahan.

4. Pemetaan URL

Kami ingin klien kami berlangganan antrian menggunakan pemetaan URL yang sesuai dengan pola berikut:

"/user/queue/updates"

Pemetaan ini akan secara otomatis diubah oleh UserDestinationMessageHandler menjadi alamat khusus sesi pengguna.

Misalnya, jika kita memiliki pengguna bernama "user123" , alamat yang sesuai adalah:

"/queue/updates-user123"

Di sisi server, kami akan mengirimkan tanggapan khusus pengguna kami menggunakan pola pemetaan URL berikut:

"/user/{username}/queue/updates"

Ini juga akan diubah menjadi pemetaan URL yang benar, kita sudah berlangganan sisi klien.

Jadi, kami melihat bahwa bahan penting di sini ada dua:

  1. Tambahkan Awalan Tujuan Pengguna yang kami tentukan (dikonfigurasi di AbstractWebSocketMessageBrokerConfigurer ).
  2. Gunakan "/ queue" di suatu tempat dalam pemetaan.

Di bagian selanjutnya, kita akan melihat bagaimana tepatnya melakukan ini.

5. Memanggil convertAndSendToUser ()

Kita dapat secara non-statis memanggil convertAndSendToUser () dari SimpMessagingTemplate atau SimpMessageSendingOperations :

@Autowired private SimpMessagingTemplate simpMessagingTemplate; @MessageMapping("/secured/room") public void sendSpecific( @Payload Message msg, Principal user, @Header("simpSessionId") String sessionId) throws Exception { OutputMessage out = new OutputMessage( msg.getFrom(), msg.getText(), new SimpleDateFormat("HH:mm").format(new Date())); simpMessagingTemplate.convertAndSendToUser( msg.getTo(), "/secured/user/queue/specific-user", out); }

Anda mungkin telah memperhatikan:

@Header("simpSessionId") String sessionId

The @Header penjelasan memungkinkan akses ke header terpapar oleh pesan masuk. Misalnya, kita bisa mengambil sessionId saat ini tanpa perlu interseptor yang rumit. Demikian pula, kami dapat mengakses pengguna saat ini melalui Kepala Sekolah .

Yang penting, pendekatan yang kami ambil dalam artikel ini memberikan penyesuaian yang lebih besar pada anotasi @sendToUser sehubungan dengan pemetaan URL. Untuk mengetahui lebih lanjut tentang anotasi itu, lihat artikel hebat ini.

Sisi klien, kami akan menggunakan connect () di JavaScript untuk menginisialisasi instance SockJS dan terhubung ke server WebSocket kami menggunakan STOMP:

var socket = new SockJS('/secured/room'); var stompClient = Stomp.over(socket); var sessionId = ""; stompClient.connect({}, function (frame) { var url = stompClient.ws._transport.url; url = url.replace( "ws://localhost:8080/spring-security-mvc-socket/secured/room/", ""); url = url.replace("/websocket", ""); url = url.replace(/^[0-9]+\//, ""); console.log("Your current session is: " + url); sessionId = url; } 

Kami juga mengakses sessionId yang disediakan dan menambahkannya ke pemetaan URL " secure / room " . Ini memberi kami kemampuan untuk secara dinamis dan manual menyediakan antrian langganan khusus pengguna:

stompClient.subscribe('secured/user/queue/specific-user' + '-user' + that.sessionId, function (msgOut) { //handle messages } 

Setelah semuanya diatur, kita akan melihat:

Dan di konsol server kami:

6. Kesimpulan

Lihat blog resmi Spring dan dokumentasi resmi untuk informasi lebih lanjut tentang topik ini.

Seperti biasa, contoh kode yang digunakan dalam artikel ini tersedia di GitHub.