Spring WebSockets: Hantar Mesej kepada Pengguna Tertentu

1. Pengenalan

Dalam tutorial ini, kami akan menerangkan cara menggunakan Spring WebSockets untuk menghantar mesej STOMP kepada satu pengguna. Itu penting kerana kadang-kadang kita tidak mahu menyiarkan setiap mesej kepada setiap pengguna. Selain itu, kami akan menunjukkan cara menghantar mesej ini dengan cara yang selamat.

Untuk pengenalan WebSockets, lihat tutorial hebat ini untuk bagaimana bangun dan berjalan. Dan, untuk menyelami keselamatan yang lebih mendalam, lihat artikel ini untuk mendapatkan pelaksanaan WebSockets anda.

2. Baris, Topik, dan Titik Akhir

Terdapat tiga cara utama untuk mengatakan di mana mesej dihantar dan bagaimana mereka dilanggan menggunakan Spring WebSockets dan STOMP:

  1. Topik - perbualan biasa atau topik sembang terbuka untuk pelanggan atau pengguna mana pun
  2. Baris - dikhaskan untuk pengguna tertentu dan sesi semasa mereka
  3. Titik Akhir - titik akhir generik

Sekarang, mari kita lihat jalan konteks contoh untuk masing-masing:

  • "/ Topik / filem"
  • "/ Pengguna / barisan / pengguna khusus"
  • "/ Selamat / berbual"

Penting untuk diperhatikan bahawa kita mesti menggunakan antrian untuk menghantar mesej kepada pengguna tertentu, kerana topik dan titik akhir tidak menyokong fungsi ini .

3. Konfigurasi

Sekarang, mari kita pelajari cara mengkonfigurasi aplikasi kita sehingga kita dapat mengirim pesan kepada 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 memasukkan tujuan pengguna kerana menentukan titik akhir mana yang dikhaskan untuk pengguna tunggal.

Kami juga mengawali semua antrian dan tujuan pengguna dengan "/ selamat" untuk menjadikannya memerlukan pengesahan. Untuk titik akhir yang tidak dilindungi, kami dapat menjatuhkan awalan "/ selamat" (sebagai hasil daripada tetapan keselamatan kami yang lain)

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

4. Pemetaan URL

Kami mahu pelanggan kami melanggan barisan menggunakan pemetaan URL yang sesuai dengan corak berikut:

"/user/queue/updates"

Pemetaan ini akan diubah secara automatik oleh UserDestinationMessageHandler ke alamat khusus sesi pengguna.

Sebagai contoh, jika kita mempunyai pengguna bernama "user123" , alamat yang sesuai adalah:

"/queue/updates-user123"

Dari sisi pelayan, kami akan menghantar respons khusus pengguna kami menggunakan corak pemetaan URL berikut:

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

Ini juga akan diubah menjadi pemetaan URL yang betul yang telah kami langgankan di sisi pelanggan.

Oleh itu, kita melihat bahawa ramuan penting di sini adalah dua kali ganda:

  1. Siapkan Awalan Destinasi Pengguna yang kami tentukan (dikonfigurasi dalam AbstractWebSocketMessageBrokerConfigurer ).
  2. Gunakan "/ antrian" di suatu tempat dalam pemetaan.

Di bahagian seterusnya, kita akan melihat dengan tepat bagaimana melakukan ini.

5. Memohon convertAndSendToUser ()

Kita tidak boleh menggunakan convertAndSendToUser () dari SimpMessagingTemplate atau SimpMessageSendingOperations secara statik :

@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 menyedari:

@Header("simpSessionId") String sessionId

The @Header anotasi membolehkan akses kepada pengepala didedahkan oleh mesej masuk. Sebagai contoh, kita dapat merebut sesiId semasa tanpa memerlukan pemintas yang rumit. Begitu juga, kita boleh mengakses pengguna semasa melalui Principal .

Yang penting, pendekatan yang kami ambil dalam artikel ini memberikan penyesuaian yang lebih besar terhadap anotasi @sendToUser berkenaan dengan pemetaan URL. Untuk maklumat lanjut mengenai penjelasan itu, lihat artikel hebat ini.

Dari sisi pelanggan, kami akan menggunakan connect () dalam JavaScript untuk memulakan instance SockJS dan menyambung ke pelayan 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 sesiId yang disediakan dan menambahkannya ke pemetaan URL " selamat / ruangan " . Ini memberi kita keupayaan untuk menyediakan barisan langganan khusus pengguna secara dinamik dan manual:

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

Setelah semuanya siap, kita akan melihat:

Dan di konsol pelayan kami:

6. Kesimpulannya

Lihat blog rasmi Spring dan dokumentasi rasmi untuk maklumat lebih lanjut mengenai topik ini.

Seperti biasa, contoh kod yang digunakan dalam artikel ini terdapat di GitHub.