[Java] Windows/Linux路徑不同時,統一war的最簡辦法

来源:https://www.cnblogs.com/zyl910/archive/2018/05/25/java_war_properties_path_easy.html
-Advertisement-
Play Games

作者: "zyl910" 一、緣由 在項目開發時,因為運行環境的不同,導致有時得分別為不同的環境,切換配置參數打不同war包。但手工切換配置文件的話,不僅費時費力,而且容易出錯。 有些打包工具支持配置切換。這樣我們只要配好有那幾組參數,然後便可分別打war包了。但該辦法還是存在多個war文件易搞錯的 ...


作者: zyl910

一、緣由

在項目開發時,因為運行環境的不同,導致有時得分別為不同的環境,切換配置參數打不同war包。但手工切換配置文件的話,不僅費時費力,而且容易出錯。
有些打包工具支持配置切換。這樣我們只要配好有那幾組參數,然後便可分別打war包了。但該辦法還是存在多個war文件易搞錯的問題。而且因為生產環境一般有Windows、Linux 2類操作系統,導致生產環境的war也得分別搞2套,這是否真的有必要。

所以我們希望能統一war。即僅打包一個war,而該war能在各種環境下運行。
雖然可以使用“war 配置文件分離”、“將配置參數放到資料庫”等辦法來實現統一war。但那些辦法比較複雜,而且仍會引起配置文件種類過多問題。

分析了一下 Windows、Linux 不同的配置參數,發現它們一般都是因為路徑不同而被迫做成參數配置的。
於是我針對這種情況,找到了一些簡單、有效的處理辦法。使它們在Windows、Linux切換時不用更改參數,有利於統一war。

二、統一路徑寫法

2.1 問題

對於Windows、Linux 不同的配置參數,最常見的是日誌文件的路徑。例如以下分別是 Linux、Windows 下的日誌目錄——

/mysystem/app1/log
E:\mysystem\app1\log

可見,這2種目錄的目錄結構是類似,僅是因為 Linux、Windows 的路徑格式不同,而有了2點差異——

  1. 文件分隔符不同。Linux(等Unix類)系統用斜杠(/),而Windows系統用反斜杠(\)。
  2. 根目錄寫法不同。Linux(等Unix類)系統是單根的 /,而Windows系統有盤符的概念(如 E:\)。

2.2 辦法

對於操作系統的路徑格式區別,我們可以使用 System.getProperty("file.separator") 得到文件分隔符,使用 File.listRoots() 得到根目錄情況。根據這些信息,我們理論上能寫個函數,將約定好格式的路徑,給翻譯為當前操作系統的路徑格式。

但我後來測試File類時發現,其實有更簡單的辦法的。
File類的2點特性,對我們很有用——

  1. 在給File類的構造函數傳遞 Linux風格的路徑時,會自動轉為當前系統的文件分隔符。例如傳遞 /mysystem/app1/log,隨後File構造好後實際為 \mysystem\app1\log
  2. 在Windows下通過File類打開文件流時,若路徑中沒有盤符,則會自動選擇當前工作目錄(user.dir)的盤符。例如對於 \mysystem\app1\log,假設當前工作目錄是E盤,那麼實際的路徑是 E:\mysystem\app1\log

即File類會自動將 Linux(等Unix類)系統風格的路徑,轉為Windows風格的路徑。只要我們能保證工作目錄的所在盤符,就是所需的盤符。

2.3 應用:logback的日誌路徑

2.3.1 之前

之前在 logback.xml 文件中是這樣指定路徑的。

<property name="LOG_HOME" value="/mysystem/app1/log" />
<!-- <property name="LOG_HOME" value="E:\mysystem\app1\log" /> -->

它預設用Linux的路徑參數,而Windows的路徑參數是處於被註釋的狀態。
然後在需要部署到Windows系統時,調整一下註釋使第2行生效,並根據實際情況調整一下盤符。

2.3.2 之後

現在 logback.xml 文件中只需寫Linux目錄就行。

<property name="LOG_HOME" value="/mysystem/app1/log" />

war包一般是在tomcat等web容器中運行的。對於Windows下,工作目錄的盤符就是web容器所在盤符。

  • 假設該war部署在E盤的tomcat上的,那麼配置文件中的 /mysystem/app1/log,實際上是 E:\mysystem\app1\log
  • 假設該war部署在F盤的weblogic上的,那麼配置文件中的 /mysystem/app1/log,實際上是 F:\mysystem\app1\log

……

2.4 小結

