预讲知识点
1.掌握Resource接口的使用
2.ResourceLoader接口使用
3.掌握各种资源数据的读取操作
具体内容
如果想要进行磁盘文件的读取操作,首先想到的一定是java.io包中提供的一系列类,还可以继续深入的想到:InputStream、OutputStream、Scanner、BufferedReader、PrintStream等核心的处理操作类。
但是现在有如下几个问题:
1.这几个类的相互操作难度太高,很多人实际上对于IO的领悟并不是很彻底;
2.IO支持的读取有限且复杂:
|-读取jar包里的文件;
|-读取不同资源文件的时候操作不统一,例如:读取文件、网络读取;
所以在整个Spring设计过程之中充分的考虑了IO操作的种种操作问题,那么提供了一套新的资源访问处理的操作支持,而整个操作的关键在于:org.springframework.core.io.Resource,而这个接口就表示所有的可用资源读取,在此接口里定义有如下的几个常用方法:
long contentLength() 取得资源的数据长度
boolean exists() 判断资源是否存在
File getFile() 取得资源对应的文件类信息
URL getURL() 取得资源的完整网络路径
boolean isOpen() 判断资源是否打开
long lastModified() 最后一次修改日期
Resource createRelative(String relativePath) 创建一个操作资源
Resource本身只属于一个子接口,它有一个对应的父接口:org.springframework.core.io.InputStreamSource在这个接口里面也定义有一些资源的操作方法:
InputStream getInputStream() 取得资源的输入流
Resource本身是一个接口,那么如果要想使用这个操作接口,需要找到它的子类:ByteArrayResource(内存读取)、ClassPathResource(CLASSPATH读取)、FileSystemResource(文件读取)、
4.1、读取不同资源
下面首先按照传统开发实现一些基本资源读取。
1、读取内存资源:org.springframework.core.io.ByteArrayResource
·构造方法:ByteArrayResource(byte[] byteArray);
范例:实现内存读取
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import java.util.Scanner;
public static void main(String[] args) throws Exception{
//此处的内存处理流于之前讲解的ByteArrayInputStream使用形式类似
Resource resource = new ByteArrayResource("helloworld".getBytes());
//单单就可以取得更多的资源信息来讲,这一点比InputStream要强
System.out.println("数据长度" + resource.contentLength());
//如果给出的InputStream,那么可以利用Scanner简化
//getInputStream是通过InputStreamSource父接口继承而来的方法
Scanner scanner = new Scanner(resource.getInputStream());
if(scanner.hasNext()){
System.out.println(scanner.next());
}
}
2、文件读取:org.springframework.core.io.FileSystemResource
·构造方法FileSystemResource(java.io.File file)
FileSystemResource(java.lang.String path)
范例:读取文件
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import java.io.File;
import java.util.Scanner;
public static void main(String[] args) throws Exception{
Resource resource = new FileSystemResource(new File("/Users/macpro/IdeaProjects/Spring/src/applicationContext.xml"));
System.out.println("数据长度" + resource.contentLength());
Scanner scanner = new Scanner(resource.getInputStream());
scanner.useDelimiter("\n");
if(scanner.hasNext()){
System.out.println(scanner.next());
}
}
如果要进行文件的读取,必须要提供有完整的路径,也就是说默认情况下要想读取一个置顶的资源,那么必须要拼凑出路径(需要取得一堆系统属性)
3.CLASSPATH读取:org.springframework.core.io.ClassPathResource
只要是保存在CLASSPATH环境属性下的路径信息都可以通过此类读取进来
Resource resource = new ClassPathResource("applicationContext.xml");
System.out.println("数据的长度"+resource.contentLength());
Scanner scanner = new Scanner(resource.getInputStream());
while (scanner.hasNext()){
System.out.println(scanner.next());
}
4.3、ResourceLoader接口
ResourceLoader接口的主要作用是进行org.springframework.core.io.ResourceLoader接口对象实例化使用的,这个接口的定义如下:
·读取指定的资源信息:Resource getResource(java.lang.String location)
·取得类加载器:java.lang.ClassLoader getClassLoader()
ResourceLoader是一个接口,于是要使用这个接口必须知道他对应的子类:org.springframework.core.io.DefaultResourceLoader,利用这个子类就可以实现ResourceLoader接口实例化,但是现在资源操作的问题并不在于Resource或者是ResourceLoader接口以及其一堆的子类,而关键性的问题在于这个定位的字符串。
·文件读取资源:“file:路径”;
·CLASSPATH读取:“classpath:路径”;
·网络读取:”http://路径“。
范例:
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
public static void main(String[] args) throws Exception{
ResourceLoader resourceLoader = new DefaultResourceLoader();
Resource resource = resourceLoader.getResource("classpath:applicationContext.xml");
System.out.println("文件长度"+resource.contentLength());
Scanner scanner = new Scanner(resource.getInputStream());
while(scanner.hasNext()){
System.out.println(scanner.next());
}
}
读取其他数据只修改getResource()中的内容就好了,格式按照范例之上的格式
“file:/Users/macpro/IdeaProjects/Spring/src/applicationContext.xml”
"http://bilibili.com"
只是写了一个字符串,而后就可以进行读取了,可以清楚的感受到,都是利用了字符串来进行的资源定位,也就是说在整个Spring里面核心的设计思想就是:利用合理的字符串格式来进行
4.3、注入Resource
在以上的操作可以发现,虽然Resource的子类可以利用了字符串格式进行了隐藏,但是此时的代码之中ResourceLoader跟开发没有任何的关系。如果真的开发之关系Resource一个接口就够了。
为了解决Resource于ResourceLoader关系的耦合问题,那么在Spring设计的时候考虑到数据的自动转型问题,也就是说注入的操作模式,就可以让ResourceLoaded消失。
范例:编写一个资源处理类
import org.springframework.core.io.Resource;
public class ResourceBean {
private Resource resource;
public Resource getResource() {
return resource;
}
public void setResource(Resource resource) {
this.resource = resource;
}
}
public static void main(String[] args) throws Exception{
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ResourceBean resourceBean = ctx.getBean("rb",ResourceBean.class);
Scanner scanner = new Scanner(resourceBean.getResource().getInputStream());
scanner.useDelimiter("/n");
while(scanner.hasNext()){
System.out.println(scanner.next());
}
}
要想实资源数据的注入操作,就必须要编写applicationContext.xml文件,在这个文件里面定义所需要的资源。
范例:在applicationContext.xml文件中定义
<bean id="rb" class="cn.edu.util.ResourceBean">
<property name="resource" value="file:/Users/macpro/IdeaProjects/Spring/src/applicationContext.xml"/>
</bean>
或者
<property name="resource" value="classpath:applicationContext.xml"/>
或者
<property name="resource" value="http://bilibili.com"/>
范例:测试代码
public static void main(String[] args) throws Exception{
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ResourceBean resourceBean = ctx.getBean("rb",ResourceBean.class);
Scanner scanner = new Scanner(resourceBean.getResource().getInputStream());
scanner.useDelimiter("/n");
while(scanner.hasNext()){
System.out.println(scanner.next());
}
}
利用了配置文件的方式进行处理的时候,那么用户关心的只是Resource一个接口的作用被Spring封装起来了。
而且最为方便的是,在Spring里面允许用户设置资源数组。
范例:修改程序类
public static void main(String[] args) throws Exception{
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ResourceList resourceList = ctx.getBean("rbList",ResourceList.class);
Iterator<Resource> iterator = resourceList.getResource().iterator();
while(iterator.hasNext()){
Scanner scanner = new Scanner(iterator.next().getInputStream());
while(scanner.hasNext()){
System.out.println(scanner.next());
}
System.out.println("*************************************");
}
<bean id="rbList" class="cn.edu.util.ResourceList">
<property name="resource">
<list>
<value>file:/Users/macpro/IdeaProjects/Spring/src/applicationContext.xml</value>
<value>classpath:applicationContext.xml</value>
<value>http://bilibili.com</value>
</list>
</property>
</bean>
private List<Resource> resource;
public List<Resource> getResource() {
return resource;
}
public void setResource(List<Resource> resource) {
this.resource = resource;
}
利用Spring读取外部文件资源的时候它的设计要比直接使用IO包操作更加容易。
4.4、路径通配符(重点)
以上讲解的操作都以个共同的问题,那么就是必须设置好完整的路径,但是很多时候无法一一设置完整路径。例如,在不同目录下都会存在有“applicationContext-xxx.xml“命名结构,如果要想将其完整的读取进来,那么就必须考虑到路径的通配符使用,在Spring中继续发扬了ANT工具的特征,而在这个工具下提供有几种符号:
·“?”:匹配任意的一位字符
·“*”:匹配零个或多个任意的字符。
·“**”:表示匹配任意目录,可以是零个、一个或多个。
但是一旦要进行多个路径的匹配那么返回的内容也一定是多个,此时只能利用resourceLoader进行读取:org.springframework.core.io.support.ResourcePatternResolver。可以使用子类:PathMatchingResourcePatternResolver。
范例:读取资源
public class ClassPathMany{
public static void main(String[] args) throws Exception{
ResourcePatternResolver loader = new PathMatchingResourcePatternResolver();
Resource[] source = loader.getResource("classpath:cn/edu/**/applicationContext-?"));
for(int x = 0; x < source.length; x++){
System.out.println("文件名称:" + source[x].getFilename() + "数据长度" + source[x].contentLength());
}
}
}
在Spring里面目录的访问不再成为限制。
网友评论