欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

spring?boot集成WebSocket日志實(shí)時(shí)輸出到web頁(yè)面

 更新時(shí)間:2022年03月05日 14:28:26   作者:kl  
這篇文章主要為大家介紹了spring?boot集成WebSocket日志實(shí)時(shí)輸出到web頁(yè)面展示的詳細(xì)操作,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步

前言

今天來(lái)做個(gè)有趣的東西,就是實(shí)時(shí)將系統(tǒng)日志輸出的前端web頁(yè)面,因?yàn)槭菍?shí)時(shí)輸出,所有第一時(shí)間就想到了使用webSocket,而且在spring boot中,使用websocket超級(jí)方便,閱讀本文,你會(huì)接觸到以下關(guān)鍵詞相關(guān)技術(shù),WebSocket(stopmp服務(wù)端),stomp協(xié)議,sockjs.min.js,stomp.min.js(stomp客戶端),本文使用到的其實(shí)就是使用spring boot自帶的webSocket模塊提供stomp的服務(wù)端,前端使用stomp.min.js做stomp的客戶端,使用sockjs來(lái)鏈接,前端訂閱后端日志端點(diǎn)的消息,后端實(shí)時(shí)推送,達(dá)到日志實(shí)時(shí)輸出到web頁(yè)面的目的,效果如下圖

首先了解下stomp

STOMP即Simple (or Streaming) Text Orientated Messaging Protocol,簡(jiǎn)單(流)文本定向消息協(xié)議,它提供了一個(gè)可互操作的連接格式,允許STOMP客戶端與任意STOMP消息代理(Broker)進(jìn)行交互。STOMP協(xié)議由于設(shè)計(jì)簡(jiǎn)單,易于開(kāi)發(fā)客戶端,因此在多種語(yǔ)言和多種平臺(tái)上得到廣泛地應(yīng)用。

STOMP協(xié)議的前身是TTMP協(xié)議(一個(gè)簡(jiǎn)單的基于文本的協(xié)議),專(zhuān)為消息中間件設(shè)計(jì)。
STOMP是一個(gè)非常簡(jiǎn)單和容易實(shí)現(xiàn)的協(xié)議,其設(shè)計(jì)靈感源自于HTTP的簡(jiǎn)單性。盡管STOMP協(xié)議在服務(wù)器端的實(shí)現(xiàn)可能有一定的難度,但客戶端的實(shí)現(xiàn)卻很容易。例如,可以使用Telnet登錄到任何的STOMP代理,并與STOMP代理進(jìn)行交互。

下面是具體的步驟,主要是日志信息的獲取和日志信息的推送,不多說(shuō),上代碼

一.引入spring boot websocket依賴(lài)

<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

二.新增日志消息實(shí)體

/**
 * Created by kl on 2017/10/9.
 * Content :日志消息實(shí)體,注意,這里為了減少篇幅,省略了get,set代碼
 */
public class LoggerMessage{
    private String body;
    private String timestamp;
    private String threadName;
    private String className;
    private String level;
    public LoggerMessage(String body, String timestamp, String threadName, String className, String level) {
        this.body = body;
        this.timestamp = timestamp;
        this.threadName = threadName;
        this.className = className;
        this.level = level;
    }
    public LoggerMessage() {
    }
}

三. 創(chuàng)建一個(gè)阻塞隊(duì)列

作為日志系統(tǒng)輸出的日志的一個(gè)臨時(shí)載體

public class LoggerQueue {
    //隊(duì)列大小
    public static final int QUEUE_MAX_SIZE = 10000;
    private static LoggerQueue alarmMessageQueue = new LoggerQueue();
    //阻塞隊(duì)列
    private BlockingQueueblockingQueue = new LinkedBlockingQueue<>(QUEUE_MAX_SIZE);

