從零構建可視化jar包部署平臺JarManage

来源:https://www.cnblogs.com/yanpeng19940119/archive/2023/04/01/17279025.html
-Advertisement-
Play Games

項目背景 在java項目部署過程中,由於內外部各種因素,可能會遇到一些感覺操作不便捷的場景,例如 jar包未隨系統自動啟動需要每次手動重啟 系統vpn堡壘機多重防禦更新繁瑣 系統無圖形化界面命令行操作複雜 等等...... 在工作中之前也總結了windows的Jar包部署工具與linux下的jar包 ...


項目背景

在java項目部署過程中,由於內外部各種因素,可能會遇到一些感覺操作不便捷的場景,例如

  • jar包未隨系統自動啟動需要每次手動重啟
  • 系統vpn堡壘機多重防禦更新繁瑣
  • 系統無圖形化界面命令行操作複雜
  • 等等......

在工作中之前也總結了windows的Jar包部署工具linux下的jar包自動化部署腳本,這次就想著否能將二者統一結合,本著簡單/高效/功能專一的原則,做出一

個可視化jar包部署平臺,JarManage應運而生

功能介紹

項目地址:https://gitee.com/code2roc/jar-manage

支持線上創建項目,上傳Jar包,自動備份,配置啟動參數,註冊系統服務,查看啟動日誌等功能,具有以下優點

  • 基於servlet開發,依賴簡潔,部署包10MB左右
  • 結合嵌入式tomcat一鍵部署,無外部容器依賴
  • 使用h2db存儲數據,無外部資料庫依賴
  • 適配windows/linux平臺,滿足多種環境
  • 具體項目經平臺部署後自動註冊系統服務,無需擔心伺服器重啟

系統架構圖如下

系統截圖展示

技術分析

平臺識別

首先通過系統os識別是windows平臺還是linux平臺

String os = System.getProperty("os.name").toLowerCase();
if (os.startsWith("win")) {
   platform = DepolyPlatform.Windows;
}

通過system-release文件識別部分基於CentOS開發的Linux系統

String command = "cat /etc/system-release";
String result = CMDUtil.executeLinuxCommand(command);
if (result.startsWith("Red Hat")) {
   platform = DepolyPlatform.LinuxRedHat;
} else if (result.startsWith("CentOS")) {
   platform = DepolyPlatform.LinuxCentOS;
} else if (result.startsWith("openEuler")) {
   platform = DepolyPlatform.LinuxOpenEuler;
}

通過issue文件識別部分基於Ubuntu/Debian開發的Linux系統

command = "cat /etc/issue";
result = CMDUtil.executeLinuxCommand(command);
if (!StringUtil.isEmpty(result)) {
  if (result.startsWith("Ubuntu")) {
     platform = DepolyPlatform.LinuxUbuntu;
} else if (result.startsWith("Debian")) {
      platform = DepolyPlatform.LinuxDebian;
   }
}

windows註冊服務

通過sc query命令判斷服務狀態

    public String getStatus(String serviceName) {
        String status = DepolyStatus.UnInstall;
        try {
            String command = "sc query " + serviceName;
            String commandResultFilePath = CMDUtil.executeWindowCommandStoreFile(command);
            BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(commandResultFilePath)));
            String line = reader.readLine();
            while (line != null) {
                if (line.trim().startsWith("STATE")) {
                    if (line.trim().substring(line.trim().indexOf(":") + 1, line.trim().indexOf(":") + 4).trim().equals("1"))
                        status = DepolyStatus.Stopped;
                    else if (line.trim().substring(line.trim().indexOf(":") + 1, line.trim().indexOf(":") + 4).trim().equals("2"))
                        status = DepolyStatus.Startting;
                    else if (line.trim().substring(line.trim().indexOf(":") + 1, line.trim().indexOf(":") + 4).trim().equals("3"))
                        status = DepolyStatus.Stopping;
                    else if (line.trim().substring(line.trim().indexOf(":") + 1, line.trim().indexOf(":") + 4).trim().equals("4"))
                        status = DepolyStatus.Running;
                }
                line = reader.readLine();
            }
        } catch (IOException e) {
            LogUtil.error(e);
        }
        return status;
    }

