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资源 ...
随机推荐
- KbmMW资源汇总(特别是xalion的文章)
KbmMW框架是收费的,不在此提供下载,如需购买,请自行联系作者Kim Madsen. 网址资源: 官网主页:http://www.components4programmers.com/product ...
- webpack与grunt/glub 的比较
webpack.grunt.glub 都是前端打包的工具: grunt/gulp 的工作方式是:在一个配置文件中,指明对某些文件进行压缩.组合.检查等任务的具体步骤,然后在运行中输入相应的命令. we ...
- maven配置本地仓库和国内镜像仓库,解决国内访问国外中央仓库速度过慢问题
Maven项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的软件项目管理工具. 1.配置本地仓库 打开conf文件夹下面的setting.xml文件 红色方框为配置本地仓 ...
- fuse的编译安装(Centos7-minimal)
打算寒假在家跟着THU的一个分布式系统的课程:http://thu-cmu.cs.tsinghua.edu.cn/curriculum/dscourse/schedule.htm 第0个lab就是要在 ...
- opencv直方图该怎么画
图像直方图是反映图像中像素分布特性的统计表,一般显示如下: 其中横坐标代表的是图像像素的种类,或者说是灰度级,纵坐标代表的是每一级灰度下像素数或者该灰度级下像素数在所有图像总像素数总所占的百分比. 直 ...
- Laravel中常见的错误与解决方法小结
一.报错: 「Can't swap PDO instance while within transaction」 通过查询 Laravel 源代码,可以确认异常是在 setPdo 方法中抛出的: ? ...
- 一些好用的Linux命令组合
1.删除0字节文件 代码如下: find -type f -size 0 -exec rm -rf {} \; 2.查看进程按内存从大到小排列 代码如下: ps -e -o "%C : %p ...
- E20180407-hm
queue n. (人或车辆) 行列,长队; 辫子; vi. (人.车等) 排队等候; vt. (使) 排队,列队等待; compatible adj. 兼容的,相容的; 和谐的,协调的 ...
- poj 2406 Power Strings【kmp】
kmp,根据next数组的性质如果有答案的话就是n/(n-(ne[n]+1)),否则是1 搬来打算用SA后来发现必须用DC3就没写 #include<iostream> #include& ...
- div 四周都有阴影的写法
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...