概述:

  1. 主要介绍3种方式(当然不止三种,但是这三种基本能应付大多需求)
    FileSystemResource:以文件的绝对路径方式进行访问
    ClassPathResourcee:以类路径的方式访问
    ServletContextResource:web应用根目录的方式访问
  2. 主要公用方法介绍(Resource接口下的)
    getFilename() : 获得文件名称
    contentLength() : 获得文件大小
    createRelative(path) : 在资源的相对地址上创建新文件
    exists() : 是否存在
    getFile() : 获得Java提供的File 对象
    getInputStream() :  获得文件的流
  3. 与常规的对应方法
    FileSystemResource 效果类似于Java中的File
    ClassPathResource 效果类似于this.getClass().getResource("/").getPath();
    ServletContextResource 效果类似于request.getServletContext().getRealPath("");
  4. 说明
    1.虽然这些方法都有常规方法获得(这个也是肯定的),但是spring的这些方法都继承自Resource接口(更加方便)
    2.ServletContextResource 还演示了转码操作 EncodedResource类的使用(个人认为比较实用)
    3.今后会继续补充
    4.不多说了,上代码,看注释
Java代码  收藏代码
  1. package com.cxyapi.spring.resource;  
  2.   
  3. import java.io.File;  
  4.   
  5. import org.apache.commons.io.IOUtils;  
  6. import org.junit.Test;  
  7. import org.springframework.core.io.ClassPathResource;  
  8. import org.springframework.core.io.FileSystemResource;  
  9. import org.springframework.core.io.Resource;  
  10.   
  11. /** 
  12.  * @author cxy@cxyapi.com 
  13.  * spring学习笔记 - 资源访问(Resource接口) 
  14.  * 说明: 
  15.  * 主要介绍3种方式(当然不止三种,但是这三种基本能应付大多需求) 
  16.  *   FileSystemResource:以文件的绝对路径方式进行访问 
  17.  *   ClassPathResource:以类路径的方式访问 
  18.  *   ServletContextResource:web应用根目录的方式访问 
  19.  */  
  20. public class ResourceTest  
  21. {  
  22.       
  23.     /** 
  24.      * FileSystemResource 
  25.      * 文件系统资源访问:以文件系统的绝对路径方式进行访问 
  26.      */  
  27.     @Test  
  28.     public void FileSystemResourceTest() throws Exception  
  29.     {  
  30.         String filePath="D:/cxyapi/show.txt";  
  31.         FileSystemResource res1=new FileSystemResource(filePath);  
  32.         if(res1.exists())  
  33.         {  
  34.             System.out.println("资源的文件名:"+res1.getFilename());  
  35.             System.out.println("资源的文件大小:"+res1.contentLength());  
  36.             //可以获取输入流和输出流,然后配合apache common的IOUtils 读取内容  
  37.             System.out.println("文件内容:"+IOUtils.toString(res1.getInputStream(),"GB2312"));  
  38.             File f=res1.getFile();  //转换成Java的File对象  
  39.         }else  
  40.         {  
  41.             System.out.println("指定资源不存在");  
  42.         }  
  43.     }  
  44.       
  45.     /** 
  46.      * ClassPathResource:以类路径的方式访问 
  47.      */  
  48.     @Test  
  49.     public void ClassPathResourceTest() throws Exception  
  50.     {  
  51.         Resource res=new ClassPathResource("aop.xml");  
  52.         //对应的文件路径:E:\workspace\SpringTest\WebContent\WEB-INF\classes\aop.xml  
  53.         System.out.println("文件的物理路径:"+res.getFile().getAbsolutePath());  
  54.         System.out.println("对应的以往的实现方式:"+this.getClass().getResource("/").getPath());  
  55.     }  
  56.   
  57. }  

 

   ServletContextResource的测试写在了jsp中,因为这个方法需要jsp内置对象application作为参数

