在应用开发中,基本上都会有读取资源的情况,这些资源包括文件系统的文件、ClassPath中的某个配置文件或者是网络上的文件,我们之前可以使用java.net.URL这个类去完成这个任务,但是在开发基于Spring框架的应用的时候,可以使用Spring原生提供的Resources接口来实现.
Spring 的Resources是一个抽象的接口,它可以被实现成各种场景下的资源访问,首先看一下接口的定义:
public interface Resource extends InputStreamSource {
boolean exists();
boolean isOpen();
URL getURL() throws IOException;
File getFile() throws IOException;
Resource createRelative(String relativePath) throws IOException;
String getFilename();
String getDescription();
}
public interface InputStreamSource {
InputStream getInputStream() throws IOException;
}
说明:
getInputStream()
:用来定位并打开资源,返回资源的InputStream;
exists()
:用来判断给定的资源是否存在;
其他的方法主要是获取和资源相关的描述信息;
上面只是抽象接口的定义,具体的实现有哪些呢?
Spring 提供了几种默认的实现类,这些实现类被应用的场合环境不同,下面简要说明:
UrlResource
通过封装java.net.URL去访问资源,可以访问文件系统里的资源,http或ftp的资源;
ClassPathResource
根据ClassPath去获取资源;
FileSystemResource
通过封装java.io.File去访问资源
ServletContextResource
ServletContext实现的Resource接口,解析的资源主要是相对于Web 应用的跟路径(Web Application’s root directory)
InputStreamResource
待补充
ByteArrayResource
待补充
大家可能看到上面存在这么多的Resource接口实现类,在具体使用的时候难道是由开发者自己决定使用什么类比较合适吗?如果真的是这样的话,Spring的Resource的特性就没有体现出来了.
Spring提供了另外一个接口:ResourceLoader,这个接口帮我们解决了选择Resource的工作,ResourceLoader接口的定义如下:
public interface ResourceLoader {
Resource getResource(String location);
}
大家可以看到这个接口提供的getResource方法接收一个String类型的参数,这个location用来表述资源的所在,我们唯一要做的工作就是给定资源的路径,ResourceLoader会返回给我们对应的Resource接口具体实现类.
所有的application context都是实现ResourceLoader接口,因此,可以通过application context获取到Resource实例,当你调用application context的getResource方法时,如果location没有前缀,则返回的Resource类型取决于当前的application context环境,
例如:
ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[] {"application-context.xml"});
Resource template = ctx.getResource("some/resource/path/myTemplate.txt");
因为location并没有什么前缀,所以当前Resource返回的实例的具体类型是:ClassPathResource.
大家不禁要问了,如果有前缀会怎么样呢?
大家先看一下几行代码:
Resource resource1 = ctx.getResource("classpath:some/resource/path/myTemplate.txt");
Resource resource2 = ctx.getResource("file:///some/resource/path/myTemplate.txt");
Resource resource3 = ctx.getResource("http://myhost.com/resource/path/myTemplate.txt");
上面分别出现了不同的几种前缀,
1. “classpath”:这个前缀表明指定返回ClassPathResource类型的实例,无论当前的application context是什么环境;
2. “file”和”http”:这两个前缀都要求返回的UrlResource类型的实例;
这里我简单的使用Spring MVC的一个controller来演示一下:
@Autowired
private ResourceLoader resourceLoader;
@RequestMapping("/resources")
@ResponseBody
public String resources() {
Resource resource = resourceLoader.getResource("file:/home/jiangjian/demo.txt");
System.out.println("resource instanceof UrlResource : " + (resource instanceof UrlResource));
if(resource.exists()) {
InputStream is = null;
try {
is = resource.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line;
while((line = br.readLine()) != null) {
System.out.println(line);
}
br.close();
} catch (IOException e) {
e.printStackTrace();
return "failed";
}
}
return "success";
}
参考:
1. Spring Resource loader with getResource() example
2. Spring Resource