Java-利用Spring提供的Resource/ResourceLoader接口操作资源文件
- 背景
- 資源訪問接口
- 主要方法
- 主要實現類
- 例子
- WritableResource ClassPathResource
- ServletContextResource
- 對資源文件編碼
- 資源加載
- 資源地址表達式
- Spring支持的資源類型的地址前綴
- 注意事項 classpath 和 classpath
- Ant風格的資源地址
- 資源加載器
- 介紹
- 示例
- 資源地址表達式
- 注意事項
背景
JDK提供的訪問資源的類(如java.net.URL、File等)并不能很好地滿足各種底層資源的訪問需求,比如缺少從類路徑或者Web容器上下文中獲取資源的操作類。
Spring提供了Resource接口,為應用提供了更強的底層資源訪問能力,該接口擁有對應不同資源類型的實現類。
資源訪問接口
主要方法
- boolean exists() 資源是否存在
- boolean isOpen() 資源是否打開
- URL getURL() throws IOException 如果底層資源可以表示成URL,則該方法放回對應的URL對象
- File getFile() throws IOException 如果底層資源對應一個文件,這返回對應的File對象
Spring框架使用Resource裝載各種資源,包括配置文件資源、國際化屬性文件資源等。
主要實現類
- WritableResource : 可寫資源接口,Spring3.1新增的接口,有2個實現類: FileSystemResource和PathResource。 其中PathResource是Spring4.0提供的實現類
- ByteArrayResource:二進制數組表示的資源,二進制數組資源可以在內存中通過程序構造。
- ClassPathResource:類路徑下的資源,資源以相對于類路徑的方式表示,一般是以相對于根路徑的方式
- FileSystemResouce:文件系統資源,資源以文件系統路徑的方式表示
- InputStreamResource:以輸入流返回標識的資源
- ServletContextResource:為訪問Web容器上下文中的資源而設計的類,負責以相對于Web應用根目錄的路徑來加載資源。支持以流和URL的訪問能行事,在war包解包的情況下,也可以通過File方式訪問。 該類還可以直接從JAR包中訪問資源。
- UrlResource:封裝了java.net.URL,它使用戶能夠訪問任何可以通過URL表示的資源,如文件系統的資源,HTTP資源,FTP資源
- PathResource : Spring4.0提供的讀取資源文件的新類。Ptah封裝了java.net.URL、java.nio.file.Path(Java 7.0提供)、文件系統資源,它四用戶能夠訪問任何可以通過URL、Path、系統文件路徑標識的資源,如文件系統的資源,HTTP資源,FTP資源
有了這個抽象的資源類后,就可以將Spring配置文件放在任何地方(如數據庫、LDAP中),只要最終通過Resource接口返回配置信息即可。
Spring的Resource接口及其實現類可以在脫離Spring框架的情況下適用,比JDK更方便更強大.
例子
假設一個Web應用下有一個文件,用戶可以通過以下幾種方式對這個資源文件進行訪問:
WritableResource / ClassPathResource
package com.xgj.service;import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream;import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.PathResource; import org.springframework.core.io.WritableResource; /*** * @ClassName: ResourceLoadTest* @Description: 跟這個模塊無關,僅僅是為了測試 Resource接口操作文件* @author: Mr.Yang* @date: 2017年7月7日 下午11:38:19*/ public class ResourceLoadTest {public static void main(String[] args) {try {String filePath = "D:/workspace/workspace-jee/HelloSpring/hello-spring4/src/test/resources/resourcefiletest.txt";// (1)使用系統文件路徑加載文件WritableResource res = new FileSystemResource(filePath);// PathResource @since 4.0//WritableResource res = new PathResource(filePath);System.out.println(res.getFilename());// (2)使用類路徑方式加載spring-context.xml文件ClassPathResource classPathResource = new ClassPathResource("spring-context.xml");System.out.println(classPathResource.getFilename());// (3)使用WritableResource接口寫資源文件OutputStream os = res.getOutputStream();os.write("小工匠的使用Resource接口測試".getBytes());os.close();// (4)使用Resource接口讀取資源文件InputStream ins = res.getInputStream();ByteArrayOutputStream bos = new ByteArrayOutputStream();int i;while ((i = ins.read()) != -1) {bos.write(i);}System.out.println("讀取的文件:" + res.getFilename() + ",內容:" + bos.toString());// 讀取spring-context.xml的內容InputStream ins2 = classPathResource.getInputStream();int j;while ((j = ins2.read()) != -1) {bos.write(j);}//System.out.println("讀取的文件:" + classPathResource.getFilename() + ",內容:" + bos.toString());} catch (IOException e) {e.printStackTrace();}}}輸出:
resourcefiletest.txt spring-context.xml 讀取的文件:resourcefiletest.txt,內容:小工匠的使用Resource接口測試ServletContextResource
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"pageEncoding="ISO-8859-1"%> <jsp:directive.page import="org.springframework.web.context.support.ServletContextResource" /> <jsp:directive.page import="org.springframework.core.io.Resource" /> <jsp:directive.page import="org.springframework.web.util.WebUtils" /><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>ResourceTest,nothing to do with this module</title> </head> <body><%Resource res3 = new ServletContextResource(application, "/WEB-INF/classes/spring-context.xml");out.print(res3.getFilename() + "<br/>");out.print(WebUtils.getTempDir(application).getAbsolutePath());%></body> </html>運行:
對資源文件編碼
// (2)使用類路徑方式加載spring-context.xml文件 ClassPathResource classPathResource = new ClassPathResource("spring-context.xml"); System.out.println(classPathResource.getFilename());// 以UTF-8編碼 EncodedResource ens = new EncodedResource(classPathResource ,"UTF-8"); String content = FileCopyUtils.copyToString(ens.getReader()); System.out.println("編碼后的內容:\n" +content);資源加載
通過上面的例子,是不是發現 ,為了訪問不同類型的資源,必須使用相應的Resource實現類。
是否可以在不顯式使用Resource實現類的情況下,僅僅通過資源地址的特殊標示符就可以訪問相應的資源? 答案是肯定的,Spring提供了一個強大的加載資源的方式,不僅能通過“classpath:”、“file:”等資源地址前綴識別不同的資源類型,還支持Ant風格帶通配符的資源地址。
資源地址表達式
Spring支持的資源類型的地址前綴
| classpath: | classpath:com/xgj/beans.xml | 從類不經中加載資源,classpath: 和 classpath:/ 是等價的,都是相對于類的根路徑,資源文件可以在標準的文件系統中,也可以在jar或者zip的類包中 |
| file: | file:/conf/com/xgj/beans.xml | 使用UrlResource從文件系統目錄中裝載資源,可以采用絕對路徑或者相對路徑 |
| http:// | http://www.xgj.com/resource/beans.xml | 使用UrlResource從web服務器中加載資源 |
| ftp:// | ftp://www.xgj.com/resource/beans.xml | 使用UrlResource從FTP服務器中裝載資源 |
| 沒有前綴 | com/xgj/beans.xml | 根據ApplicationContext的具體實現類采用對應類型的Resource |
注意事項 classpath: 和 classpath*:
舉個例子: 假設有多個Jar包或者文件系統類路徑下擁有一個相同包名(com.xgj)
- classpath: 只會加載第一個加載的com.xgj包的類路徑下查找
- classpath*: 會掃描到所有的這些jar包及類路徑下出下的com.xgj類路徑。
使用場景:
一般情況下,我們的應用都是有各個模塊組成的,對于分模塊打包的應用,假設我們有一個應用,分為N個模塊,一個模塊對應一個配置文件,分別為module1.xml 、module2xml、module3.xml….等,都放在了com.xgj的目錄下,每個模塊單獨打成jar包。
我們可以使用 classpath*:com/xgj/module*.xml加載所有模塊的配置文件。
如果使用classpath:com/xgj/module*.xml 只會加載一個模塊的配置文件
Ant風格的資源地址
Ant風格的資源地址支持三種匹配符
- ? 匹配文件名中的一個字符
- * 匹配文件名中的任意字符
- ** 匹配多層路徑
示例:
classpath:com/t?st.xml匹配com類路徑下的 com/test.xml com/tast.xml等
file:D:/conf/*.xml
匹配文件系統D:/conf/目錄下所有以.xml為后綴的文件
classpath:com/**/test.xml
匹配com類路徑下(當前目錄及子孫目錄)的test.xml
classpath:org/springframework/**/*.xml
匹配類路徑org/springframework/下是有的以.xml為后綴的文件
classpath:org/**/servlet/bla.xml
匹配類路徑org任意層級的 /servlet/bla.xml的文件
資源加載器
介紹
Spring定義了一套資源加載的接口,并提供了實現類
其中
ResourceLoader中的方法Resource getResource(String location);
可以根據一個資源地址加載文件資源, 不過ResourceLoader這個接口方法中的資源地址僅支持帶資源類型前綴的表達式,不支持Ant風格的資源路徑表達式。
不過 ResourcePatternResolver 擴展了 ResourceLoader接口,
ResourcePatternResolver 的getResource方法支持帶資源類型前綴以及Ant風格的資源路徑表達式。
PathMatchingResourcePatternResolver 是Spring提供的標準實現類。
示例
package com.xgj.service;import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream;import org.apache.log4j.Logger; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver;/*** * * @ClassName: ResourceLoaderTest* * @Description: 跟這個模塊無關,僅僅是為了測試 ResourceLoa接口操作文件* * @author: Mr.Yang* * @date: 2017年7月9日 下午7:51:37*/ public abstract class ResourceLoaderTest {static Logger logger = Logger.getLogger(ResourceLoaderTest.class);static ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();public static void main(String[] args) {try {readFromClasspath();readFromHttp();readFromFile();readFromFTP();readFromNoPreFix();} catch (IOException e) {e.printStackTrace();}}/*** * * @Title: readFromClasspath* * @Description: 讀取 classpath: 地址前綴的文件* * @throws IOException* * @return: void*/public static void readFromClasspath() throws IOException {Resource[] resources = resourcePatternResolver.getResources("classpath*:com/xgj/conf/**/*.xml");for (Resource resource : resources) {System.out.println(resource.getDescription());readContent(resource);}}public static void readFromNoPreFix() throws IOException {Resource resource = resourcePatternResolver.getResource("spring-context.xml");System.out.println(resource.getDescription());readContent(resource);}/*** * * @Title: readFromFile* * @Description: 使用UrlResource從文件系統目錄中裝載資源,可以采用絕對路徑或者相對路徑* * @throws IOException* * @return: void*/public static void readFromFile() throws IOException {Resource resource = resourcePatternResolver.getResource("file:/D:/workspace/workspace-jee/HelloSpring/hello-spring4/src/main/java/com/xgj/conf/conf2/test2.xml");readContent(resource);}/*** * * @Title: readFromHttp* * @Description: 使用UrlResource從web服務器中加載資源* * @throws IOException* * @return: void*/public static void readFromHttp() throws IOException {Resource resource = resourcePatternResolver.getResource("http://127.0.0.1:8080/hello-spring4/index.jsp");System.out.println(resource.getDescription());readContent(resource);}/*** * * @Title: readFromFTP* * @Description: 這里只演示寫法,因為這個服務器要求用戶名和密碼,其實是無法讀取的。* * @throws IOException* * @return: void*/public static void readFromFTP() throws IOException {Resource resource = resourcePatternResolver.getResource("ftp://172.25.243.81/webserver/config/logback.xml");}/*** * * @Title: readContent* * @Description: 讀取獲取到的資源文件的內容* * @param resource* @throws IOException* * @return: void*/public static void readContent(Resource resource) throws IOException {InputStream ins = resource.getInputStream();ByteArrayOutputStream bos = new ByteArrayOutputStream();int i;while ((i = ins.read()) != -1) {bos.write(i);}logger.debug("讀取的文件:" + resource.getFilename() + ",/n內容:/n" + bos.toString());}}注意事項
使用Resource操作文件時,如果資源的配置文件在項目發布的時候會打包到jar中,那么就不能使用Resource.getFile()方法,否則會拋出FileNotFoundException異常。
推薦使用 Resource.getInputStream()讀取。
錯誤的方式
(new DefaultResourceLoader()).getResource("classpath:conf/sys.properties").getFile();正確的方式
(new DefaultResourceLoader()).getResource("classpath:conf/sys.properties").getInputStream();建議盡量使用流的方式讀取,避免環境不同造成問題
總結
以上是生活随笔為你收集整理的Java-利用Spring提供的Resource/ResourceLoader接口操作资源文件的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java-查看JVM从哪个JAR包中加载
- 下一篇: Spring-ApplicationCo