通過winsw這個開源項目配置exe和xml文件將jar包註冊為windows服務,項目地址:https://github.com/winsw/winsw/

linux註冊服務

通過systemctl status命令判斷服務狀態

    public String getStatus(String serviceName) {
        String status = DepolyStatus.UnInstall;
        try {
            String command = "systemctl status " + serviceName;
            String commandResultFilePath = CMDUtil.executeLinuxCommandWithStore(command);
            BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(commandResultFilePath)));
            String line = reader.readLine();
            while (line != null) {
                if (line.trim().startsWith("Active")) {
                    if (line.trim().indexOf("inactive (dead)") > 0)
                        status = DepolyStatus.Stopped;
                    else if (line.trim().indexOf("active (running)") > 0)
                        status = DepolyStatus.Running;
                    else if (line.trim().indexOf("failed") > 0)
                        status = DepolyStatus.Stopped;
                }
                line = reader.readLine();
            }
        } catch (IOException e) {
            LogUtil.error(e);
        }
        return status;
    }

通過拷貝service文件到systemd/system目錄下註冊linux服務

yml配置文件識別

  • maven配置
        <dependency>
            <groupId>org.yaml</groupId>
            <artifactId>snakeyaml</artifactId>
            <version>1.26</version>
        </dependency>
  • 配置文件
jarmanage:
  port: 8555
  username: admin
  password: abcd@1234
  backupcount: 5
  • 工具類
    public static String getConfigValue(String configName){
        String configValue = "";
        try{
            Yaml yaml = new Yaml();
            InputStream resourceAsStream = new FileInputStream(new File("resources"+File.separator+"application.yml"));
            Map obj = yaml.load(resourceAsStream);
            Map<String,Object> param = (Map) obj.get("jarmanage");
            configValue = ConvertUtil.convert2String(param.get(configName));
        }catch (Exception e){
            LogUtil.error(e);
        }
        return configValue;
    }

h2database使用

  • maven引用
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>2.1.214</version>
        </dependency>
  • 工具類
    public static Connection getConnection() throws Exception {
        File file = new File("database");
        Connection conn = DriverManager.getConnection("jdbc:h2:file:" + file.getAbsolutePath() + File.separator + "manage", "root", "abcd@1234");
        return conn;
    }
    
    public static void executeSQL(String sql) {
        try {
            Connection conn = getConnection();
            Statement stmt = conn.createStatement();
            stmt.execute(sql);
            stmt.close();
            conn.close();
        } catch (Exception e) {
            LogUtil.error(e);
        }
    }

servelt內置tomcat打包

  • maven引用
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
            <version>9.0.35</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-el</artifactId>
            <version>9.0.35</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <version>9.0.35</version>
        </dependency>
  • 手動啟動
            //啟動tomcat服務
            // 1.創建一個內嵌的Tomcat
            Tomcat tomcat = new Tomcat();
            // 2.設置Tomcat埠
            tomcat.setPort(8555);
            // 3.設置工作目錄,tomcat需要使用這個目錄進行寫一些東西
            final String baseDir = "workspace" + File.separator;
            tomcat.setBaseDir(baseDir);
            tomcat.getHost().setAutoDeploy(false);
            // 4. 設置webapp資源路徑
            String webappDirLocation = "webapp" + File.separator;
            StandardContext ctx = (StandardContext) tomcat.addWebapp("/", new File(webappDirLocation).getAbsolutePath());
            // 5. 設置上下文路每徑
            String contextPath = "";
            ctx.setPath(contextPath);
            ctx.addLifecycleListener(new Tomcat.FixContextListener());
            ctx.setName("jar-manage");
            tomcat.getHost().addChild(ctx);
            //6.啟動
            tomcat.getConnector();
            tomcat.start();
            tomcat.getServer().await();
  • 打包包含引用類庫,自定義配置xml,指定運行class
        <plugins>
            <plugin>
                <!-- 打包包含引用 -->
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <descriptors>
                        <!-- 自定義配置 -->
                        <descriptor>package.xml</descriptor>
                    </descriptors>
                    <archive>
                        <manifest>
                            <!-- 運行類 -->
                            <mainClass>com.code2roc.jarmanage.Application</mainClass>
                        </manifest>
                    </archive>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
        </plugins>
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.1"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.1 https://maven.apache.org/xsd/assembly-2.1.1.xsd">
    <!-- TODO: a jarjar format would be better -->
    <id>depoly</id>
    <formats>
        <format>jar</format>
    </formats>
    <includeBaseDirectory>false</includeBaseDirectory>
    <dependencySets>
        <dependencySet>
            <outputDirectory>/</outputDirectory>
            <useProjectArtifact>true</useProjectArtifact>
            <unpack>true</unpack>
            <scope>runtime</scope>
        </dependencySet>
    </dependencySets>
    <fileSets>
        <fileSet>
            <directory>src/main/webapp/</directory>
            <outputDirectory>/webapp</outputDirectory>
            <includes>
                <include>**/**</include>
            </includes>
        </fileSet>
        <fileSet>
            <directory>src/main/resources/</directory>
            <outputDirectory>/resources</outputDirectory>
            <includes>
                <include>**/**</include>
            </includes>
        </fileSet>
    </fileSets>