統一路徑寫法是非常簡單的,即只保留Linux(Unix類)路徑寫法就行。這樣大多數程式都能正常工作的。

三、不支持統一路徑寫法時

3.1 問題與思路

有少量程式是不支持統一路徑寫法的寫法(可能是因為它們沒有使用File類來處理文件路徑,而是手工拼接)。這時該怎麼辦呢?

退回之前的“配置切換”法是不行的,容易造成參數複雜等問題。
因Java中能判斷操作系統版本,故可以考慮寫個函數,將統一路徑寫法轉為當前操作系統的格式。這樣便解決問題了。

System.getProperty可獲取系統屬性——

  • os.name: 操作系統的名稱。例如Windows系統都是以 windows 開頭。
  • user.dir: 用戶的當前工作目錄。

3.2 代碼

    /** 判斷是不是Windows系統.
    *
    * @return    返回是不是Windows系統.
    */
    private static boolean isOsWindows() {
        String osname = System.getProperty("os.name").toLowerCase();
        boolean rt = osname.startsWith("windows");
        return rt;
    }

    /** 將路徑修正為當前操作系統所支持的形式.
    *
    * @param path    源路徑.
    * @return    返回修正後的路徑.
    */
    public static String fixPath(String path) {
        if (null==path) return path;
        if (path.length()>=1 && ('/'==path.charAt(0) || '\\'==path.charAt(0))) {
            // 根目錄, Windows下需補上盤符.
            if (isOsWindows()) {
                String userdir = System.getProperty("user.dir");
                if (null!=userdir && userdir.length()>=2) {
                    return userdir.substring(0, 2) + path;
                }
            }
        }
        return  path;
    }

於是可利用fixPath函數,將配置中讀到的路徑,轉為當前操作系統的格式。

四、Linux與Windows下的參數不同時

4.1 問題與思路

上面的辦法主要是適合於路徑結構相同時。可是有些時候,Linux與Windows下的參數不同,例如動態庫的路徑——

/mysystem/app1/libMyLib.so
E:\mysystem\app1\MyLib.dll

它們主要是有這2點差異——

  1. 尾碼名不同。Linux系統用so,而Windows系統用dll。
  2. 文件基本名的命名習慣不同。Linux系統一般有個“lib”首碼。

4.2 辦法

假設動態庫的文件名都是符合命名規範的話,理論上是可以寫個函數將“lib.so”替換為“.dll”的。但是該辦法存在缺點——萬一遇到不符合規範的文件名就麻煩了。

所以建議採用這個辦法——在配置文件中分別給出不同操作系統的參數,然後java端判斷一下操作系統,選擇符合當前操作系統的參數。
不只是動態庫路徑,該辦法還能推廣任何的“Linux與Windows下的參數不同”問題,都可以按此辦法來處理。

隨後會遇到一個小問題——這種參數,因不同操作系統會有多個參數名(如 path.MyLib_windowspath.MyLib_linux)。當取參數時,若都將這些參數名傳過去,代碼會變得很臃腫。而且不易擴充操作系統類型。
所以建議制定一下規範——帶“._windows”尾碼的是Windows特有參數,否則則是預設參數(Linux的)。這樣便簡化了參數名傳遞,且有利於未來增加操作系統的支持。

