1. 程式人生 > 其它 >@scheduled註解配置時間_使用spring boot+WebSocket 實現定時訊息推送(基於註解)

@scheduled註解配置時間_使用spring boot+WebSocket 實現定時訊息推送(基於註解)

技術標籤:@scheduled註解配置時間@serverendpoint註解c++ websocket客戶端enablescheduling註解java訊息推送怎麼實現serverendpoint註解

  • 作者:清風徐來水波不清

  • https://www.jianshu.com/p/62132f605669

前言

前面文章也有 websocket 相關的文章,為什麼這次又要重新寫一篇呢?第一這篇文章需求業務場景有些不同,第二這篇文章 websocket 基本上完全基於註解操作簡單。
其實能實現定時訊息推送的技術有很多,Dwr、goeasy、comer4j 、netPush 等技術也可以完全實現這個功能.

  • DWR 之前文件的訊息推送也有使用到,但是在實際專案中表現的並不是很好,畢竟技術相對較老,對於一些瀏覽器版本相容性不是很好,而且容易出現訊息丟失的情況,研究半天原始碼改動很多無法解決這個問題。

  • GoEasy 其實在訊息推送方面表現還是比較良好,但是其是收費的,我們專案基本使用開源產品對應收費產品合規性檢測肯定無法通過,因此沒有考慮。

  • 後面兩個技術沒有具體研究過,目前覺得 webSocket 可以完美解決我現在業務需求。

websocket 簡介

websocket 協議是在 http 協議上的一種補充協議,是 html5 的新特性,是一種持久化的協議。其實 websocket 和 http 關係並不是很大,不過都是屬於應用層的協議。關於更多概念大家可以參考下面文章講述的很詳細,接下來我們就開始實戰。

https://www.cnblogs.com/fuqiang88/p/5956363.html

websocket 定時推送

本教程基於 springboot 為腳手架,沒使用過 springboot 同學可以看往期文章,或者直接去 spring 官網拉一個 springboot 基礎專案下來。

加入依賴

在 springboot 的專案中新增一下 webSocket 依賴,一般一項新技術的引入在 springboot 中也只是引用一個此技術 starter 的依賴,其他配置基本 springboot 幫我們解決了。

org.springframework.boot

spring-boot-starter-websocket

配置

新建一個 Java 配置類,注入 ServerEndpointExporter 配置,如果是使用 springboot 內建的 tomcat 此配置必須,如果是使用的是外部 tomcat 容器此步驟請忽略。看 spring 原始碼中這樣描述,使用此配置可以關閉 servlet 容器對 websocket 端點的掃描,這個暫時沒有深入研究。

@Configuration

public class WebSocketConfig {

@Bean

public ServerEndpointExporter serverEndpointExporter() {

return new ServerEndpointExporter();

}

}

核心程式碼

接下來最核心的類其實就是提供一個前後端互動的類實現訊息的接收推送。

  • @ServerEndpoint(value = "/wsdemo") 前端通過此 URI 和後端互動,建立連線

  • @Component 不用說將此類交給 spring 管理

  • @OnOpen websocket 建立連線的註解,前端觸發上面 URI 時會進入此註解標註的方法,和之前關於 DWR 文章中的 onpage 方法類似

  • @OnClose 顧名思義關閉連線,銷燬 session

  • @OnMessage 收到前端傳來的訊息後執行的方法

@ServerEndpoint(value = "/wsdemo")

@Component

public class MyWebSocket {

private static int onlineCount = 0;

private static CopyOnWriteArraySet<MyWebSocket> webSocketSet = new CopyOnWriteArraySet<MyWebSocket>();

private Session session;

@OnOpen

public void onOpen(Session session) {

this.session = session;

webSocketSet.add(this);

addOnlineCount();

System.out.println("有新連線加入!當前線上人數為" + getOnlineCount());

try {

sendMessage("連線已建立成功.");

} catch (Exception e) {

System.out.println("IO異常");

}

}

@OnClose

public void onClose() {

webSocketSet.remove(this);

subOnlineCount();

System.out.println("有一連線關閉!當前線上人數為" + getOnlineCount());

}

@OnMessage

public void onMessage(String message, Session session) {

System.out.println("來自客戶端的訊息:" + message);

}

@OnError

public void onError(Session session, Throwable error) {

System.out.println("發生錯誤");

error.printStackTrace();

}

public void sendMessage(String message) throws IOException {

this.session.getBasicRemote().sendText(message);

}

public static synchronized int getOnlineCount() {

return onlineCount;

}

public static synchronized void addOnlineCount() {

MyWebSocket.onlineCount++;

}

public static synchronized void subOnlineCount() {

MyWebSocket.onlineCount--;

}

public Session getSession() {

return session;

}

public void setSession(Session session) {

this.session = session;

}

public static CopyOnWriteArraySet<MyWebSocket> getWebSocketSet() {

return webSocketSet;

}

public static void setWebSocketSet(CopyOnWriteArraySet<MyWebSocket> webSocketSet) {

MyWebSocket.webSocketSet = webSocketSet;

}

}

定時任務

使用 spring 的 Schedule 建立定時任務

  • @EnableScheduling 開啟 spring 定時任務功能

  • @Scheduled(cron = "0/10 * * * * ?") 用於標識定時執行的方法,此處主要方法返回值一定是 void,沒有入參。對應定時時間配置可以百度 cron 語法,根據自己的業務選擇合適的週期
    在這類中,我們通過上面 MyWebSocket 提供的靜態方法獲取其中的 webSocketSet ,來獲取所有此業務相關的所有 websocketsession,可以在定時任務中對 session 內容進行驗證判斷(許可權驗證等),進行傳送訊息

@Component

@EnableScheduling

public class TimeTask

{

private static Logger logger = LoggerFactory.getLogger(TimeTask.class);

@Scheduled(cron = "0/1 * * * * ?")

public void test(){

System.err.println("********* 定時任務執行 **************");

CopyOnWriteArraySet<MyWebSocket> webSocketSet =

MyWebSocket.getWebSocketSet();

int i = 0 ;

webSocketSet.forEach(c->{

try {

c.sendMessage(" 定時傳送 " + new Date().toLocaleString());

} catch (IOException e) {

e.printStackTrace();

}

});

System.err.println("/n 定時任務完成.......");

}

}

前端頁面

前端頁面可以參考使用,主要要更改呼叫的 url 為自己專案 URL

My WebSocket

Welcome

type="text" /> onclick="send()">Send onclick="closeWebSocket()">Close

效果演示

e02cc9570fb885832933a342b70ec2ca.png

(完)

推薦閱讀

IDEA新特性:提前知道程式碼怎麼走!

還在擔心寫的一手爛SQL,送你4款工

瞬間幾千次的重複提交,我用 SpringBoot+Redis 扛住了

爬了知乎“神回覆”,笑得根本停不下來

這 17 個 JVM 引數,高階 Java 必須掌握!

HTTP客戶端連線,選擇HttpClient還是OkHttp?

為什麼建議使用你 LocalDateTime ,而不是 Date?

d316685c436ec398f9f6e1f05d07ac3e.png

好文!必須點贊