Hiện thực WebSocket với Spring framework

WebSocket là một trong các loại Socket, nói nôm na cho các bạn dễ hình dung về WebSocket thì nó giúp chúng ta có thể tạo kết nối 2 chiều giữa server side và client side trong một web application bất kỳ. Một khi kết nối đã được thiết lập thì client và server có thể trao đổi các thông tin với nhau, client có thể gửi message cho server và ngược lại server cũng vậy. Khác với HTTP connection thì chỉ có client mới có thể gửi request tới server, server trả về response, server không thể tự gửi message tới bất kỳ client nào. WebSocket thường được sử dụng trong các ứng dụng web đòi hỏi tính realtime của một chức năng nào đó. Trong bài viết này, mình sẽ hướng dẫn các bạn cách hiện thực WebSocket trong một web application với Spring framework các bạn nhé!

Đầu tiên, mình sẽ tạo mới một Spring Boot project:

Hiện thực WebSocket với Spring framework

với Web và WebSocket dependency như sau:

Hiện thực WebSocket với Spring framework

để làm ví dụ.

Kết quả:

Hiện thực WebSocket với Spring framework


Tạo mới WebSocket server

Để khởi tạo WebSocket server với Spring WebSocket, trước tiên, các bạn cần phải nắm một số khái niệm như sau:

Đầu tiên là về Message Broker, nó là một message-oriented middleware server đứng ở giữa để delivery message từ các request tới các topic theo cơ chế pub-sub hoặc queue theo cơ chế point-to-point. Có nghĩa là thay vì các application gửi thẳng message tới topic hoặc queue mà các bạn thường thấy khi làm việc với Message Queue thì với Message Broker, các message phải đi qua Message Broker này. Spring sử dụng Message Broker để hiện thực WebSocket behind the sense đó các bạn!

Cái thứ hai là mình sẽ nói về STOMP. STOMP là gì? Nó là viết tắt của từ Streaming Text Oriented Messaging Protocol, dịch ra thì STOMP là một giao thức tin nhắn hướng văn bản, được sử dụng để client và server sau khi đã connect được với nhau, sử dụng để trao đổi thông tin. Spring cũng hỗ trợ giao thức này trong việc truyền thông tin giữa client và server với WebSocket đó các bạn.

OK, giờ chúng ta sẽ khai báo để tạo mới một WebSocket server các bạn nhé!

Các bạn cần tạo mới một class để cấu hình cho WebSocket. Class này sẽ implement interface WebSocketMessageBrokerConfigurer và được annotate với annotation @EnableWebSocketMessageBroker nha các bạn:

Tất nhiên, là nó cũng cần được annotate với annotation @Configuration để Spring Boot tự động scan nữa!

Có 2 phương thức mà chúng ta cần implement trong class WebSocketConfiguration này là configureMessageBroker() và registerStompEndpoints(). Phương thức configureMessageBroker() với tham số là class MessageBrokerRegistry cho phép chúng ta có thể cấu hình Message Broker với phương thức enableSimpleBroker():

Tham số của phương thức enableSimpleBroker() là prefix của các endpoint mà các client có thể subscribe và nhận message từ server. Có nghĩa là, endpoint mà các client subscribe phải bắt đầu với giá trị được khai báo với phương thức enableSimpleBroker(). Khác thì ứng dụng của chúng ta sẽ không chạy.

Trong phương thức configureMessageBroker() trên, mình cũng sử dụng thêm phương thức setApplicationDestinationPrefixes() để định nghĩa prefix cho các destination mà client sẽ gửi message tới WebSocket server. Các bạn nếu đã làm việc với RESTful Web Service sử dụng Spring MVC thì có thể hình dung mục đích của phương thức này giống như các bạn định nghĩa một request mapping trong Controller ở class level. Những method định nghĩa các request URL sẽ có prefix là value của request mapping này.

