One - One Code All

Blog Content

通过Spring Resource接口获取资源,读取本地资源文件进行文件下载

Java   2014-07-04 16:38:11

通过Spring Resource接口获取资源,读取本地资源文件进行文件下载。


ClassPathResource使用简介

使用Spring的ClassPathResource来读取maven项目resource下的文件。我们获取到resource对象后,可以调用resouce.getFile()方法来获取文件。

具体代码如下:

Resource resource = new ClassPathResource(“static/Std_Resource_Train_Model.xls”);
// 因为Resouce是一个接口 所以我们可以使用它的实现类ClassPathResource来new一个对象。
//而构造方法的参数便是resources目录下的文件路径,注意这里是使用的相对路径(相对于resouces目录而言的)。
/**
     * 下载模板
	 *  模板位置:项目.main.resource目录下template/import_template.xlsx
     */
	@GetMapping("/slot/downloadSlotTemplate")
    public void downloadTemplate(HttpServletResponse response) throws UnsupportedEncodingException {

        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");

        String fileName = "模板.xlsx";
        fileName = new String(fileName.getBytes("UTF-8"), "iso-8859-1");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName);

        ServletOutputStream out = null;
        try {
            ClassPathResource classPathResource = new ClassPathResource("template/import_template.xlsx");
            byte[] bytes = FileCopyUtils.copyToByteArray(classPathResource.getInputStream());
            out = response.getOutputStream();
            out.write(bytes);
            out.flush();

        } catch (FileNotFoundException e) {
            log.error("模板文件不存在 ", e);
        } catch (IOException e) {
            log.error("访问资源异常",e);
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                log.error("关闭io流异常", e);
            }
        }

    }

在Spring内部,针对于资源文件有一个统一的接口Resource表示。其主要实现类有ClassPathResource、FileSystemResource、UrlResource、ByteArrayResource、ServletContextResource和InputStreamResource。Resource接口中主要定义有以下方法:


exists():用于判断对应的资源是否真的存在。

isReadable():用于判断对应资源的内容是否可读。需要注意的是当其结果为true的时候,其内容未必真的可读,但如果返回false,则其内容必定不可读。

 isOpen():用于判断当前资源是否代表一个已打开的输入流,如果结果为true,则表示当前资源的输入流不可多次读取,而且在读取以后需要对它进行关闭,以防止内存泄露。该方法主要针对于InputStreamResource,实现类中只有它的返回结果为true,其他都为false。

getURL():返回当前资源对应的URL。如果当前资源不能解析为一个URL则会抛出异常。如ByteArrayResource就不能解析为一个URL。

getFile():返回当前资源对应的File。如果当前资源不能以绝对路径解析为一个File则会抛出异常。如ByteArrayResource就不能解析为一个File。

getInputStream():获取当前资源代表的输入流。除了InputStreamResource以外,其它Resource实现类每次调用getInputStream()方法都将返回一个全新的InputStream。


 

ClassPathResource可用来获取类路径下的资源文件。假设我们有一个资源文件test.txt在类路径下,我们就可以通过给定对应资源文件在类路径下的路径path来获取它,new ClassPathResource(“test.txt”)。

FileSystemResource可用来获取文件系统里面的资源。我们可以通过对应资源文件的文件路径来构建一个FileSystemResource。FileSystemResource还可以往对应的资源文件里面写内容,当然前提是当前资源文件是可写的,这可以通过其isWritable()方法来判断。FileSystemResource对外开放了对应资源文件的输出流,可以通过getOutputStream()方法获取到。

UrlResource可用来代表URL对应的资源,它对URL做了一个简单的封装。通过给定一个URL地址,我们就能构建一个UrlResource。

ByteArrayResource是针对于字节数组封装的资源,它的构建需要一个字节数组。

ServletContextResource是针对于ServletContext封装的资源,用于访问ServletContext环境下的资源。ServletContextResource持有一个ServletContext的引用,其底层是通过ServletContext的getResource()方法和getResourceAsStream()方法来获取资源的。

InputStreamResource是针对于输入流封装的资源,它的构建需要一个输入流。

