JavaSE基礎:Properties屬性類

胖先森發表於2019-02-28

Properties

在Java中屬性操作類是一個很重要的類,而要想明白屬性操作類的作用,就必須先要清楚什麼是屬性檔案,在屬性檔案中含有多個屬性,每個屬性就是直接用字串表示出來的"key=value 鍵/值對", 而如果要想輕鬆操作這些屬性需要使用Properties類完成.

1.簡單認識Properties

JavaSE基礎:Properties屬性類

public class Properties extends Hashtable<Object,Object>
複製程式碼
編號 方法名稱 型別 描述
1 public Properties() 構造 建立一個無預設值的空屬性類
2 public Properties(Properties props) 構造 建立一個帶有指定預設值的空屬性類
3 public String getProperty(String key) 普通方法 根據屬性的key取得屬性的value,如果沒有,將放回null
4 public String getProperty(String key, String defaultValue) 普通方法 根據屬性的key取得屬性的value,如果沒有,將返回defaultValue
5 public Object setProperty(String key, String value) 普通方法 設定屬性
6 public void list(PrintStream out) 普通方法 屬性列印
7 public void load(InputStream inStream) 普通方法 將輸入流中取出全部的屬性內容
8 public void loadFromXML(InputStream in) 普通方法 從XML檔案格式中讀取內容
9 public void store(OutputStream out, String comments) 普通方法 將屬性內容通過輸出流輸出,同時宣告屬性的註釋內容
10 public void storeToXML(OutputStream os, String comment) 普通方法 以XML檔案格式輸出屬性,預設編碼
11 public void storeToXML(OutputStream os, String comment, String encoding) 普通方法 以XML檔案格式輸出屬性,使用者指定預設編碼

實際開發中我們使用Properties的功能類似於儲存的資料為Map<String,String>都是字串的形式

2.Properties的操作例項

示例1:設定和取得屬性

主要使用setProperty()和getProperty()方法設定和獲取屬性,儲存的資料型別都是String

package com.shxt.demo06;

import java.util.Properties;

public class Demo01 {
    public static void main(String[] args) {
        Properties props = new Properties(); //建立Properties物件
        //設定屬性
        props.setProperty("title","胖先森部落格");
        props.setProperty("version","v1.0");
        props.setProperty("db","MySQL 5.7");

        //獲取屬性
        System.out.println("1.title屬性存在:"+props.getProperty("title"));
        System.out.println("2.name屬性不存在:"+props.getProperty("name"));
        System.out.println("3.name屬性不存在,顯示預設值:"+props.getProperty("name","胖先森"));

    }
}
/*
	執行結果:
		1.title屬性存在:胖先森部落格
        2.name屬性不存在:null
        3.name屬性不存在,顯示預設值:胖先森
*/
複製程式碼

示例2:儲存屬性到普通的屬性檔案

package com.shxt.demo06;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;