    private LoggerQueue() {
    }
    public static LoggerQueue getInstance() {
        return alarmMessageQueue;
    }
    /**
     * 消息入隊(duì)
     * @param log
     * @return
     */
    public boolean push(LoggerMessage log) {
        return this.blockingQueue.add(log);//隊(duì)列滿了就拋出異常,不阻塞
    }
    /**
     * 消息出隊(duì)
     * @return
     */
    public LoggerMessage poll() {
        LoggerMessage result = null;
        try {
            result = this.blockingQueue.take();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return result;
    }
}

四.獲取logback的日志,塞入日志隊(duì)列中

1.定義Logfilter攔截輸出日志

public class LogFilter extends Filter{
    @Override
    public FilterReply decide(ILoggingEvent event) {
        LoggerMessage loggerMessage = new LoggerMessage(
                event.getMessage()
                , DateFormat.getDateTimeInstance().format(new Date(event.getTimeStamp())),
                event.getThreadName(),
                event.getLoggerName(),
                event.getLevel().levelStr
        );
        LoggerQueue.getInstance().push(loggerMessage);
        return FilterReply.ACCEPT;
    }
}

2.配置logback.xml,添加我們自定義的filter

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true">
    <include resource="org/springframework/boot/logging/logback/defaults.xml" />
    <property name="LOG_FILE"
              value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}spring.log}" />
    <include resource="org/springframework/boot/logging/logback/file-appender.xml" />
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
        <filter class="com.example.websocket.LogFilter"></filter>
    </appender>
    <root level="INFO">
        <appender-ref ref="FILE" />
        <appender-ref ref="CONSOLE" />
    </root>
</configuration>

五.配置WebSocket消息代理端點(diǎn),即stomp服務(wù)端

@Configuration
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer{
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/websocket")
                .setAllowedOrigins("http://localhost:8976")
                .withSockJS();
    }
}

注意:為了連接安全,setAllowedOrigins設(shè)置的允許連接的源地址,如果在非這個(gè)配置的地址下發(fā)起連接會(huì)報(bào)403,進(jìn)一步還可以使用addInterceptors設(shè)置攔截器,來(lái)做相關(guān)的鑒權(quán)操作

六.啟動(dòng)類(lèi),開(kāi)啟webSocket消息代理功能,并推送日志信息

@SpringBootApplication
@EnableScheduling
@EnableWebSocketMessageBroker
public class WebsocketApplication {
	private Logger logger = LoggerFactory.getLogger(WebsocketApplication.class);
	public static void main(String[] args) {
		SpringApplication.run(WebsocketApplication.class, args);
	}
	@Autowired
	private SimpMessagingTemplate messagingTemplate;
    int info=1;
	@Scheduled(fixedRate = 1000)
	public void outputLogger(){
      logger.info("測(cè)試日志輸出"+info++);
	}
	/**
	 * 推送日志到/topic/pullLogger
	 */
	@PostConstruct
	public void pushLogger(){
		ExecutorService executorService=Executors.newFixedThreadPool(2);
		Runnable runnable=new Runnable() {
			@Override
			public void run() {
				while (true) {
					try {
						LoggerMessage log = LoggerQueue.getInstance().poll();
						if(log!=null){
							if(messagingTemplate!=null)
							messagingTemplate.convertAndSend("/topic/pullLogger",log);
						}
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		};
		executorService.submit(runnable);
		executorService.submit(runnable);
	}
}

七.html頁(yè)面,連接stomp服務(wù)端,訂閱/topic/pullLogger的消息,展示日志信息

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>WebSocket Logger</title>
    <script src="https://cdn.bootcss.com/jquery/2.1.4/jquery.js"></script>
    <script src="https://cdn.bootcss.com/sockjs-client/1.1.4/sockjs.min.js"></script>
    <script src="https://cdn.bootcss.com/stomp.js/2.3.3/stomp.min.js"></script>
</head>
<body>
<button onclick="openSocket()">開(kāi)啟日志</button><button onclick="closeSocket()">關(guān)閉日志</button>
<div id="log-container" style="height: 450px; overflow-y: scroll; background: #333; color: #aaa; padding: 10px;">
    <div></div>
</div>
</body>
<script>
    var stompClient = null;
    $(document).ready(function() {openSocket();});
    function openSocket() {
        if(stompClient==null){
            var socket = new SockJS('http://localhost:8084/websocket?token=kl');
            stompClient = Stomp.over(socket);
            stompClient.connect({token:"kl"}, function(frame) {
                stompClient.subscribe('/topic/pullLogger', function(event) {
                    var content=JSON.parse(event.body);
                    $("#log-container div").append(content.timestamp +" "+ content.level+" --- ["+ content.threadName+"] "+ content.className+"   :"+content.body).append("<br/>");
                    $("#log-container").scrollTop($("#log-container div").height() - $("#log-container").height());
                },{
                    token:"kltoen"
                });
            });
        }
    }
    function closeSocket() {
        if (stompClient != null) {
            stompClient.disconnect();
            stompClient=null;
        }
    }
</script>
</body>
</html>

參考地址:

stomp.js客戶端:http://jmesnil.net/stomp-websocket/doc/

scok.js客戶端:https://github.com/sockjs/sockjs-client

spring webSocket:https://docs.spring.io/spring/docs/

以上就是spring boot集成WebSocket到web頁(yè)面實(shí)時(shí)輸出的詳細(xì)內(nèi)容,更多關(guān)于spring boot集成WebSocket實(shí)時(shí)輸出到web的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Spring Data JPA實(shí)現(xiàn)分頁(yè)P(yáng)ageable的實(shí)例代碼

    Spring Data JPA實(shí)現(xiàn)分頁(yè)P(yáng)ageable的實(shí)例代碼

    本篇文章主要介紹了Spring Data JPA實(shí)現(xiàn)分頁(yè)P(yáng)ageable的實(shí)例代碼,具有一定的參考價(jià)值,有興趣的可以了解一下
    2017-07-07
  • Java中Collections.emptyList()的注意事項(xiàng)

    Java中Collections.emptyList()的注意事項(xiàng)

    這篇文章主要給大家介紹了關(guān)于Java中Collections.emptyList()的注意事項(xiàng),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • Java實(shí)現(xiàn)的計(jì)算最大下標(biāo)距離算法示例

    Java實(shí)現(xiàn)的計(jì)算最大下標(biāo)距離算法示例

    這篇文章主要介紹了Java實(shí)現(xiàn)的計(jì)算最大下標(biāo)距離算法,涉及java針對(duì)數(shù)組的遍歷、運(yùn)算等相關(guān)操作技巧,需要的朋友可以參考下
    2018-02-02
  • IDEA中如何移除未使用的包

    IDEA中如何移除未使用的包

    這篇文章主要介紹了IDEA中如何移除未使用的包問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • 簡(jiǎn)單談?wù)凴xJava和多線程并發(fā)

    簡(jiǎn)單談?wù)凴xJava和多線程并發(fā)

