1. 程式人生 > >[有圖有真相]IDEA下的Maven工程讀取properties等資原始檔的路徑問題

[有圖有真相]IDEA下的Maven工程讀取properties等資原始檔的路徑問題

僅供參考,如有錯誤或不足歡迎留言指正。

我們以maven的web專案為例:
這裡寫圖片描述
接下來我們看看工程結構:這裡只討論src目錄和target目錄
src目錄:

  • src/main/java: java:起初生成maven專案時並沒有這個resource資料夾,是建立maven專案後手動新增進去的,用於存放java原始檔
  • src/main/resources:存放專案的各種資源(如圖片文字之類的)及全域性配置檔案
  • src/main/webapp:webapp目錄是web目錄所特有的目錄,不作詳細介紹

target目錄:
- classes:這個就是classpath目錄,即存放java位元組碼檔案以及相關配置檔案(如properties檔案)的根目錄,後面會用程式碼演示資原始檔的路徑及相關知識
target目錄下的其他目錄不再做介紹,與本文討論的知識並無多大關係。

src 與 target: src/main/下的java檔案下的.java檔案編譯後的.class檔案及resources檔案相關資原始檔都會在target/classes中。

關於java的位元組碼檔案存放位置: target/classes目錄下會生成對應的相關位元組碼檔案及相關的包資料夾
關於src/main/resources檔案:這是一個專門存放各類資訊檔案的配置資料夾,筆者曾犯的一個錯誤就是將配置檔案放在了java目錄下,導致始終無法獲取配置檔案的輸入流

說完了相關檔案介紹,我們進入正題:
首先介紹兩個方法:getResource(String filePath)getResourceAsStream(String filePath)


getResource(String filePath):下面上程式碼:
這裡寫圖片描述
分析:通過執行結果我們可以看到通過Class類物件呼叫getResource(String filePath)方法獲取的路徑是classes檔案下的類路徑但不包含類本身;而通過ClassLoader類呼叫的getResource(String filePath)方法,則輸出到classpath的根目錄。

ok,說到此處,我覺得有上 API文件的必要了。我們來看看Class和ClassLoader類的getResource(),getResourceAsStream()方法:
Class類的getResource()和getResourceAsStream():

getResource()方法註釋:
<li> If the {@code name} begins with a {@code '/'}
* (<tt>'&#92;u002f'</tt>), then the absolute name of the resource is the
* portion of the {@code name} following the {@code '/'}
* <li> Otherwise, the absolute name is of the following form:
* <blockquote>
* {@code modified_package_name/name}
* </blockquote>
* <p> Where the {@code modified_package_name} is the package name of this object with {@code '/'} substituted for {@code '.'}
* (<tt>'&#92;u002e'</tt>).

大致意思是:如果路徑名(也就是filePath)以 “/” 開頭,那麼資源的絕對路徑名是檔案路徑的一部分。否則,其路徑名為 “包名/檔名”,最後還特別說明了一下:包名的點被 “/”所替代掉。
getResourceAsStream()註釋的資源路徑說明與getResource()方法相同,可以自己區查閱API文件。

ClassLoader類的getResource()和getResourceAsStream():
getResource()註釋:

* Finds the resource with the given name.  A resource is some data(images, audio, text, etc) that can be accessed by class code in a way that is independent of the location of the code.
     * <p> The name of a resource is a '<tt>/</tt>'-separated path name that
     * identifies the resource.
     * <p> This method will first search the parent class loader for the
     * resource; if the parent is <tt>null</tt> the path of the class loader
     * built-in to the virtual machine is searched.  That failing, this method
     * will invoke {@link #findResource(String)} to find the resource.  </p>

大致意思是:通過給定的名字搜尋資源。這些資源指的是那些可以通過一種不依賴java程式碼的方式而被java檔案所接收的資源(例如:圖片,音訊,文字等等)。關於搜尋規則,其中提到了一個關鍵點:首先搜尋父目錄(位元組碼目錄classes)。通過這點,我們已經可以知道該方法的filepath開頭是不加”/”的,即從classes目錄開始搜尋。而關於getResourceAsStream()的搜尋規則,文件註釋中說與getResource()一樣,在此就不再貼註釋了。

說的再多,不如貼程式碼來的直接:
首先在如圖mysql.properties檔案位置:
這裡寫圖片描述

同時呢,我們可以在classes下看到相關的資料夾config及mysql.properties檔案:
這裡寫圖片描述

前面我們提到過,資源的路徑取的是classpath(即類載入路徑)下的路徑。接下來我們要討論的是分別通過Class及ClassLoader類的getResourceAsStream()方法獲取mysql.properites檔案流從而獲取資料。

public class Test {
    public static void main(String[] args) throws Exception {
        getStreamByClass("/config/mysql.properties");
        getStreamByClassLoader("config/mysql.properties");
    }
    public static void getStreamByClass(String filePath) throws Exception {
        //通過Class的getResourceAsStream()獲取properties檔案輸入流
        InputStream in = Test.class.getResourceAsStream(filePath);
        //當然,也可以通過例項獲取Class物件
        InputStream in1 = new Test().getClass().getResourceAsStream(filePath);
        printProperties(in);
        printProperties(in1);
    }
    public static void getStreamByClassLoader(String filePath) throws Exception {
        //通過ClassLoader的getResourceAsStream()獲取輸入流
        InputStream in = Test.class.getClassLoader().getResourceAsStream(filePath);
        //同樣的,通過例項也可以獲取ClassLoader物件
        InputStream in1 = new Test().getClass().getClassLoader().getResourceAsStream(filePath);
        printProperties(in);
        printProperties(in1);
    }
    public static void printProperties(InputStream in) throws Exception {
        Properties pro = new Properties();
        pro.load(in);
        System.out.println("url: " + pro.getProperty("url")
                         + "user: " + pro.getProperty("user")
                         + "password: " + pro.getProperty("password"));
    }
}

執行結果如下:
這裡寫圖片描述