0、寫在前面的話
最近在做微信的公眾號開發,因為調用微信接口失敗的話是以各類錯誤碼和錯誤信息返回的,在Github發現有位老哥整理成了xml(
weixin/error.xml),索性也就想借鑒他的方式和這份xml,將內容讀取存儲到一個Map中,這樣在遇到微信返回的錯誤碼時就可以從Map中取出對應的具體錯誤信息。
在工具類中建立一個靜態塊,然后試圖讀取xml然后存入Map,問題來了,之前在Servlet中都是利用的ServletContext上下文對象,使用getRealPath(String path)方法獲取文件路徑。可是這個工具類並不是Servlet,也就沒有ServletContext。
然而,什么都難不倒Google,下面就類似的配置文件的讀取問題,進行一下總結。
另外,要說一個前提是,
xml、properties等配置文件和Java資源都是放在WEB-INF下面的classes文件夾中(以下則稱之為classpath)。我們的目的是如何獲取該目錄下的文件資源,假如我們現在的文件為應用根目錄下" .../WEB-INF/classes/error.xml "。
1、在Servlet類中讀取
假如要將文件獲取為流,有兩種讀取方式:
(1)直接讀取文件為流,getResourceAsStream(path)方法,path默認為應用的根目錄
InputStream inputStream = this.getServletContext().getResourceAsStream("/WEB-INF/classes/error.xml");
1
1
InputStream inputStream = this.getServletContext().getResourceAsStream("/WEB-INF/classes/error.xml");
(2)先讀取文件,再讀取為流,獲取路徑的方式和上面是類似的
String path = this.getServletContext().getRealPath("/WEB-INF/classes/error.xml");
InputStream inputStream = new FileInputStream(path);
2
1
String path = this.getServletContext().getRealPath("/WEB-INF/classes/error.xml");
2
InputStream inputStream = new FileInputStream(path);
2、在非Servlet類中(普通Java類中)的讀取
在非Servlet類中,要將文件獲取為流,也有兩種方式:
(1)用ClassLoader類加載資源文件,這里默認是從classes目錄下讀取
用ClassLoader加載配置文件時,path,也就是這里的 "error.xml" 不能以"/"開頭,在查找時直接在classpath下進行查找:
InputStream in = ClassName.class.getClassLoader().getResourceAsStream("error.xml");
1
1
InputStream in = ClassName.class.getClassLoader().getResourceAsStream("error.xml");
同樣的方法,也可以迂回一下,先讀取到文件的路徑,再用流讀出,這里FileInputStream的path就可以使用絕對或者相對路徑:
String path = ClassName.class.getClassLoader().getResource("error.xml").getPath();
InputStream inputStream = new FileInputStream(path);
2
1
String path = ClassName.class.getClassLoader().getResource("error.xml").getPath();
2
InputStream inputStream = new FileInputStream(path);
(2)用Class類加載資源文件,形參不同,訪問路徑不同
InputStream inputStream = ClassName.class.getResourceAsStream("/error.xml");
1
1
InputStream inputStream = ClassName.class.getResourceAsStream("/error.xml");
需要注意的是,這種方式的形參有兩種方式:
- 絕對定位,“/”開頭,此時即以classpath為根目錄
- 相對定位,不加“/”,則以調用getResourceAsStream類的包路徑作為根目錄(即該類所在包下獲取資源)
最后,也就是用了如上的方法,解決了我讀取error.xml的問題:
//讀取errorCode錯誤碼到Map中
static {
InputStream xml = WeChatUtil.class.getResourceAsStream("/error.xml");
SAXReader saxReader = new SAXReader();
try {
Document document = saxReader.read(xml);
Element root = document.getRootElement();
List<Element> elements = root.elements();
for (Element element : elements) {
String code = element.elementText("code");
String text = element.elementText("text");
WeChatUtil.errorCodeMap.put(code, text);
}
} catch (DocumentException e) {
log.debug("error.xml讀取失敗");
e.printStackTrace();
}
}
1
//讀取errorCode錯誤碼到Map中
2
static {
3
InputStream xml = WeChatUtil.class.getResourceAsStream("/error.xml");
4
SAXReader saxReader = new SAXReader();
5
try {
6
Document document = saxReader.read(xml);
7
Element root = document.getRootElement();
8
List<Element> elements = root.elements();
9
for (Element element : elements) {
10
String code = element.elementText("code");
11
String text = element.elementText("text");
12
WeChatUtil.errorCodeMap.put(code, text);
13
}
14
} catch (DocumentException e) {
15
log.debug("error.xml讀取失敗");
16
e.printStackTrace();
17
}
18
}
3、參考鏈接
題外話:
在使用Spring時通常看到諸如 <param-value
>classpath:applicationContext-*.xml</param-value> 的配置,此處的classpath確實是指WEB-INF下的classes目錄,但此處畢竟只是配置的字符串,實際上獲取資源路徑時是框架進行了識別和處理的。我之前也是很愚,一直不理解所謂的classpath,今天才明白了些許,順便追了下Spring源碼。
在Spring的配置中,實際上有classpath和classpath*,區別在於:
- classpath 只會到你的classes路徑中查找找文件
- classpath* 不僅包含classes路徑,還包括jar文件中(class路徑)進行查找