Html代码  收藏代码
    1. <%@page import="org.springframework.core.io.support.EncodedResource"%>  
    2. <%@page import="org.springframework.util.FileCopyUtils"%>  
    3. <%@page import="org.springframework.web.context.support.ServletContextResource"%>  
    4. <%@page import="org.springframework.core.io.Resource"%>  
    5. <%@ page language="java" contentType="text/html; charset=UTF-8"  
    6.     pageEncoding="UTF-8"%>  
    7. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
    8. <html>  
    9. <head>  
    10. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
    11. <title>ServletContextResource测试</title>  
    12. </head>  
    13. <body>  
    14. <%  
    15.     //文件的相对路径是Web应用的根路径 也就是 WebContent 或者是 WebRoot(超级实用)  
    16.     Resource res = new ServletContextResource(application,"/configTest/cxyapi.txt");  
    17.     String fileName=res.getFilename();  
    18.     //做个转码 输出文件内容  
    19.     EncodedResource encRes=new EncodedResource(res,"UTF-8");  
    20.     String fileContent=FileCopyUtils.copyToString(encRes.getReader()).replaceAll("\r\n", "<br/>");  
    21. %>  
    22. <p>  
    23.     <b>文件名称:</b><%=fileName%>  
    24. </p>  
    25. <p>  
    26.     <b>文件内容:</b><br/>  
    27.     <%=fileContent%>  
    28. </p>  
    29. </body>  
    30. </html>  

一,简单介绍Spring中资源处理相关类

 

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. <span style="font-family:Microsoft YaHei;">BeanFactory beanFactory=new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));</span>  

 

 

 

 

 

 

spring中,定义了接口InputStreamSource,这个类中只包含一个方法:

 

 

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. <span style="font-family:Microsoft YaHei;">public interface InputStreamSource {  
  2.   
  3.     /** 
  4.      * Return an {@link InputStream}. 
  5.      * <p>It is expected that each call creates a <i>fresh</i> stream. 
  6.      * <p>This requirement is particularly important when you consider an API such 
  7.      * as JavaMail, which needs to be able to read the stream multiple times when 
  8.      * creating mail attachments. For such a use case, it is <i>required</i> 
  9.      * that each {@code getInputStream()} call returns a fresh stream. 
  10.      * @return the input stream for the underlying resource (must not be {@code null}) 
  11.      * @throws IOException if the stream could not be opened 
  12.      * @see org.springframework.mail.javamail.MimeMessageHelper#addAttachment(String, InputStreamSource) 
  13.      */  
  14.     InputStream getInputStream() throws IOException;  
  15.   
  16. }</span>  

 

 

    用来返回一个基本的InputStream文件。

 

    之后,使用Resource接口来规定对文件的一些基本的操作。对于不同来源的件:classpath,file,url,byte,inputstream...进行处理。在我们的应用程序里面,比较常用的就是对我们classpath下的xml文件进行解析的ClassPathResource。

 

