首頁 > 軟體

spring boot整合WebSocket紀錄檔實時輸出到web頁面

2022-03-05 16:01:21

前言

今天來做個有趣的東西,就是實時將系統紀錄檔輸出的前端web頁面,因為是實時輸出,所有第一時間就想到了使用webSocket,而且在spring boot中,使用websocket超級方便,閱讀本文,你會接觸到以下關鍵詞相關技術,WebSocket(stopmp伺服器端),stomp協定,sockjs.min.js,stomp.min.js(stomp使用者端),本文使用到的其實就是使用spring boot自帶的webSocket模組提供stomp的伺服器端,前端使用stomp.min.js做stomp的使用者端,使用sockjs來連結,前端訂閱後端紀錄檔端點的訊息,後端實時推播,達到紀錄檔實時輸出到web頁面的目的,效果如下圖

首先了解下stomp

STOMP即Simple (or Streaming) Text Orientated Messaging Protocol,簡單(流)文字定向訊息協定,它提供了一個可互操作的連線格式,允許STOMP使用者端與任意STOMP訊息代理(Broker)進行互動。STOMP協定由於設計簡單,易於開發使用者端,因此在多種語言和多種平臺上得到廣泛地應用。

STOMP協定的前身是TTMP協定(一個簡單的基於文字的協定),專為訊息中介軟體設計。
STOMP是一個非常簡單和容易實現的協定,其設計靈感源自於HTTP的簡單性。儘管STOMP協定在伺服器端的實現可能有一定的難度,但使用者端的實現卻很容易。例如,可以使用Telnet登入到任何的STOMP代理,並與STOMP代理進行互動。

下面是具體的步驟,主要是紀錄檔資訊的獲取和紀錄檔資訊的推播,不多說,上程式碼

一.引入spring boot websocket依賴

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

二.新增紀錄檔訊息實體

/**
 * Created by kl on 2017/10/9.
 * Content :紀錄檔訊息實體,注意,這裡為了減少篇幅,省略了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() {
    }
}

三. 建立一個阻塞佇列

作為紀錄檔系統輸出的紀錄檔的一個臨時載體

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

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

四.獲取logback的紀錄檔,塞入紀錄檔佇列中

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訊息代理端點,即stomp伺服器端

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

注意:為了連線安全,setAllowedOrigins設定的允許連線的源地址,如果在非這個設定的地址下發起連線會報403,進一步還可以使用addInterceptors設定攔截器,來做相關的鑑權操作

六.啟動類,開啟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("測試紀錄檔輸出"+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頁面,連線stomp伺服器端,訂閱/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()">開啟紀錄檔</button><button onclick="closeSocket()">關閉紀錄檔</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頁面實時輸出的詳細內容,更多關於spring boot整合WebSocket實時輸出到web的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com