    認(rèn)識(shí)RxJava已經(jīng)有一段時(shí)間了,但是一直沒(méi)有機(jī)會(huì)在項(xiàng)目中嘗試,最近在新的項(xiàng)目里引進(jìn)了RxJava寫(xiě)一些事件處理,在review代碼的時(shí)候發(fā)現(xiàn)了一些和多線程并發(fā)相關(guān)的問(wèn)題,所以寫(xiě)了這篇文章,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-03-03
  • Spring2.5.6開(kāi)發(fā)環(huán)境搭建圖文教程

    Spring2.5.6開(kāi)發(fā)環(huán)境搭建圖文教程

    這篇文章主要為大家詳細(xì)介紹了Spring2.5.6開(kāi)發(fā)環(huán)境搭建圖文教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • hotspot解析jdk1.8?Unsafe類(lèi)park和unpark方法使用

    hotspot解析jdk1.8?Unsafe類(lèi)park和unpark方法使用

    這篇文章主要為大家介紹了hotspot解析jdk1.8?Unsafe類(lèi)park和unpark方法使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • Java調(diào)用linux shell腳本的方法

    Java調(diào)用linux shell腳本的方法

    這篇文章主要介紹了Java調(diào)用linux shell腳本的方法,需要的朋友可以參考下
    2015-02-02
  • Java實(shí)現(xiàn)冒泡排序與雙向冒泡排序算法的代碼示例

    Java實(shí)現(xiàn)冒泡排序與雙向冒泡排序算法的代碼示例

    這篇文章主要介紹了Java實(shí)現(xiàn)冒泡排序與雙向冒泡排序算法的代碼示例,值得一提的是所謂的雙向冒泡排序并不比普通的冒泡排序效率來(lái)得高,注意相應(yīng)的時(shí)間復(fù)雜度,需要的朋友可以參考下
    2016-04-04
  • java中反射和注解的簡(jiǎn)單使用方法

    java中反射和注解的簡(jiǎn)單使用方法

    相信大家對(duì)注解和反射應(yīng)該并不陌生,在現(xiàn)在信息飛速發(fā)展的年代,各種優(yōu)秀的框架或許都離不開(kāi)注解的使用,這篇文章主要給大家介紹了關(guān)于java中反射和注解的簡(jiǎn)單使用方法,需要的朋友可以參考下
    2021-08-08

最新評(píng)論