public class Demo02 {
    public static void main(String[] args) {
        Properties props = new Properties(); //建立Properties物件
        //設定屬性
        props.setProperty("title","胖先森部落格");
        props.setProperty("version","v1.0");
        props.setProperty("db","MySQL 5.7");

        //設定屬性檔案的儲存路徑,使用絕對路徑
        //關於檔案的操作,我們在後面J2EE檔案上傳的時候會再次說明
        File file = new File("D:/sys.properties");
        try {
            props.store(new FileOutputStream(file),"system config");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
複製程式碼

執行結果:

JavaSE基礎:Properties屬性類

說明:如果是中文會使用Unicode進行轉換

示例3:從屬性檔案中讀取內容

package com.shxt.demo06;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;

public class Demo03 {
    public static void main(String[] args) {
        Properties props = new Properties(); //建立Properties物件

        //跟磁碟中的檔案建立聯絡
        File file = new File("D:/sys.properties");
        try {
            //讀取屬性檔案
            props.load(new FileInputStream(file));
            //獲取屬性
            System.out.println("getProperty():"+props.getProperty("title"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
/*
	執行結果:
		getProperty():胖先森部落格
*/
複製程式碼

下面的簡單瞭解就好

示例4:將屬性檔案儲存到XML檔案中

package com.shxt.demo06;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;

public class Demo04 {
    public static void main(String[] args) {
        Properties props = new Properties(); //建立Properties物件
        //設定屬性
        props.setProperty("title","胖先森部落格");
        props.setProperty("version","v1.0");
        props.setProperty("db","MySQL 5.7");

        //跟磁碟中的檔案建立聯絡,檔案的字尾名必須為.xml
        File file = new File("D:/sys.xml");
        try {
            props.storeToXML(new FileOutputStream(file),"system config");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
複製程式碼

執行結果:

JavaSE基礎:Properties屬性類

示例5:從XML檔案中讀取屬性

package com.shxt.demo06;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;

public class Demo05 {
    public static void main(String[] args) {
        Properties props = new Properties(); //建立Properties物件

        //跟磁碟中的檔案建立聯絡
        File file = new File("D:/sys.xml");
        try {
            //讀取XML檔案
            props.loadFromXML(new FileInputStream(file));
            //獲取屬性
            System.out.println("getProperty():"+props.getProperty("title"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
/*
	執行結果:
		getProperty():胖先森部落格
*/
複製程式碼

3.認識Properties檔案

  • properties檔案是一個文字檔案
  • properties檔案的語法有兩種,一種是註釋,一種屬性配置。
    • 註釋:前面加上#號
    • 屬性配置:以"鍵=值"的方式書寫一個屬性的配置資訊,都是字串。
  • properties檔案的一個屬性配置資訊值可以換行,但鍵不可以換行。值換行用“\”表示。
  • properties的屬性配置鍵值前後的空格在解析時候會被忽略。
  • properties檔案可以只有鍵而沒有值。也可以僅有鍵和等號而沒有值,但無論如何一個屬性配置不能沒有鍵。

不推薦的寫法

#正確的properties配置檔案 
aaa=wu\ 
    kong 
b
bb    =     bajie
複製程式碼

推薦的寫法

#格式良好的properties檔案 
aaa=wukong
bbb=bajie
複製程式碼

4.讀取Properties檔案的方法

(1) 使用java.util.Properties類的load()方法

你需要提供一共絕對路徑讀取資料,"D:/sys.properties"類似的路徑,我個人不怎麼推薦使用

package com.shxt.demo06;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;

public class Demo06 {
    public static void main(String[] args) {
       Properties props = new Properties();
        try {
            props.load(new FileInputStream("D:/sys.properties"));
            //獲取屬性
            System.out.println("title屬性的值:"+props.getProperty("title"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

複製程式碼

(2) 使用java.util.ResourceBunld類的getBundle()方法[掌握]

通過ResourceBundle.getBundle()靜態方法來獲取(ResourceBundle是一個抽象類),這種方式來獲取properties屬性檔案不需要加.properties字尾名,只需要檔名即可.

  • 屬性檔案在src的根目錄下

package com.shxt.demo06;

import java.util.ResourceBundle;

public class Demo07 {
    public static void main(String[] args) {
       ResourceBundle resouce = ResourceBundle.getBundle("sys");
        //獲取屬性
        System.out.println("title屬性的值:"+resouce.getString("title"));
    }
}
複製程式碼
  • 屬性檔案在包com.shxt.demo06
package com.shxt.demo06;

import java.util.ResourceBundle;

public class Demo08 {
    public static void main(String[] args) {
        //sys為屬性檔名,放在包com.shxt.demo06下,如果是放在src下,直接用sys即可
       ResourceBundle resouce = ResourceBundle.getBundle("com/shxt/demo06/sys");
        //獲取屬性
        System.out.println("title屬性的值:"+resouce.getString("title"));
    }
}
複製程式碼

(3) 使用PropertyResourceBundle

package com.shxt.demo06;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;

public class Demo09 {
    public static void main(String[] args) {
        try {
            ResourceBundle resource =  new PropertyResourceBundle(new FileInputStream("D:/sys.properties"));
            //獲取屬性
            System.out.println("title屬性的值:"+resource.getString("title"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
複製程式碼

(4) 使用class變數的getResourceAsStream()方法

package com.shxt.demo06;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class Demo11 {
    public static void main(String[] args) {
		//  /config/sys.properties 從src的根目錄開始查詢,記住這個"/"
      	// 如果沒有這個斜線,那麼會報空指標異常
        InputStream in =  Demo11.class.getResourceAsStream("/config/sys.properties");
        Properties props = new Properties();
        try {
            props.load(in);
            //獲取屬性
            System.out.println("title屬性的值:"+props.getProperty("db"));
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

複製程式碼

(5) 使用class.getClassLoader()所得到的java.lang.ClassLoader的getResourceAsStream()方法

package com.shxt.demo06;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class Demo12 {
    public static void main(String[] args) {

        InputStream in =  Demo12.class.getClassLoader().getResourceAsStream("config/sys.properties");
        Properties props = new Properties();
        try {
            props.load(in);
            //獲取屬性
            System.out.println("title屬性的值:"+props.getProperty("db"));
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

複製程式碼

感覺上就是少了一個斜線而已

(6) 使用java.lang.ClassLoader類的getSystemResourceAsStream()靜態方法[推薦]

package com.shxt.demo06;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class Demo13 {
    public static void main(String[] args) {

        InputStream in =  ClassLoader.getSystemResourceAsStream("config/sys.properties");
        Properties props = new Properties();
        try {
            props.load(in);
            //獲取屬性
            System.out.println("title屬性的值:"+props.getProperty("db"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

複製程式碼

7.補充:Servlet中可以使用javax.servlet.ServletContext的getResourceAsStream()方法

InputStream in = context.getResourceAsStream(path);
Properties p = new Properties();
p.load(in);
複製程式碼

5.技術穿越

這裡分享一個簡單的封裝的工具類

package com.pangsir.helper.properties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.util.Properties;


/**
 * 載入屬性檔案
 *
 * @author 劉文銘
 * @see com.pangsir.helper.properties.PropertiesConfigHelper
 * @since 1.0
 */
public class PropertiesConfigHelper {
    private PropertiesConfigHelper(){}

    //使用日誌輸出
    private final static Logger logger = LoggerFactory.getLogger(PropertiesConfigHelper.class);
    //設定字尾名
    private final static String EXT = ".properties";
    //例項化Properties物件
    private static Properties configProperties = null;

    /**
     * 載入properties檔案
     *
     * @param filepaths properties檔案路徑
     */
    public static void load(String... filepaths) {
        logger.debug("開始讀取properties檔案 開始時間" + System.currentTimeMillis());
        if(configProperties==null){
            configProperties = new Properties();
        }
        //配置檔案路徑
        String configFilePath;
        InputStream inputStream = null;
        //遍歷filepathke陣列
        for (int i = 0; i < filepaths.length; i++) {
            configFilePath = filepaths[i];
            //讀取屬性檔案字尾名為.properties
            try {
                if (configFilePath.toLowerCase().endsWith(EXT)) {
                    inputStream = PropertiesConfigHelper.class.getClassLoader().getResourceAsStream(configFilePath);
                    configProperties.load(inputStream);
                } else {
                    throw new RuntimeException("無法讀取該檔案: " + configFilePath);
                }
                logger.debug("檔案 \"" + configFilePath + "\" 讀取 成功! 時間為:" + System.currentTimeMillis());
            } catch (Exception e) {
                logger.debug("檔案 \"" + configFilePath + "\" 讀取 失敗, 失敗異常資訊:\\n" + e.getMessage());
                throw new RuntimeException("檔案 \"" + configFilePath + "\" 載入失敗", e);
            } finally {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        logger.debug("所有配置檔案讀取完畢,當關閉檔案FileInputStream時,異常資訊 :\\n" + e.getMessage());
                    }
                }
            }

        }

    }

    /**
     * 獲取 int 型別的配置屬性的value
     *
     * @param key          配置屬性的key
     * @param defaultValue 預設值
     * @return 對應的配置屬性value,如果配置屬性的value不為short型別或不存在對應的配置屬性,則返回 defaultValue
     */
    public static Short getShortValue(String key, Short defaultValue) {
        try {
            return getShortValue(key);
        } catch (NumberFormatException e) {
            return defaultValue;
        }
    }

    /**
     * 獲取 short 型別的配置屬性的value
     *
     * @param key 配置屬性的key
     * @return 對應的配置屬性value
     */
    public static Short getShortValue(String key) {
        return Short.parseShort(configProperties.getProperty(key));
    }

    /**
     * 獲取 int 型別的配置屬性的value
     *
     * @param key          配置屬性的key
     * @param defaultValue 預設值
     * @return 對應的配置屬性value,如果配置屬性的value不為int型別或不存在對應的配置屬性,則返回 defaultValue
     */
    public static int getIntegerValue(String key, Integer defaultValue) {
        try {
            return getIntegerValue(key);
        } catch (NumberFormatException e) {
            return defaultValue;
        }
    }

    /**
     * 獲取 int 型別的配置屬性的value
     *
     * @param key 配置屬性的key
     * @return 對應的配置屬性value
     */
    public static Integer getIntegerValue(String key) {
        return Integer.parseInt(configProperties.getProperty(key));
    }


    /**
     * 獲取 float 型別的配置屬性的value
     *
     * @param key          配置屬性的key
     * @param defaultValue 預設值
     * @return 對應的配置屬性value,如果配置屬性的value不為float型別或不存在對應的配置屬性,則返回 defaultValue
     */
    public static Float getFloatValue(String key, float defaultValue) {
        try {
            return getFloatValue(key);
        } catch (NumberFormatException e) {
            return defaultValue;
        }
    }

    /**
     * 獲取 float 型別的配置屬性的value
     *
     * @param key 配置屬性的key
     * @return 對應的配置屬性value
     */
    public static Float getFloatValue(String key) {
        return Float.parseFloat(configProperties.getProperty(key));
    }

    /**
     * 獲取 double 型別的配置屬性的value
     *
     * @param key 配置屬性的key
     * @param defaultValue 預設值
     * @return 對應的配置屬性value,如果配置屬性的value不為double型別或不存在對應的配置屬性,則返回 defaultValue
     */
    public static Double getDoubleValue(String key, double defaultValue) {
        try {
            return getDoubleValue(key);
        } catch (NumberFormatException e) {
            return defaultValue;
        }
    }
    /**
     * 獲取 Double 型別的配置屬性的value
     *
     * @param key 配置屬性的key
     * @return 對應的配置屬性value
     */
    public static Double getDoubleValue(String key) {
        return Double.parseDouble(configProperties.getProperty(key));
    }



    /**
     * 獲取 long 型別的配置屬性的value
     *
     * @param key 配置屬性的key
     * @param defaultValue 預設值
     * @return 對應的配置屬性value,如果配置屬性的value不為long型別或不存在對應的配置屬性,則返回 defaultValue
     */
    public static Long getLongValue(String key, long defaultValue) {
        try {
            return getLongValue(key);
        } catch (NumberFormatException e) {
            return defaultValue;
        }
    }
    /**
     * 獲取 Long 型別的配置屬性的value
     *
     * @param key 配置屬性的key
     * @return 對應的配置屬性value
     */
    public static Long getLongValue(String key) {
        return Long.parseLong(configProperties.getProperty(key));
    }



    /**
     * 獲取 String 型別的配置屬性的value
     *
     * @param key 配置屬性的key
     * @param defaultValue 預設值
     * @return 對應的配置屬性value,如果配置屬性的value為""或不存在對應的配置屬性,則返回 defaultValue
     */
    public static String getStringValue(String key, String defaultValue) {
        String value = configProperties.getProperty(key);
        return (value == null) ? defaultValue : getStringValue(key);
    }
    /**
     * 獲取 String 型別的配置屬性的value
     *
     * @param key 配置屬性的key
     * @return 對應的配置屬性value
     */
    public static String getStringValue(String key) {
        return configProperties.getProperty(key);
    }

    /**
     * 獲取 boolean 型別的配置屬性的value
     *
     * @param key 配置屬性的key
     * @param defaultValue 預設值
     * @return 如果在配置檔案中沒有定義此屬性,則返回 defaultValue;
     *         如果 value 為y、on、yes 、true 或非 0 數值(均不區分大小寫) 則返回 true, 否則返回 false
     */
    public static boolean getBooleanValue(String key, Boolean defaultValue) {
        String value = configProperties.getProperty(key);
        return (value == null) ? defaultValue : getBooleanValue(key);
    }
    /**
     * 獲取 boolean 型別的配置屬性的value
     *
     * @param key 配置屬性的key
     * @return 對應的配置屬性value
     */
    public static Boolean getBooleanValue(String key) {
        String value = configProperties.getProperty(key);
        return ("y".equalsIgnoreCase(value)) || ("on".equalsIgnoreCase(value)) || ("yes".equalsIgnoreCase(value))
                || ("true".equalsIgnoreCase(value)) || (getIntegerValue(key, 0) != 0);
    }
    /**
     * 載入properties檔案
     *
     * @param filepath properties檔案路徑
     */
    public static void write(String key, String value,String filepath){
        if(configProperties==null){
            configProperties = new Properties();
        }

        OutputStream outputStream = null;
        try{
            String base = PropertiesConfigHelper.class.getResource("/"+filepath).getPath();
            java.net.URL url = PropertiesConfigHelper.class.getResource("/"+filepath);
            File file = new File(url.toURI());
            //判斷檔案是否存在
            if(!file.exists()){
                file.createNewFile();
            }

            load(filepath);//載入檔案

            outputStream = new FileOutputStream(file);

            configProperties.setProperty(key,value);

            configProperties.store(outputStream,"");


        }catch (Exception e){
            throw new RuntimeException("檔案 \"" + filepath + "\" 載入失敗", e);
        }finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    logger.debug("所有配置檔案修改完畢,FileOutputStream異常資訊 :\\n" + e.getMessage());
                }
            }
        }

    }
}

複製程式碼

重點:將properties檔案的配置設定為整個Web應用的全域性變數實現方法,學到J2EE階段再使用下面的方式

WEB域的簡單說明:

Web應用中的變數存放在不同的jsp物件中,會有不一樣的作用域,四種不同的作用域排序是 pageContext < request < session < application;

  • pageContext:頁面域,僅當前頁面有效,離開頁面後,不論重定向還是轉向(即無論是redirect還是forward),pageContext的屬性值都失效;
  • request:請求域,在一次請求中有效,如果用forward轉向,則下一次請求還可以保留上一次request中的屬性值,而redirect重定向跳轉到另一個頁面則會使上一次request中的屬性值失效;
  • session:會話域,在一次會話過程中(從瀏覽器開啟到瀏覽器關閉這個過程),session物件的屬性值都保持有效,在這次會話過程,session中的值可以在任何頁面獲取;
  • application:應用域,只要應用不關閉,該物件中的屬性值一直有效,並且為所有會話所共享

思路說明:

利用ServletContextListener監聽器,一旦應用載入,就將properties的值儲存到application當中.

現在需要在所有的jsp中都能通過EL表示式讀取到properties中的屬性,並且是針對所有的會話,故這裡利用application作用域,那麼什麼時候將properties中的屬性儲存到application呢?因為是將properties的屬性值作為全域性的變數以方便任何一次EL的獲取,所以在web應用載入的時候就將值儲存到application當中.

這裡就要利用ServletContextListener:

  • ServletContextListener是Servlet API 中的一個介面,它能夠監聽 ServletContext 物件的生命週期,實際上就是監聽 Web 應用的生命週期。
  • 當Servlet 容器啟動或終止Web 應用時,會觸發ServletContextEvent 事件,該事件由ServletContextListener 來處理。

具體步驟:

  • (1) 新建一個類PropertyListenter實現 ServletContextListener介面的contextInitialized方法;
  • (2) 讀取properties配置檔案,轉存到Map當中;
  • (3) 使用ServletContext物件將Map儲存到application作用域中;
/**
 * 設值全域性變數
 */
public class PropertyListenter implements ServletContextListener {
 private static final Logger logger = (Logger) LoggerFactory.getLogger(PropertyListenter.class);
 @Override
 public void contextDestroyed(ServletContextEvent context) {}
 @Override
 public void contextInitialized(ServletContextEvent sce) {
  /**
   * 讀取properties檔案
   */
  Properties properties = new Properties(); 
  
  InputStream in = null;
  try {
   //通過類載入器進行獲取properties檔案流
   in = PropertiesUtil.class.getClassLoader().getResourceAsStream("sys.properties");   
   properties.load(in);
   
  } catch (FileNotFoundException e) {
   logger.error("未找到properties檔案");
  } catch (IOException e) {
   logger.error("發生IOException異常");
  } finally {
   try {
    if(null != in) {
     in.close();
    }
   } catch (IOException e) {
    logger.error("properties檔案流關閉出現異常");
   }
  }
      
  /**
   * 將properties檔案轉存到map.關鍵步驟
   */
  Map<String, String> pros = new HashMap<String,String>((Map)properties);
  
  /**
   * 將Map通過ServletContext儲存到全域性作用域中
   */
  ServletContext sct=sce.getServletContext(); 
  
  sct.setAttribute("pros", pros);

 }
 

}
複製程式碼

相關文章