代碼如下——

    /** 取得字元串_自動選擇操作系統的專用參數, 具有 defaultValue 參數.
    *
    * <ul>
    *    <li>當為Windows時, 優先讀取 {@code key + "._windows"} 參數, 找不到時才用 {@code key} .</li>
    * </ul>
    *
    * @param config    配置對象.
    * @param key    的鍵名.
    * @param defaultValue    預設值.
    * @return    返回所找到的參數值, 找不到時返回 defaultValue .
    */
    public static String getString(AbstractConfiguration config, String key, String defaultValue) {
        String rt = null;
        if (isOsWindows()) {
            String key2 = key+"._windows";
            rt = config.getString(key2, null);
        }
        if (null==rt) {
            rt = config.getString(key, defaultValue);
        }
        return rt;
    }

    /** 取得字元串_自動選擇操作系統的專用參數, 無 defaultValue 參數.
    *
    * <ul>
    *    <li>當為Windows時, 優先讀取 {@code key + "._windows"} 參數, 找不到時才用 {@code key} .</li>
    * </ul>
    *
    * @param config    配置對象.
    * @param key    的鍵名.
    * @return    返回所找到的參數值, 找不到時返回空串.
    */
    public static String getString(AbstractConfiguration config, String key) {
        return  getString(config, key, null);
    }

    /** 取得路徑字元串_自動選擇操作系統的專用參數, 具有 defaultValue 參數. Windows下會自動將根目錄(/)轉為當前盤符的根路徑(E:/) .
    *
    * <ul>
    *    <li>當為Windows時, 優先讀取 {@code key + "._windows"} 參數, 找不到時才用 {@code key} .</li>
    * </ul>
    *
    * @param config    配置對象.
    * @param key    的鍵名.
    * @param defaultValue    預設值.
    * @return    返回所找到的參數值, 找不到時返回 defaultValue .
    */
    public static String getStringPath(AbstractConfiguration config, String key, String defaultValue) {
        String rt = getString(config, key, defaultValue);
        rt = fixPath(rt);
        return rt;
    }

    /** 取得路徑字元串_自動選擇操作系統的專用參數, 無 defaultValue 參數. Windows下會自動將根目錄(/)轉為當前盤符的根路徑(E:/) .
    *
    * <ul>
    *    <li>當為Windows時, 優先讀取 {@code key + "._windows"} 參數, 找不到時才用 {@code key} .</li>
    * </ul>
    *
    * @param config    配置對象.
    * @param key    的鍵名.
    * @return    返回所找到的參數值, 找不到時返回空串.
    */
    public static String getStringPath(AbstractConfiguration config, String key) {
        return  getStringPath(config, key, null);
    }

4.3 用法

4.3.1 之前

之前靠註釋來切換所需配置的。

path.MyLib=/mysystem/app1/libMyLib.so
#path.MyLib=E:\mysystem\app1\MyLib.dll

它預設用Linux的參數,而Windows的參數是處於被註釋的狀態。
然後在需要部署到Windows系統時,調整一下註釋使第2行生效。(已經利用之前的內容,使用統一路徑寫法)

4.3.2 之後

現在可直接在配置文件中寫上這2個參數。註意給Windows版參數加上“._windows”尾碼。

path.MyLib=/mysystem/app1/libMyLib.so
path.MyLib._windows=/mysystem/app1/MyLib.dll

然後在程式中這樣獲取配置了。

String pathMyLib = getStringPath(config, "path.MyLib");

隨後war運行時,會自動根據當前操作系統,選取自己的參數。 保證了war包的統一。

五、總結

回想一下本文的辦法,它其實是“約定大於配置”思想的一種實踐。

(完)

參考文獻


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

-Advertisement-
Play Games
更多相關文章
  • 索引: 開源Spring解決方案--lm.solution 參看代碼 GitHub: solution/pom.xml pojo/pom.xml mapper/pom.xml common/pom.xml service/pom.xml console/pom.xml web/pom.xml web ...
  • 簡單創建json格式文件 核心就兩點: addProperty 添加屬性(也就是加鍵值對) add是添加 另外的object對象 然後直接toString()輸出 核心代碼如下; ...
  • 基本思想 每一趟將一個待排序的記錄,按其關鍵字的大小插入到已經排好序的一組記錄的適當位置上,直到所有待排序記錄全部插入為止。 排序過程 1.初始化無序區、有序區,待排序數組的第一個元素為有序區,剩餘元素為無序區; 2.遍歷無序區,將無序區每一個元素插入到有序區的正確位置上; Java演算法實現 /** ...
  • socket.socket() 可以創建一個套接字: 簡單的發送和接收信息的socket程式. 另: 用 struct.pack() 打包 ,用 unpack() 解包. 還可以直接廣播: ...
  • 1 void vBubbleSort(int arr[], int len){ 2 int i, j, temp; 3 for (j = 0; j arr[i + 1]){ //交換兩個數 6 temp = arr[i]; 7 arr[i] = arr[i + 1]; 8 ... ...
  • nginx反向代理與正向代理 1 正向代理 3 正反向代理的區別 4 nginx的正向代理 5 nginx的反向代理配置 參考文章 : https://blog.csdn.net/hiyun9/article/details/51602428 非常感謝 ...
  • 一.變數 1. 首先我們要做的就是申明一個變數例如: name="xiaohua" name是我們的變數名,xiaohua是我們的變數值 變數時我們臨時儲存和調用 對於數字我們直接是:age=24 請註意,在使用變數前,需要對其賦值,不代表任何值得變數沒有意義。 下麵大家看一下麵這張圖片,想一下a, ...
  • "官方文檔 1.11" 配置 簡易文本郵件 連接一次郵件伺服器發送多份不同的郵件 和 發送多媒體郵件 發送html模板郵件 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...