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

 更新时间:2022年03月05日 14:28:26   作者:kl  
这篇文章主要为大家介绍了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依赖

<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的资料请关注脚本之家其它相关文章!

相关文章

  • spring boot使用WebClient调用HTTP服务代码示例

    spring boot使用WebClient调用HTTP服务代码示例

    这篇文章主要介绍了spring boot使用WebClient调用HTTP服务代码示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12
  • Java实现阿里云短信接口的示例

    Java实现阿里云短信接口的示例

    这篇文章主要介绍了Java实现阿里云短信接口的示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • @JsonFormat处理LocalDateTime失效的问题

    @JsonFormat处理LocalDateTime失效的问题

    这篇文章主要介绍了关于@JsonFormat处理LocalDateTime失效的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-08-08
  • Java8新特性之泛型的目标类型推断_动力节点Java学院整理

    Java8新特性之泛型的目标类型推断_动力节点Java学院整理

    泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。下面通过本文给分享Java8新特性之泛型的目标类型推断,感兴趣的朋友参考下吧
    2017-06-06
  • SpringCloud Nacos + Ribbon 调用服务的实现方式(两种)

    SpringCloud Nacos + Ribbon 调用服务的实现方式(两种)

    这篇文章主要介绍了SpringCloud Nacos + Ribbon 调用服务的两种方法,分别是通过代码的方式调用服务和通过注解方式调用服务,每种方式给大家介绍的非常详细,需要的朋友可以参考下
    2022-03-03
  • SpringBoot无法使用jkd8问题的解决方法

    SpringBoot无法使用jkd8问题的解决方法

    这篇文章主要介绍了SpringBoot无法使用jkd8问题的解决方法,文中通过图文结合的形式给大家讲解的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2024-12-12
  • Springboot整合Mybatis传值的常用方式总结

    Springboot整合Mybatis传值的常用方式总结

    今天给大家带来的是关于Springboot的相关知识,文章围绕着Springboot整合Mybatis传值的常用方式展开,文中有非常详细的介绍及代码示例,需要的朋友可以参考下
    2021-06-06
  • Spring事务管理下synchronized锁失效问题的解决方法

    Spring事务管理下synchronized锁失效问题的解决方法

    这篇文章主要给大家介绍了关于Spring事务管理下synchronized锁失效问题的解决方法,文中通过示例代码介绍的非常详细,对大家学习或者使用Spring具有一定的参考学习价值,需要的朋友可以参考下
    2022-03-03
  • Springboot如何读取resources下的json配置文件

    Springboot如何读取resources下的json配置文件

    这篇文章主要介绍了Springboot如何读取resources下的json配置文件问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-07-07
  • Java实现随机出题,10道10以内加减法计算代码实例

    Java实现随机出题,10道10以内加减法计算代码实例

    这篇文章主要介绍了Java实现随机出题,10道10以内加减法计算,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-04-04

最新评论