/** 
    * ClassPathResource可以用来获取类路径下的资源 
    * @throws IOException 
    */ 
	@Test  
	public void testClassPath() throws IOException {  
      Resource resource = new ClassPathResource("test.txt");  
      String fileName = resource.getFilename();  
      System.out.println(fileName);  
//    resource.getFile();   //获取资源对应的文件  
//    resource.getURL(); //获取资源对应的URL  
      if (resource.isReadable()) {  
         //每次都会打开一个新的流  
         InputStream is = resource.getInputStream();  
         this.printContent(is);  
      }  
   }  

    /** 
    * 针对于URL进行封装的Resource,可用来从URL获取资源内容 
    * @throws Exception 
    */  
   @Test  
   public void testURL() throws Exception {  
      UrlResource resource = new UrlResource("http://www.google.com.hk");  
      if (resource.isReadable()) {  
         //URLConnection对应的getInputStream()。  
         printContent(resource.getInputStream());  
      }  
   }  

    /** 
    * 针对于输入流的Resource,其getInputStream()方法只能被调用一次。 
    * @throws Exception 
    */  
   @Test  
   public void testInputStream() throws Exception {  
      InputStream is = new FileInputStream("/test.txt");  
      InputStreamResource resource = new InputStreamResource(is);  
      //对于InputStreamResource而言,其getInputStream()方法只能调用一次,继续调用将抛出异常。  
      InputStream target = resource.getInputStream();   //返回的就是构件时的那个InputStream  
      //is将在printContent方法里面进行关闭  
      printContent(target);  
   }  

   /** 
    * FileSystemResource可以用来获取文件系统里面的资源,对于FileSystemResource而言我们 
    * 可以获取到其对应的输出流。 
    * @throws IOException 
    */  
   @Test  
   public void testFileSystem() throws IOException {  
      FileSystemResource resource = new FileSystemResource("D:\\test.txt");  
      if (resource.isReadable()) {  
         //FileInputStream  
         printContent(resource.getInputStream());  
      }  
	  if (resource.isWritable()) {  
         //每次都会获取到一个新的输出流  
         OutputStream os = resource.getOutputStream();  
         BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));  
         bw.write("你好,中国!");  
         bw.flush();  
         if (os != null) {  
            os.close();  
         }  
         if (bw != null) {  
            bw.close();  
         }  
      }  
   }

通过ResourceLoader获取资源


在Spring里面还定义有一个ResourceLoader接口,该接口中只定义了一个用于获取Resource的getResource(String location)方法。它的实现类有很多,这里我们先挑一个DefaultResourceLoader来讲。DefaultResourceLoader在获取Resource时采用的是这样的策略:首先判断指定的location是否含有“classpath:”前缀,如果有则把location去掉“classpath:”前缀返回对应的ClassPathResource;否则就把它当做一个URL来处理,封装成一个UrlResource进行返回;如果当成URL处理也失败的话就把location对应的资源当成是一个ClassPathResource进行返回。

@Test  
    public void testResourceLoader() {  
       ResourceLoader loader = new DefaultResourceLoader();  
       Resource resource = loader.getResource("http://www.google.com.hk");  
       System.out.println(resource instanceof UrlResource); //true  
       //注意这里前缀不能使用“classpath*:”,这样不能真正访问到对应的资源,exists()返回false  
       resource = loader.getResource("classpath:test.txt");  
       System.out.println(resource instanceof ClassPathResource); //true  
       resource = loader.getResource("test.txt");  
       System.out.println(resource instanceof ClassPathResource); //true  
    }

ApplicationContext接口也继承了ResourceLoader接口,所以它的所有实现类都实现了ResourceLoader接口,都可以用来获取Resource。


对于ClassPathXmlApplicationContext而言,它在获取Resource时继承的是它的父类DefaultResourceLoader的策略。


FileSystemXmlApplicationContext也继承了DefaultResourceLoader,但是它重写了DefaultResourceLoader的getResourceByPath(String path)方法。所以它在获取资源文件时首先也是判断指定的location是否包含“classpath:”前缀,如果包含,则把location中“classpath:”前缀后的资源从类路径下获取出来,当做一个ClassPathResource;否则,继续尝试把location封装成一个URL,返回对应的UrlResource;如果还是失败,则把location指定位置的资源当做一个FileSystemResource进行返回。



上一篇:airflow backfill用法
下一篇:量化投资基础介绍

The minute you think of giving up, think of the reason why you held on so long.