Phương thức registerStompEndpoints() với tham số là class StompEndpointRegistry thì cũng giống như khi định nghĩa các request URL trong RESTful Web Service, giúp chúng ta định nghĩa những endpoint mà client sẽ sử dụng để gọi và kết nối tới WebSocket. Chúng ta sử dụng phương thức addEndpoint() của class StompEndpointRegistry để thêm các endpoint mà các bạn muốn. Ví dụ mình định nghĩa một endpoint như sau:

Một số trình duyệt có thể sẽ không hỗ trợ WebSocket connection ví dụ như chế độ ẩn danh của trình duyệt Chrome chẳng hạn. Trong trường hợp này, các bạn có thể gọi thêm method withSockJS() để sử dụng các giải pháp thay thế khác như xhr-streaming, xhr-polling thay vì kết nối WebSocket mặc định.

Nội dung class WebSocketConfiguration của mình lúc này như sau:

Để handle message từ client gửi tới endpoint mà chúng ta vừa mới configure ở trên “/hello”, các bạn có thể tạo mới một controller MessageController với nội dung như sau:

Giống như controller trong Spring MVC, các bạn có thể annotate class handle message từ client với annotation @Controller nhưng thay vì sử dụng annotation @RequestMapping trong method handle message, chúng ta sử dụng annotation @MessageMapping với value là giá trị của endpoint mà chúng ta đã cấu hình trong class WebSocketConfiguration, ví dụ của mình là “/hello”.

Sau khi method xử lý business logic và trả về kết quả, kết quả này sẽ được gửi tới destination mà client đã subscribe, được khai báo trong annotation @SendTo. Nên nhớ là giá trị được khai báo trong annotation @SendTo phải bắt đầu giống với giá trị chúng ta đã khai báo trong phương thức enableSimpleBroker() ở trên nha các bạn!

Bây giờ, nếu các bạn chạy ứng dụng, xem log message, các bạn sẽ thấy WebSocket server sẽ start và sẵn sàng nhận kết nối từ phía client như sau:

Tiếp theo, chúng ta sẽ code phần client để xem WebSocket hoạt động như thế nào nhé các bạn!


Tạo mới client kết nối tới WebSocket server

Mình sẽ viết code HTML, JavaScript để giả lập việc gửi message từ client tới server, và cả việc server gửi message tới client như thế nào.

Mình sẽ sử dụng WebJars để thêm JQuery, SocketJS clientStomp WebSocket dependencies như sau:

JQuery dùng để viết code Javascript dễ dàng hơn, SockJS để làm việc với WebSocket connection còn Stomp WebSocket thì để chúng ta làm việc với STOMP message đó các bạn!

Mình sẽ tạo mới một trang HTML cho phép chúng ta nhập tên user, nhấn nút gửi tới WebSocket server, và một nơi để hiển thị kết quả trả về từ WebSocket server.

Hiện thực WebSocket với Spring framework

Nội dung của tập tin index.html trong thư mục src/main/resources/static như sau:

Tập tin app.js cũng trong thư mục src/main/resources/static có nội dung như sau:

Nếu các bạn biết một chút về JQuery thì sẽ hiểu code của mình có nghĩa là: khi browser đã load nội dung của trang index.html, web của mình sẽ tự động connect tới WebSocket server sử dụng thư viện SockJS client và sử dụng thư viện Stomp WebSocket để gửi STOMP message. Đối tượng Stomp Client sẽ subscribe vào “/topic/messages” để nhận message từ WebSocket server.

Stomp Client cho phép chúng ta có thể gửi một STOMP message tới WebSocket server sử dụng endpoint “/app/hello” với giá trị chúng ta nhập trong textbox.

Mỗi khi nhận message từ WebSocket server thì giá trị trong phần body của STOMP message này sẽ được hiển thị.

Kết quả khi mình chạy ứng dụng, nhập Khanh vào textbox và nhấn nút Send như sau:

Hiện thực WebSocket với Spring framework

Nếu các bạn mở 2 cửa sổ trình duyệt và làm lại thao tác như trên, các bạn cũng sẽ thấy cả 2 browser đều nhận được message từ WebSocket server. Của mình như sau:

Hiện thực WebSocket với Spring framework

Add Comment