推送通知是一種實(shí)時(shí)消息傳遞形式,通過(guò)它網(wǎng)站可以向用戶實(shí)時(shí)通知特定事件。通常使用WebSockets實(shí)現(xiàn)推送通知,這種技術(shù)提供了客戶端和服務(wù)器之間的雙向通信,從而實(shí)現(xiàn)了實(shí)時(shí)消息的處理。
本文使用WebSockets來(lái)實(shí)現(xiàn)推送通知,并使用STOMP協(xié)議在客戶端和服務(wù)器之間進(jìn)行通信。
STOMP代表簡(jiǎn)單文本導(dǎo)向的消息協(xié)議(Simple Text Oriented Messaging Protocol)。由于WebSockets是一種低級(jí)協(xié)議,使用幀(frames)來(lái)傳輸數(shù)據(jù),而STOMP是一種高級(jí)協(xié)議,定義了如何解釋某些幀類型中的數(shù)據(jù)。這些幀類型包括CONNECT、SEND、ACK等。因此,使用STOMP能夠更加簡(jiǎn)化使用WebSockets進(jìn)行數(shù)據(jù)的發(fā)送、接收和解析過(guò)程。
有了這個(gè)基礎(chǔ),接下來(lái)創(chuàng)建服務(wù)器應(yīng)用程序。
到https://start.spring.io創(chuàng)建一個(gè)Spring Boot應(yīng)用程序,并添加以下依賴項(xiàng):
Spring Boot Starter Websockets
現(xiàn)在,使用一個(gè)嵌入式消息代理,它將是一個(gè)提供WebSocket功能的內(nèi)存中代理。給代理添加一些目的地。這些目的地指的是將要發(fā)送消息的路徑。
@Configuration@EnableWebSocketMessageBrokerpublic class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker("/all","/specific"); config.setApplicationDestinationPrefixes("/app"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/ws"); registry.addEndpoint("/ws").withSockJS(); }}
在第一部分中,啟用了一個(gè)帶有兩個(gè)目的地(/all和/specific)的代理。/all目的地將用于向所有用戶發(fā)送通知,/specific目的地用于向特定用戶發(fā)送通知。
接下來(lái),設(shè)置應(yīng)用程序的目的地,即 /app,這樣就可以向應(yīng)用程序發(fā)送信息了。
在第二部分中,注冊(cè)了STOMP端點(diǎn)。其中一個(gè)啟用了SockJS,另一個(gè)僅使用WebSocket。之所以這樣做,是因?yàn)椴⒎撬袨g覽器都支持WebSocket,當(dāng)不可用時(shí),可以回退到使用SockJS。
先看一下第一個(gè)用例,即向所有用戶發(fā)送推送通知。
為此,首先實(shí)現(xiàn)一個(gè)控制器,該控制器會(huì)把來(lái)自一個(gè)客戶端的信息轉(zhuǎn)發(fā)給所有客戶端。
@org.springframework.stereotype.Controllerpublic class Controller { @Autowired SimpMessagingTemplate simpMessagingTemplate; @MessageMapping("/application") @SendTo("/all/messages") public Message send(final Message message) throws Exception { return message; }}
在上面的代碼中,我們接受/application端點(diǎn)上的消息。這實(shí)際上是之前定義的應(yīng)用程序目的地/app的子目的地。這意味著客戶端必須把消息發(fā)送到/app/application目的地才能到達(dá)該處理程序。
接下來(lái),把傳入的消息轉(zhuǎn)發(fā)到/all/messages。現(xiàn)在,訂閱該目的地的所有客戶端都將收到發(fā)送給所有客戶端的消息。
來(lái)看看HTML頁(yè)面上的客戶端代碼:
<script type="text/javascript"> var stompClient = null; var socket = new SockJS('/ws'); stompClient = Stomp.over(socket); stompClient.connect({}, function(frame) { console.log(frame); stompClient.subscribe('/all/messages', function(result) { show(JSON.parse(result.body)); }); });
在這里,使用一個(gè)STOMP客戶端,在WebSocket上建立連接,然后訂閱/all/messages上的消息。
現(xiàn)在,為了將消息發(fā)送給應(yīng)用程序,有以下的JavaScript函數(shù),它將消息發(fā)送到/app/application:
function sendMessage() { var text = document.getElementById('text').value; stompClient.send("/app/application", {}, JSON.stringify({'from':from, 'text':text}));}
它簡(jiǎn)單地從文本字段中獲取文本值,并將其發(fā)送到代理的應(yīng)用程序目標(biāo)。
這是通過(guò)下面顯示的一個(gè)簡(jiǎn)單表單進(jìn)行連接的。
圖片
為了測(cè)試這個(gè),我們向所有連接的客戶端發(fā)送一個(gè)推送通知"Notification to all"。
圖片
這里有兩個(gè)連接的客戶端,兩個(gè)客戶端都立即收到了通知。
現(xiàn)在,在這里只是顯示了從WebSocket接收到的內(nèi)容,但可以根據(jù)需要使用CSS和JavaScript來(lái)自定義通知彈出窗口或通知標(biāo)簽。
這就是如何向所有用戶發(fā)送通知。那么如何向特定用戶發(fā)送通知呢?
要向特定用戶發(fā)送通知,我們需要收件人的用戶ID。這意味著接收方用戶需要登錄并提供一個(gè)有效的會(huì)話來(lái)標(biāo)識(shí)用戶的用戶ID。
為此,我們將集成Spring Security。因此,添加以下依賴項(xiàng)。
Spring Boot Starter Security
添加了Spring Security依賴項(xiàng)后,我們需要定義一個(gè)安全配置來(lái)允許使用WebSockets進(jìn)行連接。
@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests() .mvcMatchers("/","/ws/**") .permitAll() .and() .authorizeHttpRequests() .anyRequest().authenticated() .and() .formLogin() .and() .logout( logout -> logout.logoutSuccessUrl("/")); return http.build();}@Beanpublic InMemoryUserDetailsManager userDetailsService() { UserDetails user = User.withDefaultPasswordEncoder() .username("test") .password("test") .roles("USER") .build(); return new InMemoryUserDetailsManager(user);}
在這里,我們?cè)试S所有連接到/ws路徑的連接,以便在沒(méi)有任何身份驗(yàn)證的情況下進(jìn)行WebSocket通信,還定義了一個(gè)名為"test"的靜態(tài)用戶。
還記得在上面的消息代理設(shè)置中創(chuàng)建的/specific目標(biāo)嗎?現(xiàn)在將使用它來(lái)發(fā)送特定的消息。
首先,在控制器中添加一個(gè)處理程序,用于接收消息并將其發(fā)送給特定的用戶,這些用戶將使用它們的用戶名進(jìn)行標(biāo)識(shí)。
@org.springframework.stereotype.Controllerpublic class Controller { @Autowired SimpMessagingTemplate simpMessagingTemplate; @MessageMapping("/application") @SendTo("/all/messages") public Message send(final Message message) throws Exception { return message; } @MessageMapping("/private") public void sendToSpecificUser(@Payload Message message) { simpMessagingTemplate.convertAndSendToUser(message.getTo(), "/specific", message); }}
現(xiàn)在,在sendToSpecificUser方法中,我們接受使用/app/private發(fā)送的消息。消息包含要發(fā)送給接收者的文本以及接收者的用戶ID。
消息模板所做的是將消息發(fā)送到以/user開頭的目標(biāo),然后將其附加到我們?cè)赾onvertAndSendToUser函數(shù)調(diào)用中指定的目標(biāo),即/specific,然后附加所指定的用戶的用戶會(huì)話ID。
因此,convertAndSendToUser將消息發(fā)送到目標(biāo)/user/specific-<user-session-id>。這個(gè)目標(biāo)是在用戶登錄并訂閱/user/specific時(shí)創(chuàng)建的。
當(dāng)用戶登錄并訂閱/user/specific時(shí),它會(huì)發(fā)送有效的已登錄會(huì)話ID。然后,Spring自動(dòng)處理訂閱/user/specific將自動(dòng)訂閱已登錄用戶的特定目標(biāo),即/user/specific-<user-session-id>。
這也意味著只有用戶登錄時(shí)才能發(fā)送通知。
現(xiàn)在,添加一個(gè)新的文本塊并訂閱用戶特定的目標(biāo)。
socket = new SockJS('/ws');privateStompClient = Stomp.over(socket);privateStompClient.connect({}, function(frame) { console.log(frame); privateStompClient.subscribe('/user/specific', function(result) { console.log(result.body) show(JSON.parse(result.body)); }); });
圖片
打開兩個(gè)客戶端,并使用"test"用戶登錄第二個(gè)客戶端。可以使用/login端點(diǎn)觸發(fā)登錄。
在上面的圖像中,正在以"test"用戶登錄第二個(gè)客戶端。
登錄后,首先向所有客戶端發(fā)送消息。
圖片
所以,即使已登錄的用戶也會(huì)收到發(fā)送給所有客戶端的通知。
現(xiàn)在,向"test"用戶發(fā)送一個(gè)私有通知。
圖片
在上面的圖像中,我們?yōu)樘囟ㄓ脩籼峁┝艘粭l消息,并指定了特定用戶的用戶ID,即"test",通知只會(huì)傳遞給已登錄的用戶。
這是一個(gè)關(guān)于它是如何工作的簡(jiǎn)短演示。
圖片
在本文中,我們學(xué)習(xí)了如何使用Spring Boot應(yīng)用程序、WebSockets和STOMP協(xié)議發(fā)送推送通知。如果希望使用外部的ActiveMQ實(shí)例,只需將其連接到應(yīng)用程序,因?yàn)锳ctiveMQ也支持STOMP協(xié)議。這樣,我們就可以通過(guò)應(yīng)用程序?qū)⑾⒅欣^到外部的ActiveMQ實(shí)例,實(shí)現(xiàn)更靈活和可定制的消息傳遞。通過(guò)這種方式,可以輕松地實(shí)現(xiàn)推送通知功能,為用戶提供實(shí)時(shí)的信息更新和交互體驗(yàn)。希望這篇文章對(duì)讀者有所幫助!
本文鏈接:http://www.www897cc.com/showinfo-26-51263-0.html基于Spring Boot,一步步教你用Websockets和STOMP進(jìn)行消息推送
聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com