好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

spring boot集成WebSocket日志实时输出到web页面

前言

今天来做个有趣的东西,就是实时将系统日志输出的前端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依赖

?

1

2

3

4

< dependency >

             < groupId >org.springframework.boot</ groupId >

             < artifactId >spring-boot-starter-websocket</ artifactId >

</ dependency >

二.新增日志消息实体

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

/**

  * 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() {

     }

}

三. 创建一个阻塞队列

作为日志系统输出的日志的一个临时载体

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

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拦截输出日志

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

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

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

<? 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服务端

?

1

2

3

4

5

6

7

8

9

@Configuration

public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer{

     @Override

     public void registerStompEndpoints(StompEndpointRegistry registry) {

         registry.addEndpoint( "/websocket" )

                 .setAllowedOrigins( "http://localhost:8976" )

                 .withSockJS();

     }

}

注意:为了连接安全,setAllowedOrigins设置的允许连接的源地址,如果在非这个配置的地址下发起连接会报403,进一步还可以使用addInterceptors设置拦截器,来做相关的鉴权操作

六.启动类,开启webSocket消息代理功能,并推送日志信息

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

@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的消息,展示日志信息

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

<!DOCTYPE html>

< html >

< head >

     < meta charset = "utf-8" >

     < title >WebSocket Logger</ title >

     < script src = "https://cdn.bootcss测试数据/jquery/2.1.4/jquery.js" ></ script >

     < script src = "https://cdn.bootcss测试数据/sockjs-client/1.1.4/sockjs.min.js" ></ script >

     < script src = "https://cdn.bootcss测试数据/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测试数据/sockjs/sockjs-client

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

以上就是spring boot集成WebSocket到web页面实时输出的详细内容,更多关于spring boot集成WebSocket实时输出到web的资料请关注其它相关文章!

原文链接:http://HdhCmsTestkailing.pub/article/index/arcid/164.html

查看更多关于spring boot集成WebSocket日志实时输出到web页面的详细内容...

  阅读:72次