Springboot + Websocket + Sockjs + Stomp + Vue + Iview 实现java后端日志显示在前端web页面上
话不多说,看代码。
一、pom.xml 引入spring boot websocket依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
二、WebSocketConfig 配置WebSocket消息代理端点,即stomp服务端
@Slf4j
@Configuration
@EnableWebSocketMessageBroker // 注解开启STOMP协议来传输基于代理的消息,此时控制器支持使用
@MessageMapping
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer
{
@Autowired
private SimpMessagingTemplate messagingTemplate; // 测试
// int info = 1;
//
// @Scheduled(fixedRate = 4000)
// public void outputLogger()
// {
// log.info("测试日志输出" + info++);
// } @Override
public void registerStompEndpoints(StompEndpointRegistry registry)
{
// 将clientMessage注册为STOMP的一个端点
// 客户端在订阅或发布消息到目的路径前,要连接该端点
// setAllowedOrigins允许所有域连接,否则浏览器可能报403错误
registry.addEndpoint("/websocket").setAllowedOrigins("*").addInterceptors().withSockJS(); //
} /**
* 推送日志到/topic/pullLogger
*/
@PostConstruct
public void pushLogger()
{
ExecutorService executorService = Executors.newFixedThreadPool(4);
Runnable fileLog = new Runnable()
{
@Override
public void run()
{
while (true)
{
try
{
String log = LoggerQueue.getInstance().poll().toString();
if (log != null)
{
if (messagingTemplate != null)
messagingTemplate.convertAndSend("/topic/pullFileLogger", log);
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
};
executorService.submit(fileLog);
executorService.submit(fileLog);
}
}
三、新增日志消息实体
/*
* 日志消息实体类,这里用了lombok插件
* 没有安装该插件的话,就手动添加get、set方法、toString方法
*/
@Getter
@Setter
@ToString
@AllArgsConstructor
public class LoggerMessage
{
private String body;
private String timestamp;
private String threadName;
private String className;
private String level;
private String exception;
private String cause;
}
四、创建一个阻塞队列,作为日志系统输出的日志的一个临时载体
/*
* 创建一个阻塞队列,作为日志系统输出的日志的一个临时载体
*/
public class LoggerQueue
{
// 队列大小
public static final int QUEUE_MAX_SIZE = 10000;
private static LoggerQueue alarmMessageQueue = new LoggerQueue();
// 阻塞队列
private BlockingQueue blockingQueue = 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 = (LoggerMessage) this.blockingQueue.take();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
return result;
}
}
五、获取logback的日志,塞入日志队列中
1.定义Logfilter拦截输出日志
@Service
public class LogFilter extends Filter<ILoggingEvent>
{
@Override
public FilterReply decide(ILoggingEvent event)
{
String exception = "";
IThrowableProxy iThrowableProxy1 = event.getThrowableProxy();
if (iThrowableProxy1 != null)
{
exception = "<span class='excehtext'>" + iThrowableProxy1.getClassName() + " " + iThrowableProxy1.getMessage() + "</span></br>";
for (int i = 0; i < iThrowableProxy1.getStackTraceElementProxyArray().length; i++)
{
exception += "<span class='excetext'>" + iThrowableProxy1.getStackTraceElementProxyArray()[i].toString() + "</span></br>";
}
}
LoggerMessage loggerMessage = new LoggerMessage(event.getMessage(), DateFormat.getDateTimeInstance().format(new Date(event.getTimeStamp())), event.getThreadName(), event.getLoggerName(),
event.getLevel().levelStr, exception, "");
LoggerQueue.getInstance().push(loggerMessage);
return FilterReply.ACCEPT;
}
}
2.配置logback-spring.xml,添加我们自定义的filter
<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文档如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文档是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。
当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration scan="true" scanPeriod="10 seconds">
<contextName>logback</contextName>
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<include resource="org/springframework/boot/logging/logback/file-appender.xml" />
<!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义后,可以使“${}”来使用变量。 -->
<property name="log.path" value="/var/log/" /> <!--0. 日志格式和颜色渲染 -->
<!-- 彩色日志依赖的渲染类 -->
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
<conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
<!-- 彩色日志格式 -->
<property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/> <!--1. 输出到控制台-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
<!-- <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>info</level>
</filter> -->
<encoder>
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
<!-- 设置字符集 -->
<charset>UTF-8</charset>
</encoder>
<!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
<filter class="com.hmkj.ddos.config.LogFilter">
</filter>
</appender> <!-- 2.2 level为 INFO 日志,时间滚动输出 -->
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/hmddos.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天日志归档路径以及格式 -->
<fileNamePattern>${log.path}/web-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录info级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>info</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender> <root level="info">
<appender-ref ref="CONSOLE" />
<appender-ref ref="INFO_FILE" />
</root>
</configuration>
六、Vue中添加基于webSocket通信的库
先安装 sockjs-client 和 stompjs
注意: 在安装stompjs出现一个问题,net 模块不存在,则应该在项目根目录再执行npm install net 即可。
npm install sockjs-client
npm install stompjs
.vue页面
<template>
<div>
<Card dis-hover>
4 <p slot="title" style="padding-bottom: 20px; padding-top: 5px;">
监听程序日志
6 </p>
<Button type="primary" @click="openSocket">开启日志</Button>
<Button type="error" @click="closeSocket">关闭日志</Button><br><br>
<div id="filelog-container" style="height: 400px; overflow-y: scroll; background: #333; color: #aaa; padding: 10px;">
<div id="aa">{{pullFileLogger}}</div>
</div>
</Card>
</div>
</template> <script>
// 安装并引入相关模块
import SockJS from 'sockjs-client';
import Stomp from 'stompjs';
export default {
data(){
return {
pullLogger: '',
pullFileLogger: '正在连接websocket,请稍后~',
stompClient: null
}
},
methods:{
openSocket () {
if (this.stompClient === null) {
console.log('打开websocket连接')
this.pullFileLogger = '正在连接websocket,请稍后~'
let _that = this
var socket = new SockJS('http://localhost:7788/websocket?token=kl');
_that.stompClient = Stomp.over(socket);
_that.stompClient.connect({token:"kl"}, function(frame) {
_that.stompClient.subscribe('/topic/pullFileLogger', function(event) {
_that.pullFileLogger = ''
var content = event.body
var aa = document.getElementById('aa')
var p = document.createElement('p')
p.style.wordWrap = 'break-word'
p.style.fontSize = 18 + 'px'
p.appendChild(document.createTextNode(event.body))
aa.appendChild(p)
var div1 = document.getElementById('filelog-container')
div1.scrollTop = div1.scrollHeight
}, {
token:"kltoen"
})
})
}
},
closeSocket () {
if (this.stompClient != null) {
this.stompClient.disconnect()
this.stompClient = null
console.log("关闭websocket连接")
this.pullFileLogger = 'websocket连接已关闭'
}
}
},
//销毁页面之前,断开连接
beforeDestroy: function () {
//页面离开时断开连接,清除定时器
this.closeSocket()
},
mounted(){
//调用初始化websocket方法
this.openSocket()
}
}
</script>
<style>
</style>
七、效果图,字体颜色背景颜色可以自行修改样式。
有什么不对的地方欢迎大家评论指点。
Springboot + Websocket + Sockjs + Stomp + Vue + Iview 实现java后端日志显示在前端web页面上的更多相关文章
- springboot+websocket+sockjs进行消息推送【基于STOMP协议】
springboot+websocket+sockjs进行消息推送[基于STOMP协议] WebSocket是在HTML5基础上单个TCP连接上进行全双工通讯的协议,只要浏览器和服务器进行一次握手,就 ...
- java后端无法接收到前端传递的json对象
java后端无法接收到前端传递的json对象 一·可能是因为未使用@RequestBody 在Controller层中,要么使用@RestController要么使用@Controller+@@Req ...
- springboot实现服务器端消息推送(websocket + sockjs + stomp)
服务器端推送技术在web开发中比较常用,可能早期很多人的解决方案是采用ajax向服务器轮询消息,这种方式的轮询频率不好控制,所以大大增加了服务器的压力,后来有了下面的方案:当客户端向服务器发送请求时, ...
- springBoot -webSocket 基于STOMP协议交互
浅谈WebSocket WebSocket是在HTML5基础上单个TCP连接上进行全双工通讯的协议,只要浏览器和服务器进行一次握手,就可以建立一条快速通道,两者就可以实现数据互传了.说白了,就是打破了 ...
- SpringBoot WebSocket STOMP 广播配置
目录 1. 前言 2. STOMP协议 3. SpringBoot WebSocket集成 3.1 导入websocket包 3.2 配置WebSocket 3.3 对外暴露接口 4. 前端对接测试 ...
- springboot之websocket,STOMP协议
一.WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议. WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据.在 ...
- springboot支持webSocket和stomp实现消息订阅通知示例
先导入支持websocket的jar包,这里用Gradle构建的项目: dependencies { compile('org.springframework.boot:spring-boot-sta ...
- Java Springboot webSocket简单实现,调接口推送消息到客户端socket
Java Springboot webSocket简单实现,调接口推送消息到客户端socket 后台一般作为webSocket服务器,前台作为client.真实场景可能是后台程序在运行时(满足一定条件 ...
- SpringBoot WebSocket 消息交互
1. Websocket原理 Websocket协议本质上是一个基于TCP的独立协议,能够在浏览器和服务器之间建立双向连接,以基于消息的机制,赋予浏览器和服务器间实时通信能力. WebSocket资源 ...
随机推荐
- Kafka在Windows安装运行
摘要:本文主要说明了如何在Windows安装运行Kafka 一.安装JDK 过程比较简单,这里不做说明. 最后打开cmd输入如下内容,表示安装成功 二.安装zooeleeper 下载安装包:http: ...
- HDU1569 方格取数(2) —— 二分图点带权最大独立集、最小割最大流
题目链接:https://vjudge.net/problem/HDU-1569 方格取数(2) Time Limit: 10000/5000 MS (Java/Others) Memory L ...
- ES6 解构赋值的常见用途,很强大
字符串 var [a,b,c,d,e] = "hello"; console.log(a); // h console.log(b); // e console.log(c); / ...
- 一步一步学Silverlight 2系列(10):使用用户控件
概述 Silverlight 2 Beta 1版本发布了,无论从Runtime还是Tools都给我们带来了很多的惊喜,如支持框架语言Visual Basic, Visual C#, IronRuby, ...
- JQuery判断div(控件)是否为隐藏
以下是JavaScript 中判断div是否为隐藏代码引用片段: if (div.style.display == "none") { div.style.display = &q ...
- 用/proc/stat计算cpu的占用率
转自:http://blog.csdn.net/pppjob/article/details/4060336 在Linux下,CPU利用率分为用户态,系统态和空闲态,分别表示CPU处于用户态执行的时间 ...
- RDA TDT & TOT
首先看下面的TS PSI分析图: 注意:TOT UTC与TDT是一致的 TDT下的时间为: UTC+手动TIMEZONE TOT下的时间为: UTC+解析的time_offset time_offes ...
- 固定dll的加载基址的方法
调试dll的时候会有一件事情比较烦人,就是dll加载的地址不会很固定(默认设置下编译的dll基址总是0x10000000,多个同基址的dll加载时,后面的肯定会被重定位),这给前后多次调试时对比分析结 ...
- Get与Post的小知识
Get与Post的小知识 一.传递参数: Get把参数包含在URL中,而在Post通过request body传递参数.因为参数直接暴露在URL上,GET比POST更不安全,所以不能用来传递敏感信息. ...
- Collection View Programming Guide for iOS---(四)---Using the Flow Layout
Using the Flow Layout使用流布局 The UICollectionViewFlowLayout class is a concrete layout object that y ...