IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> springboot + websocket + html(获取centos服务器当前运行jar包的实时日志) -> 正文阅读

[网络协议]springboot + websocket + html(获取centos服务器当前运行jar包的实时日志)

①首先创建websocket服务器

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * @Author YMG
 * @Date 2021/7/16 11:05
 * @Description :
 */
@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thymeleaf.util.StringUtils;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author YMG
 * @Date 2021/7/22 18:37
 * @Description :
 */
@SuppressWarnings(value = {"all"})
@Slf4j
@Component
@ServerEndpoint(value = "/websocket/log")
public class WebsocketLoggingServer {

    private Process process;
    private InputStream inputStream;

    /**
     * 连接集合
     */
    private static final Map<String, Session> SESSION_MAP = new ConcurrentHashMap<>();
    private static final Map<String, Integer> LENGTH_MAP = new ConcurrentHashMap<>();

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session) {
        //添加到集合中
        SESSION_MAP.put(session.getId(), session);
        //默认从第一行开始
        LENGTH_MAP.put(session.getId(), 1);
        //获取日志信息
        new Thread(() -> {
            log.info("WebSocketLoggingServer 任务开始");
            boolean first = true;
            while (SESSION_MAP.get(session.getId()) != null) {
                BufferedReader reader = null;
                try {
                    // 执行tail -f命令,填写自己的 服务器日志地址,得到流解析
                    process = Runtime.getRuntime().exec("tail -n 200 nohup.log");
                    inputStream = process.getInputStream();
                    //字符流
                    reader = new BufferedReader(new InputStreamReader(inputStream));
                    Object[] lines = reader.lines().toArray();

                    //只取从上次之后产生的日志
                    Object[] copyOfRange = Arrays.copyOfRange(lines, LENGTH_MAP.get(session.getId()), lines.length);

                    //对日志进行着色,更加美观  PS:注意,这里要根据日志生成规则来操作
                    for (int i = 0; i < copyOfRange.length; i++) {
                        String line = (String) copyOfRange[i];
                        //先转义
                        line = line.replaceAll("&", "&amp;")
                                .replaceAll("<", "&lt;")
                                .replaceAll(">", "&gt;")
                                .replaceAll("\"", "&quot;");
                        //处理等级
                        line = line.replace("DEBUG", "<span style='color: blue;'>DEBUG</span>");
                        line = line.replace("INFO", "<span style='color: green;'>INFO</span>");
                        line = line.replace("WARN", "<span style='color: orange;'>WARN</span>");
                        line = line.replace("ERROR", "<span style='color: red;'>ERROR</span>");
                        //处理类名
                        String[] split = line.split("]");
                        if (split.length >= 2) {
                            String[] split1 = split[1].split("-");
                            if (split1.length >= 2) {
                                line = split[0] + "]" + "<span style='color: #298a8a;'>" + split1[0] + "</span>" + "-" + split1[1];
                            }
                        }
                        copyOfRange[i] = line;
                    }
                    //存储最新一行开始
                    LENGTH_MAP.put(session.getId(), lines.length);
                    //截取最新的200行,避免传输的数据太大
                    if (first && copyOfRange.length > 200) {
                        copyOfRange = Arrays.copyOfRange(copyOfRange, copyOfRange.length - 200, copyOfRange.length);
                        first = false;
                    }
                    String result = StringUtils.join(copyOfRange, "<br/>");
                    //发送
                    send(session, result);
                    Thread.sleep(1000);
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    try {
                        reader.close();
                    } catch (IOException ignored) {
                    }
                }
            }
            log.info("WebSocketLoggingServer 任务结束");
        }).start();
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(Session session) {
        //从集合中删除
        SESSION_MAP.remove(session.getId());
        LENGTH_MAP.remove(session.getId());
    }

    /**
     * 发生错误时调用
     */
    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }

    /**
     * 服务器接收到客户端消息时调用的方法
     */
    @OnMessage
    public void onMessage(String message, Session session) {
    }

    /**
     * 封装一个send方法,发送消息到前端
     */
    private void send(Session session, String message) {
        try {
            session.getBasicRemote().sendText(message);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

②html页面连接websocket服务器获取日志展示,由于我们用的是thymeleaf模版,请注意静态资源的导入方式(用到了jquery+layui)可以自行操作

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>logging</title>

    <!-- 引入公用部分 -->
    <script th:src="@{/static/jquery.js}"></script>
    <link rel="stylesheet" th:href="@{/static/layui/css/layui.css}">
    <script th:src="@{/static/layui/layui.js}"></script>
</head>
<body>


<!-- 显示区 -->
<div id="loggingText" contenteditable="true"
     style="width:100%;height: 890px;padding:0 30px;box-sizing:border-box;background-color: ghostwhite; overflow: auto;">
</div>

<!-- 操作栏 -->
<div style="text-align: center;" class="layui-btn-container">

    <button class="layui-btn" onclick="$('#loggingText').text('')">清屏
    </button>
    <button class="layui-btn" onclick="$('#loggingText').animate({scrollTop:$('#loggingText')[0].scrollHeight});">滚动至底部
    </button>
    <button class="layui-btn" onclick="if(window.loggingAutoBottom){$(this).text('开启自动滚动');}else{$(this).text('关闭自动滚动');}
    window.loggingAutoBottom = !window.loggingAutoBottom">开启自动滚动
    </button>
</div>
</body>

<script>
    //websocket对象
    let websocket;

    //判断当前浏览器是否支持WebSocket
    if ('WebSocket' in window) {
        //服务器IP+端口 
        websocket = new WebSocket("ws://127.0.0.1:9027/websocket/log");
    } else {
        console.error("不支持WebSocket");
    }
    //连接发生错误的回调方法
    websocket.onerror = function () {
        console.error("WebSocket连接发生错误");
    };

    //连接成功建立的回调方法
    websocket.onopen = function () {
        console.log("WebSocket连接成功")
    };

    //接收到消息的回调方法
    websocket.onmessage = function (event) {
        //追加
        if (event.data) {

            //日志内容
            let $loggingText = $("#loggingText");
            $loggingText.append(event.data);

            //是否开启自动底部
            if (window.loggingAutoBottom) {
                //滚动条自动到最底部
                $loggingText.scrollTop($loggingText[0].scrollHeight);
            }
        }
    }

    //连接关闭的回调方法
    websocket.onclose = function () {
        console.log("WebSocket连接关闭")
    };
</script>
</html>

以下是静态资源+HTML页面地址

由于这个项目用到了拦截器,要配置静态资源及页面放行?地址

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ResourceUtils;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

/**
 * @Author YMG
 * @Date 2021/6/2 16:35
 * @Description :
 */
@Configuration
public class InterceptorConfig extends WebMvcConfigurationSupport {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authenticationInterceptor())
                .addPathPatterns("/**")
                /*放行所有请求*/
                .excludePathPatterns("/**");
    }


    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        /*放行静态资源与页面*/
        registry.addResourceHandler("/templates/**").addResourceLocations(ResourceUtils.CLASSPATH_URL_PREFIX+"/templates/");
        registry.addResourceHandler("/static/**").addResourceLocations(ResourceUtils.CLASSPATH_URL_PREFIX+"/static/");
        super.addResourceHandlers(registry);

    }

    
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        /*解决请求跨域*/
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("POST", "GET", "PUT", "DELETE")
                .allowCredentials(true)
                .allowedHeaders("*")
                .maxAge(3600);
    }

    @Bean
    public AuthenticationInterceptor authenticationInterceptor() {
        return new AuthenticationInterceptor();
    }
}

③编写访问controller

import com.zh.wisdom.config.security.token.PassToken;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

/**
 * @Author YMG
 * @Date 2021/7/16 11:18
 * @Description :
 */
@RestController
@RequestMapping(value = "/websocket")
public class WebsocketController {

    @PassToken
    @GetMapping("/log")
    public ModelAndView index(){
        return new ModelAndView("log");
    }

    @PassToken
    @GetMapping("/page")
    public ModelAndView page(){
        return new ModelAndView("test");
    }


}

④项目打包部署到服务器,然后本地访问controller查看日志

访问地址"服务器ip:端口/websocket/log"

最终呈现效果如下

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-07-24 11:51:07  更:2021-07-24 11:52:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/7 1:33:35-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码