</assembly>


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 說明 有讀者反饋: 學習uniapp ios 插件開發不知道從哪些文章看起,沒有一個清晰的學習路線 本文就做一個解答。 首先本系列的文章是作者精心排過序的,如果想要完整的學習uniapp ios原生插件開發技術的話,建議是按文章順序瀏覽。 當然您如果有相關的開發經驗,且只對某一技術實現感興趣的話,也 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 最近碰到這樣一個問題,在一張封面上直接顯示書名,可能會存在書名看不太清楚的情況(容易受到背景干擾),如下 為瞭解決這個問題,設計師提了一個“究極”方案,將書名背後的圖片模糊一下,這個在 CSS 中很好實現,僅需backdrop-filte ...
  • 路由守衛 作用:對路由進行許可權控制 配置路由守衛應在暴露前配置 分類:全局守衛、獨享守衛、組件內守衛 首先先給需要鑒權的路由設置好meta配置項。 meta配置項:是vue-router中的一個對象,主要用於存儲路由的元數據(meta data)信息。這些元數據信息可以是一些描述性的內容,比如頁面的 ...
  • 泛型、Trait、生命周期 一、提取函數消除重覆 fn main() { let number_list = vec![34, 50, 25, 100, 65]; let mut largest = number_list[0]; for number in number_list { if num ...
  • Spring是什麼? Spring是一個輕量級的控制反轉(IoC)和麵向切麵(AOP)的容器框架。 Spring的優點 通過控制反轉和依賴註入實現松耦合。 支持面向切麵的編程,並且把應用業務邏輯和系統服務分開。 通過切麵和模板減少樣板式代碼。 聲明式事務的支持。可以從單調繁冗的事務管理代碼中解脫出來 ...
  • 無論對於什麼業務來說,用戶數據信息的安全性無疑都是非常重要的。尤其是在數字經濟大火背景下,數據的安全性就顯得更加重要。數據脫敏可以分為兩個部分,一個是DB層面,防止DB數據泄露,暴露用戶信息;一個是介面層面,有些UI展示需要數據脫敏,防止用戶信息被人刷走了。 v需求背景 DB層面的脫敏今天先不講,今 ...
  • 去年公司由於不斷發展,內部自研系統越來越多,所以後來搭建了一個日誌收集平臺,並將日誌收集功能以二方包形式引入各個自研系統,避免每個自研系統都要建立一套自己的日誌模塊,節約了開發時間,管理起來也更加容易。 這篇文章主要介紹如何編寫二方包,並整合到各個系統中。 先介紹整個ELK日誌平臺的架構。其中xia ...
  • 今天我來分享一個關於日誌的問題和解法。 問題 沒有界面的後端程式在實際運行中發生了什麼事,通常是通過日誌來探查。所以日誌非常重要。資料庫記錄了程式運行的結果,日誌記錄了程式運行的過程。但是日誌經常出現一個問題,日誌量太多,以至於把重要的日誌淹沒在裡面。未能及時地發現問題,或者當有問題出現的時候,在日 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...