日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

使用springboot来实现WebLog

發布時間:2025/3/12 编程问答 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用springboot来实现WebLog 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

使用websocket技術實時輸出系統日志到瀏覽器端,實現WebLog?

?

?

boot-websocket-log:

spring boot系統中使用websocket技術實時輸出系統日志到瀏覽器端,因為是實時輸出,所有第一時間就想到了使用webSocket,而且在spring boot中,使用websocket超級方便,閱讀本文,你會接觸到以下關鍵詞相關技術:

WebSocket(stopmp服務端)

stomp協議

sockjs.min.js

stomp.min.js(stomp客戶端),

本文使用到的其實就是

使用spring boot自帶的webSocket模塊提供stomp的服務端,

前端使用stomp.min.js做stomp的客戶端,

使用sockjs來鏈接,

前端訂閱后端日志端點的消息,后端實時推送,達到日志實時輸出到web頁面的目的

?

此項目使用場景

  • 集成到已有的項目中,實現項目日志文件web端瀏覽(第一個功能)

  • 單獨使用,指定已有項目的日志文件位置,實現項目日志web端瀏覽(第二個功能)

  • 使用boot-websocket-log的stopmp服務推送日志其他的非web端消費

  • ?

    ?

    參考博文:https://gitee.com/kailing/boot-websocket-log

    ?

    知識補充1:stomp協議:

    STOMP即Simple (or Streaming) Text Orientated Messaging Protocol,面向消息的簡單文本協議,它提供了一個可互操作的連接格式,允許STOMP客戶端與任意STOMP消息代理(Broker)進行交互。STOMP協議由于設計簡單,易于開發客戶端,因此在多種語言和多種平臺上得到廣泛地應用。
    ?

    STOMP協議的前身是TTMP協議(一個簡單的基于文本的協議),專為消息中間件設計。

    STOMP是一個非常簡單和容易實現的協議,其設計靈感源自于HTTP的簡單性。盡管STOMP協議在服務器端的實現可能有一定的難度,但客戶端的實現卻很容易。例如,可以使用Telnet登錄到任何的STOMP代理,并與STOMP代理進行交互。

    STOMP協議與HTTP協議很相似,它基于TCP協議,使用了以下命令:

    CONNECT
    SEND
    SUBSCRIBE
    UNSUBSCRIBE
    BEGIN
    COMMIT
    ABORT
    ACK
    NACK
    DISCONNECT

    STOMP的客戶端和服務器之間的通信是通過“幀”(Frame)實現的,每個幀由多“行”(Line)組成。
    第一行包含了命令,然后緊跟鍵值對形式的Header內容。
    第二行必須是空行。
    第三行開始就是Body內容,末尾都以空字符結尾。

    例:?
    發送消息

    SEND?
    destination:/queue/trade?
    content-type:application/json?
    content-length:44?
    {“action”:”BUY”,”ticker”:”MMM”,”shares”,44}^@

    ?

    訂閱消息

    SUBSCRIBE?
    id:sub-1?
    destination:/topic/price.stock.*?
    ^@

    ?

    服務器進行廣播消息

    MESSAGE?
    message-id:nxahklf6-1?
    subscription:sub-1?
    destination:/topic/price.stock.MMM?
    {“ticker”:”MMM”,”price”:129.45}^@
    ?

    ?

    客戶端 API

    引入stomp.js

    <script type="application/javascript" src="http://cdn.bootcss.com/stomp.js/2.3.3/stomp.min.js"></script>
    • ?

    發起連接


    客戶端可以通過使用Stomp.js和sockjs-client連接

    // 建立連接對象(還未發起連接)
    var socket=new SockJS("/spring-websocket-portfolio/portfolio");

    // 獲取 STOMP 子協議的客戶端對象
    var stompClient = Stomp.over(socket);

    // 向服務器發起websocket連接并發送CONNECT幀
    stompClient.connect(
    ? ? {},
    function connectCallback (frame) {
    ? ? // 連接成功時(服務器響應 CONNECTED 幀)的回調方法
    ? ? ? ? document.getElementById("state-info").innerHTML = "連接成功";
    ? ? ? ? console.log('已連接【' + frame + '】');
    ? ? ? ? stompClient.subscribe('/topic/getResponse', function (response) {
    ? ? ? ? ? ? showResponse(response.body);
    ? ? ? ? });
    ? ? },
    function errorCallBack (error) {
    ? ? // 連接失敗時(服務器響應 ERROR 幀)的回調方法
    ? ? ? ? document.getElementById("state-info").innerHTML = "連接失敗";
    ? ? ? ? console.log('連接失敗【' + error + '】');
    ? ? }
    );

    stompClient.connect()方法簽名:

    client.connect(headers, connectCallback, errorCallback);

    ?

    其中?
    headers表示客戶端的認證信息,如:

    var headers = {
    ? login: 'mylogin',
    ? passcode: 'mypasscode',
    ? // additional header
    ? 'client-id': 'my-client-id'
    };
    若無需認證,直接使用空對象 “{}” 即可;

    connectCallback 表示連接成功時(服務器響應 CONNECTED 幀)的回調方法;?
    errorCallback 表示連接失敗時(服務器響應 ERROR 幀)的回調方法,非必須;

    ?

    斷開連接

    若要從客戶端主動斷開連接,可調用 disconnect() 方法

    client.disconnect(function () {alert("See you next time!"); };

    該方法為異步進行,因此包含了回調參數,操作完成時自動回調;

    ?

    心跳機制


    若使用STOMP 1.1 版本,默認開啟了心跳檢測機制,可通過client對象的heartbeat field進行配置(默認值都是10000 ms):

    client.heartbeat.outgoing = 20000; ?// client will send heartbeats every 20000ms
    client.heartbeat.incoming = 0; ? ? ?// client does not want to receive heartbeats from the server
    // The heart-beating is using window.setInterval() to regularly send heart-beats and/or check server heart-beats

    發送信息
    連接成功后,客戶端可使用 send() 方法向服務器發送信息:

    client.send(destination url[, headers[, body]]);

    其中?
    destination url 為服務器 controller中 @MessageMapping 中匹配的URL,字符串,必須參數;?
    headers 為發送信息的header,JavaScript 對象,可選參數;?
    body 為發送信息的 body,字符串,可選參數;

    例:

    client.send("/queue/test", {priority: 9}, "Hello, STOMP");
    client.send("/queue/test", {}, "Hello, STOMP");

    ?

    訂閱、接收信息

    STOMP 客戶端要想接收來自服務器推送的消息,必須先訂閱相應的URL,即發送一個 SUBSCRIBE 幀,然后才能不斷接收來自服務器的推送消息;?
    訂閱和接收消息通過 subscribe() 方法實現:

    subscribe(destination url, callback[, headers])

    其中?
    destination url 為服務器 @SendTo 匹配的 URL,字符串;?
    callback 為每次收到服務器推送的消息時的回調方法,該方法包含參數 message;?
    headers 為附加的headers,JavaScript 對象;什么作用??
    該方法返回一個包含了id屬性的 JavaScript 對象,可作為 unsubscribe() 方法的參數;

    例:var headers = {ack: 'client', 'selector': "location = 'Europe'"};
    var ?callback = function(message) {
    ? if (message.body) {
    ? ? alert("got message with body " + message.body)
    ? } else {
    ? ? alert("got empty message");
    ? }
    });
    var subscription = client.subscribe("/queue/test", callback, headers);

    取消訂閱
    var subscription = client.subscribe(...);

    subscription.unsubscribe();
    JSON 支持
    STOMP 幀的 body 必須是 string 類型,若希望接收/發送 json 對象,可通過 JSON.stringify() and JSON.parse() 實現;?
    例:

    var quote = {symbol: 'APPL', value: 195.46};
    client.send("/topic/stocks", {}, JSON.stringify(quote));

    client.subcribe("/topic/stocks", function(message) {
    var quote = JSON.parse(message.body);
    alert(quote.symbol + " is at " + quote.value);
    });


    事務支持


    STOMP 客戶端支持在發送消息時用事務進行處理:?
    舉例說明:

    // start the transaction
    // 該方法返回一個包含了事務 id、commit()、abort() 的JavaScript 對象
    var tx = client.begin();
    // send the message in a transaction
    // 最關鍵的在于要在 headers 對象中加入事務 id,若沒有添加,則會直接發送消息,不會以事務進行處理
    client.send("/queue/test", {transaction: tx.id}, "message in a transaction");
    // commit the transaction to effectively send the message
    tx.commit();
    // tx.abort();


    Debug 信息


    STOMP 客戶端默認將傳輸過程中的所有 debug 信息以 console.log() 形式輸出到客戶端瀏覽器中,也可通過以下方式輸出到 DOM 中:

    client.debug = function(str) {
    ? ? // str 參數即為 debug 信息
    // append the debug log to a #debug div somewhere in the page using JQuery:
    $("#debug").append(str + "\n");
    };


    認證


    這一部分內容看的不是很理解,因此直接將原文放在這里了,待補充。?
    By default, STOMP messages will be automatically acknowledged by the server before the message is delivered to the client.

    The client can chose instead to handle message acknowledgement by subscribing to a destination and specify a ack header set to client or client-individual.

    In that case, the client must use the message.ack() method to inform the server that it has acknowledge the message.

    var subscription = client.subscribe("/queue/test",
    ? function(message) {
    ? ? // do something with the message
    ? ? ...
    ? ? // and acknowledge it
    ? ? message.ack();
    ? },
    ? {ack: 'client'}
    );
    The ack() method accepts a headers argument for additional headers to acknowledge the message. For example, it is possible to acknowledge a message as part of a transaction and ask for a receipt when the ACK STOMP frame has effectively be processed by the broker:?
    var tx = client.begin();?
    message.ack({ transaction: tx.id, receipt: ‘my-receipt’ });?
    tx.commit();?
    The nack() method can also be used to inform STOMP 1.1 brokers that the client did not consume the message. It takes the same arguments than the ack() method.

    參考博文:https://blog.csdn.net/jqsad/article/details/77745379

    ?

    同 HTTP 在 TCP 套接字上添加請求-響應模型層一樣,STOMP 在 WebSocket 之上提供了一個基于幀的線路格式層,用來定義消息語義;

    ?

    ?

    ?

    補充知識2:websocket:

    首先HTTP有1.1和1.0之說,也就是所謂的keep-alive,把多個HTTP請求合并為一個,但是Websocket其實是一個新協議,跟HTTP協議基本沒有關系,只是為了兼容現有瀏覽器的握手規范而已,也就是說它是HTTP協議上的一種補充可以通過這樣一張圖理解:


    重點:兩個關鍵(主動推送信息,持久連接)

    二、Websocket是什么樣的協議,具體有什么優點
    首先,Websocket是一個持久化的協議,相對于HTTP這種非持久的協議來說。
    簡單的舉個例子吧,用目前應用比較廣泛的PHP生命周期來解釋。
    1) HTTP的生命周期通過Request來界定,也就是一個Request 一個Response,那么HTTP1.0,這次HTTP請求就結束了。
    在HTTP1.1中進行了改進,使得有一個keep-alive,也就是說,在一個HTTP連接中,可以發送多個Request,接收多個Response。
    但是請記住 Request = Response , 在HTTP中永遠是這樣,也就是說一個request只能有一個response。而且這個response也是被動的,不能主動發起。

    教練,你BB了這么多,跟Websocket有什么關系呢?
    _(:з」∠)_好吧,我正準備說Websocket呢。。
    首先Websocket是基于HTTP協議的,或者說借用了HTTP的協議來完成一部分握手。
    在握手階段是一樣的
    -------以下涉及專業技術內容,不想看的可以跳過lol:,或者只看加黑內容--------
    首先我們來看個典型的Websocket握手(借用Wikipedia的。。)

    GET /chat HTTP/1.1 Host: server.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== Sec-WebSocket-Protocol: chat, superchat Sec-WebSocket-Version: 13 Origin: http://example.com

    熟悉HTTP的童鞋可能發現了,這段類似HTTP協議的握手請求中,多了幾個東西。
    我會順便講解下作用。

    Upgrade: websocket Connection: Upgrade

    這個就是Websocket的核心了,告訴Apache、Nginx等服務器:注意啦,窩發起的是Websocket協議,快點幫我找到對應的助理處理~不是那個老土的HTTP。

    Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== Sec-WebSocket-Protocol: chat, superchat Sec-WebSocket-Version: 13

    首先,Sec-WebSocket-Key 是一個Base64 encode的值,這個是瀏覽器隨機生成的,告訴服務器:泥煤,不要忽悠窩,我要驗證尼是不是真的是Websocket助理。
    然后,Sec_WebSocket-Protocol 是一個用戶定義的字符串,用來區分同URL下,不同的服務所需要的協議。簡單理解:今晚我要服務A,別搞錯啦~
    最后,Sec-WebSocket-Version 是告訴服務器所使用的Websocket Draft(協議版本),在最初的時候,Websocket協議還在 Draft 階段,各種奇奇怪怪的協議都有,而且還有很多期奇奇怪怪不同的東西,什么Firefox和Chrome用的不是一個版本之類的,當初Websocket協議太多可是一個大難題。。不過現在還好,已經定下來啦~大家都使用的一個東西~ 脫水:服務員,我要的是13歲的噢→_→

    然后服務器會返回下列東西,表示已經接受到請求, 成功建立Websocket啦!

    HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat

    這里開始就是HTTP最后負責的區域了,告訴客戶,我已經成功切換協議啦~

    Upgrade: websocket Connection: Upgrade

    依然是固定的,告訴客戶端即將升級的是Websocket協議,而不是mozillasocket,lurnarsocket或者shitsocket。
    然后,Sec-WebSocket-Accept 這個則是經過服務器確認,并且加密過后的 Sec-WebSocket-Key。服務器:好啦好啦,知道啦,給你看我的ID CARD來證明行了吧。。
    后面的,Sec-WebSocket-Protocol 則是表示最終使用的協議。

    至此,HTTP已經完成它所有工作了,接下來就是完全按照Websocket協議進行了。
    具體的協議就不在這闡述了。

    你TMD又BBB了這么久,那到底Websocket有什么鬼用,http long poll,或者ajax輪詢不都可以實現實時信息傳遞么。

    好好好,年輕人,那我們來講一講Websocket有什么用。
    來給你吃點胡(蘇)蘿(丹)卜(紅)



    三、Websocket的作用
    在講Websocket之前,我就順帶著講下 long poll 和 ajax輪詢 的原理。
    首先是 ajax輪詢 ,ajax輪詢 的原理非常簡單,讓瀏覽器隔個幾秒就發送一次請求,詢問服務器是否有新信息。
    場景再現:
    客戶端:啦啦啦,有沒有新信息(Request)
    服務端:沒有(Response)
    客戶端:啦啦啦,有沒有新信息(Request)
    服務端:沒有。。(Response)
    客戶端:啦啦啦,有沒有新信息(Request)
    服務端:你好煩啊,沒有啊。。(Response)
    客戶端:啦啦啦,有沒有新消息(Request)
    服務端:好啦好啦,有啦給你。(Response)
    客戶端:啦啦啦,有沒有新消息(Request)
    服務端:。。。。。沒。。。。沒。。。沒有(Response) ---- loop(一直循環)

    ?

    long poll
    long poll 其實原理跟 ajax輪詢 差不多,都是采用輪詢的方式,不過采取的是阻塞模型一直打電話,沒收到就不掛電話),也就是說,客戶端發起連接后,如果沒消息,就一直不返回Response給客戶端。直到有消息才返回,返回完之后,客戶端再次建立連接,周而復始。
    場景再現
    客戶端:啦啦啦,有沒有新信息,沒有的話就等有了才返回給我吧(Request)
    服務端:額。。 等待到有消息的時候。。來 給你(Response)
    客戶端:啦啦啦,有沒有新信息,沒有的話就等有了才返回給我吧(Request) -loop

    從上面可以看出其實這兩種方式,都是在不斷地建立HTTP連接,然后等待服務端處理,可以體現HTTP協議的另外一個特點,被動性。
    何為被動性呢,其實就是,服務端不能主動聯系客戶端,只能有客戶端發起。

    簡單地說就是,服務器是一個很懶的冰箱(這是個梗)(不會、不能主動發起連接),但是上司有命令,如果有客戶來,不管多么累都要好好接待。說完這個,我們再來說一說上面的缺陷(原諒我廢話這么多吧OAQ)
    從上面很容易看出來,不管怎么樣,上面這兩種都是非常消耗資源的
    ajax輪詢 需要服務器有很快的處理速度和資源。(速度)
    long poll 需要有很高的并發,也就是說同時接待客戶的能力。(場地大小)
    所以ajax輪詢 和long poll 都有可能發生這種情況。
    客戶端:啦啦啦啦,有新信息么?
    服務端:月線正忙,請稍后再試(503 Server Unavailable)
    客戶端:。。。。好吧,啦啦啦,有新信息么?
    服務端:月線正忙,請稍后再試(503 Server Unavailable)
    然后服務端在一旁忙的要死:冰箱,我要更多的冰箱!更多。。更多。。(我錯了。。這又是梗。。)
    ?

    言歸正傳,我們來說Websocket吧
    通過上面這個例子,我們可以看出,這兩種方式都不是最好的方式,需要很多資源。
    一種需要更快的速度,一種需要更多的'電話'。這兩種都會導致'電話'的需求越來越高。
    哦對了,忘記說了HTTP還是一個無狀態協議。(感謝評論區的各位指出OAQ)
    通俗的說就是,服務器因為每天要接待太多客戶了,是個健忘鬼,你一掛電話,他就把你的東西全忘光了,把你的東西全丟掉了。你第二次還得再告訴服務器一遍。

    所以在這種情況下出現了,Websocket出現了。
    他解決了HTTP的這幾個難題。
    首先,被動性當服務器完成協議升級后(HTTP->Websocket),服務端就可以主動推送信息給客戶端啦。
    所以上面的情景可以做如下修改。
    客戶端:啦啦啦,我要建立Websocket協議,需要的服務:chat,Websocket協議版本:17(HTTP Request)
    服務端:ok,確認,已升級為Websocket協議(HTTP Protocols Switched)
    客戶端:麻煩你有信息的時候推送給我噢。。
    服務端:ok,有的時候會告訴你的。
    服務端:balabalabalabala
    服務端:balabalabalabala
    服務端:哈哈哈哈哈啊哈哈哈哈
    服務端:笑死我了哈哈哈哈哈哈哈

    就變成了這樣,只需要經過一次HTTP請求,就可以做到源源不斷的信息傳送了。(在程序設計中,這種設計叫做回調,即:你有信息了再來通知我,而不是我傻乎乎的每次跑來問你)
    這樣的協議解決了上面同步有延遲,而且還非常消耗資源的這種情況。

    ?

    ?

    那么為什么他會解決服務器上消耗資源的問題呢?
    其實我們所用的程序是要經過兩層代理的,即HTTP協議在Nginx等服務器的解析下,然后再傳送給相應的Handler(PHP等)來處理。
    簡單地說,我們有一個非常快速的接線員(Nginx),他負責把問題轉交給相應的客服(Handler)處理器
    本身接線員基本上速度是足夠的,但是每次都卡在客服(Handler)了,老有客服處理速度太慢。,導致客服不夠。
    Websocket就解決了這樣一個難題,建立后,可以直接跟接線員建立持久連接,有信息的時候客服想辦法通知接線員,然后接線員在統一轉交給客戶。
    這樣就可以解決客服處理速度過慢的問題了。

    同時,在傳統的方式上,要不斷的建立,關閉HTTP協議,由于HTTP是非狀態性的,每次都要重新傳輸identity info(鑒別信息),來告訴服務端你是誰。
    雖然接線員很快速,但是每次都要聽這么一堆,效率也會有所下降的,同時還得不斷把這些信息轉交給客服,不但浪費客服的處理時間,而且還會在網路傳輸中消耗過多的流量/時間。
    但是Websocket只需要一次HTTP握手,所以說整個通訊過程是建立在一次連接/狀態中,也就避免了HTTP的非狀態性,服務端會一直知道你的信息,直到你關閉請求,這樣就解決了接線員要反復解析HTTP協議,還要查看identity info的信息。
    同時由客戶主動詢問,轉換為服務器(推送)有信息的時候就發送(當然客戶端還是等主動發送信息過來的。。),沒有信息的時候就交給接線員(Nginx),不需要占用本身速度就慢的客服(Handler)

    參考:https://www.zhihu.com/question/20215561

    ?

    ?

    補充3:stomp.js客戶端(Stomp Over Webscoket)

    ?

    ?

    ?

    ?

    ?

    總結

    以上是生活随笔為你收集整理的使用springboot来实现WebLog的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。