Spring5:就这一次,搞定资源加载器之FileSystemResourceLoader
FileSystemResourceLoader继承自DefaultResourceLoader,并重写了getResourceByPath(String path)方法,返回FileSystemContextResource类型资源,源码如下:/** Copyright 2002-2017 the original author or authors.** Licensed unde...
FileSystemResourceLoader继承自DefaultResourceLoader,并重写了getResourceByPath(String path)方法,返回FileSystemContextResource类型资源,源码如下:
/*
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.core.io;
/**
* {@link ResourceLoader} implementation that resolves plain paths as
* file system resources rather than as class path resources
* (the latter is {@link DefaultResourceLoader}'s default strategy).
*
* <p><b>NOTE:</b> Plain paths will always be interpreted as relative
* to the current VM working directory, even if they start with a slash.
* (This is consistent with the semantics in a Servlet container.)
* <b>Use an explicit "file:" prefix to enforce an absolute file path.</b>
*
* <p>{@link org.springframework.context.support.FileSystemXmlApplicationContext}
* is a full-fledged ApplicationContext implementation that provides
* the same resource path resolution strategy.
*
* @author Juergen Hoeller
* @since 1.1.3
* @see DefaultResourceLoader
* @see org.springframework.context.support.FileSystemXmlApplicationContext
*/
public class FileSystemResourceLoader extends DefaultResourceLoader {
/**
* Resolve resource paths as file system paths.
* <p>Note: Even if a given path starts with a slash, it will get
* interpreted as relative to the current VM working directory.
* @param path the path to the resource
* @return the corresponding Resource handle
* @see FileSystemResource
* @see org.springframework.web.context.support.ServletContextResourceLoader#getResourceByPath
*/
@Override
protected Resource getResourceByPath(String path) {
if (path.startsWith("/")) {
path = path.substring(1);
}
return new FileSystemContextResource(path);
}
/**
* FileSystemResource that explicitly expresses a context-relative path
* through implementing the ContextResource interface.
*/
private static class FileSystemContextResource extends FileSystemResource implements ContextResource {
public FileSystemContextResource(String path) {
super(path);
}
@Override
public String getPathWithinContext() {
return getPath();
}
}
}
FileSystemResourceLoader表示从文件系统中加载资源,所以咱们用FileSystemResourceLoader加载资源时应该给出资源的绝对路径,假设在classpath下有一个文件叫test.xml,咱们加载它该怎么写呢? 可以这么写:
@Controller
public class LoginController {
@RequestMapping(value="/index.html")
public String loginPage() throws IOException {
ResourceLoader resourceLoader=new FileSystemResourceLoader();
Resource resource=resourceLoader.getResource("D:\\ALANWANG-AIA\\Horse-workspace\\chapter3\\target\\classes\\test.xml");
System.out.println(resource.getInputStream());
return "index";
}
}
启动服务器,访问index.html ,观察输出:
sun.nio.ch.ChannelInputStream@274a058c
这个测试代码为什么要加一句
System.out.println(resource.getInputStream());
呢?这里要填一个坑,咱们知道,不管是DeafultResoureLoader还是FileSystemResourceLoader也好,都是ResourceLoader的子子孙孙,ResourceLoader中 getResource(String location);方法有一个现象就是该方法返回的Resource实例并不保证该Resource一定是存在的!重要的话再说一遍!该方法返回的Resource实例并不保证该Resource一定是存在的!,所以要加一个输出看看是否真的加载到了,咱们实际使用时一定要用resource.exists()判断一下!
当然,咱们已可以皮一下,非要传个相对路径进来,像这样:
@Controller
public class LoginController {
@RequestMapping(value="/index.html")
public String loginPage() throws IOException {
ResourceLoader resourceLoader=new FileSystemResourceLoader();
Resource resource=resourceLoader.getResource("test.xml");
System.out.println(resource.getInputStream());
return "index";
}
}
启动服务器,访问index.html,观察输出:
[INFO] Restart completed at Fri Jul 06 10:48:31 CST 2018
[WARNING] /chapter3/index.html java.nio.file.NoSuchFileException: test.xml
发现挂了,实际上test.xml是放在classpath下的,假如这么写肯定是没问题的,
Resource resource=resourceLoader.getResource("classpath:test.xml");
那咱们非要用相对路径,又非要用FileSystemResourceLoader咋办?咱们看一下FileSystemResourceLoader是如何实现的:
/**
* Resolve resource paths as file system paths.
* <p>Note: Even if a given path starts with a slash, it will get
* interpreted as relative to the current VM working directory.
* @param path the path to the resource
* @return the corresponding Resource handle
* @see FileSystemResource
* @see org.springframework.web.context.support.ServletContextResourceLoader#getResourceByPath
*/
@Override
protected Resource getResourceByPath(String path) {
if (path.startsWith("/")) {
path = path.substring(1);
}
return new FileSystemContextResource(path);
}
如果path以斜杠开头,会把斜杠截取掉,这段代码说明就算咱们传个斜杠打头的进来,也会被转成相对路径,只不过该方法的注释信息已经告诉咱们了,如果是个相对路径的话,相对的就是虚拟机的工作目录,也就是说该项目的根目录,咱们的这个测试项目叫chapter3,现在chapter3就是虚拟机的工作目录,因此咱们可以这么写:
@Controller
public class LoginController {
@RequestMapping(value="/index.html")
public String loginPage() throws IOException {
ResourceLoader resourceLoader=new FileSystemResourceLoader();
Resource resource=resourceLoader.getResource("target\\classes\\test.xml");
System.out.println(resource.getInputStream());
return "index";
}
}
启动服务器,访问index.html,观察输出:
[INFO] Restart completed at Fri Jul 06 10:59:47 CST 2018
sun.nio.ch.ChannelInputStream@783ccd29
成功了,不过是不是感觉这种写法怪怪的?反正我觉得是,所以咱们的总结就是,使用FileSystemResourceLoader加载资源时,最好给出资源的绝对路径,如果使用“\”打头的或者是相对路径,可能会有坑。也由此得出一个结论,已斜杠打头资源路径指的是项目的根路径,或者说jvm的启动路径等等。普通的java项目就是项目路径,web项目就要看服务器的启动路径了,tomcat是bin,本例中咱们用的是jetty,咱们知道,jetty就是个jar包,用的时候扔到项目的classpath里就可以了,所以咱们测试项目的jvm启动路径就是chapter3 。是不是挺麻烦,是不是有点绕,所以除非有特殊原因必须使用FileSystemResourceLoader,否这咱们还是老实巴交的用classpath吧!
以上纯属个人理解,如有错误,还望读多指正,非常感谢!!!
更多推荐
所有评论(0)