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资源 ...
随机推荐
- td 中设置超出宽度显示省略号失效
td测试内容超出显示省略号时,结果没有显示省略号,而是一直往后显示,且超出了td大小,强行挤大了table. 原因是因为td默认不换行. 解决方法: 1.强制td换行. IE加上word-break: ...
- YTU 2453: 我想有套北京的房
2453: 我想有套北京的房 时间限制: 1 Sec 内存限制: 128 MB 提交: 796 解决: 289 题目描述 小原是一个软件工程师,名叫原黛玛,他在北京工作.现在有一套房子,价格200 ...
- zoj 3204 Connect them(最小生成树)
题意:裸最小生成树,主要是要按照字典序. 思路:模板 prim: #include<iostream> #include<stdio.h> #include<string ...
- 使用TextView实现跑马灯的效果
1.定义textView标签的4个属性: android:singleLine="true"//使其只能单行 android:ellipsize="marquee&quo ...
- org.apache.hadoop.hbase.NotServingRegionException: Region is not online 错误
当遇到如下错误的时候 可能以为是regionserver 挂掉或者其他原因导致连接不上regionserver 但后面提示了Hbase 表statistic_login 具体信息 Thu Jan 1 ...
- 使用SVPullToRefresh实现下拉刷新和下拉加载
移动端开发中,“下拉刷新”和“上拉加载更多”早已在各大App中随处可见.也非常容易就能找到直接可供使用的第三方资源.譬如EGOTableViewPullRefresh(下拉刷新)和LoadMoreTa ...
- 微信小程序-B站:wxml和wxss文件
WXML WXML(WeiXin Markup Language)是微信的一套标签语言,结合基础组件.事件系统,可以构建出页面的结构. (小安娜:好像很厉害的样子,那基础组件.事件系统是什么?感觉更厉 ...
- SpringBoot启动的时候不去校验数据库连接配置是否正确
spring boot在启动的时候只会检查你是否配置了数据库连接, 而不会检测配置的是否正确 这样会出现的问题是: 只有在你使用数据库的时候才知道配置出错, 我们希望是在程序启动的时候就进行检查, 如 ...
- Cardboard对像的公共方法与属性
一. public Pose3D EyePose(Eye eye)/// The transformation from head to eye. 获取眼睛在头部坐标系中的局部transform: ...
- [WPF自定义控件库] 自定义控件的代码如何与ControlTemplate交互
1. 前言 WPF有一个灵活的UI框架,用户可以轻松地使用代码控制控件的外观.例设我需要一个控件在鼠标进入的时候背景变成蓝色,我可以用下面这段代码实现: protected override void ...