二,ClassPathResource的构造函数

 

         利用ClassPathResource读取xml配置的基本思路就是通过构造函数传入的文件路径,接着交给class或者classLoader,调用getResourceAsStream获取到InputStream。

 

       所以,我们的private成员变量是这样子定义的:

 

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:12px;">public class ClassPathResource extends AbstractFileResolvingResource {  
  2.   
  3.     private final String path;  
  4.   
  5.     private ClassLoader classLoader;  
  6.   
  7.     private Class<?> clazz;</span>  

 

 

    主要构造函数(存在多个构造函数,但是都差不多啦):

 

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. public ClassPathResource(String path, ClassLoader classLoader) {  
  2.         Assert.notNull(path, "Path must not be null");  
  3.         String pathToUse = StringUtils.cleanPath(path);  
  4.         if (pathToUse.startsWith("/")) {  
  5.             pathToUse = pathToUse.substring(1);  
  6.         }  
  7.         this.path = pathToUse;  
  8.         this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());  
  9.     }  

 

 

    Assert类是spring的一个校验类,比如,如果path为空的话,则会抛出一个异常,异常信息为后面的"Path must not be null"。其实就是封装了一个判断是否为null的操作,查看Assert,发现还有很多类似函数,例如,判断为trueorfalse这种。

 

     之后处理你自己传入的路径。。。。因为这里默认使用ClassLoader来加载资源,所以,路径开头要去掉“/”。但是如果你不传入classLoader,则classLoader按照如下规则获取:

 

   

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:12px;">public static ClassLoader getDefaultClassLoader() {  
  2.         ClassLoader cl = null;  
  3.         try {  
  4.             cl = Thread.currentThread().getContextClassLoader();  
  5.         }  
  6.         catch (Throwable ex) {  
  7.             // Cannot access thread context ClassLoader - falling back to system class loader...  
  8.         }  
  9.         if (cl == null) {  
  10.             // No thread context class loader -> use class loader of this class.  
  11.             cl = ClassUtils.class.getClassLoader();  
  12.         }  
  13.         return cl;  
  14.     }</span>  



 

     首选我们安全的从当前线程获取类加载器的方法,但是这个方法在 某些情况下会返回null值(可以百度下Thread.currentThread().getContextClassLoader()获取classloader跟使用**Class.getClassLoader()方法有什么不同,如果懒的话,可以看看下面的代码),这个跟JVM的类加载器的层级关系有关。。。

 

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:12px;">/* 测试利用class或者classloader读取文件classpath下的文件 */  
  2.     public static void getResourceByClassOrClassLoader() {  
  3.         /* 
  4.          * Classloader是从classpath中读取资源的一个类, 
  5.          * 一般我们用classloader来加载class,实际上,但凡是处在classpath中的文件, 
  6.          * 我们称之为资源,都可以用classloader来读取。 
  7.          * 注意,使用classloader来加载资源的时候,目录前面不加“/” 
  8.          */  
  9.         System.out.println(TestResource.class.getClassLoader().getResource(  
  10.                 "applicationContext.xml"));  
  11.   
  12.         /* 这个API的起始路径是当前类的路径,如果要正确的读到资源,目标资源必须和当前class在同一级,或子目录里,可以用相对路径读取到。 */  
  13.         System.out.println(TestResource.class  
  14.                 .getResource("/applicationContext.xml"));  
  15.   
  16.         /*安全用法---提倡使用  From:http://www.cnblogs.com/gaoxing/p/4703412.html*/  
  17.         System.out.println( Thread.currentThread().getContextClassLoader().getResource(  
  18.                 "applicationContext.xml"));  
  19.           
  20.         /*读取到InputStream*/  
  21.         InputStream inputStream = TestResource.class.getClassLoader()  
  22.                 .getSystemResourceAsStream("applicationContext.xml");  
  23.         System.out.println(inputStream);  
  24.   
  25.     }</span>  


   区分下使用class 还有classLoader 这两种方式getResource在写法跟实现上有什么不同。

 

 

   这之后,构造函数完成, XML文件加载完毕。

 

 

三,其他方法

 

   1,示例:exists

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. @Override  
  2.     public boolean exists() {  
  3.         URL url;  
  4.         if (this.clazz != null) {  
  5.             url = this.clazz.getResource(this.path);  
  6.         }  
  7.         else {  
  8.             url = this.classLoader.getResource(this.path);  
  9.         }  
  10.         return (url != null);  
  11.     }  



 

       在对资源文件文件进行操作的时候,我们的首选还是使用Class类来进行操作,因为资源和我类文件的位置是相对固定的,可能这是一种潜规则+默认的写法吧。如果执行构造函数的时候没有传入class来进行初始化,则使用classLoader来判断文件。最 后return (url != null);写法挺简洁!

      这个类里面的getInputStream,getURL,getDescription都是类似的。

 

posted on 2017-04-20 17:47  navyhj  阅读(126)  评论(0)    收藏  举报