Spring的资源抽象Resource2实体类
一、文件系统资源 FileSystemResource
文件系统资源 FileSystemResource,资源以文件系统路径的方式表示,唯一一个实现了WritableResource接口的类。这个类由2个不可变的属性 file 和 path ,本质上就是一个java.io.File 的包装。这个类的 equals() 和 hashcode() 都通过属性 path 来操作。
public class FileSystemResource extends AbstractResource implements WritableResource { private final File file; // 不可变属性 private final String path; // 不可变属性 public FileSystemResource(File file) { // 简单的构造方法,path为file路径格式化后的样子 Assert.notNull(file, "File must not be null"); this.file = file; this.path = StringUtils.cleanPath(file.getPath()); } public FileSystemResource(String path) { //简单的构造方法 Assert.notNull(path, "Path must not be null"); this.file = new File(path); this.path = StringUtils.cleanPath(path); } public final String getPath() { //新增的方法,返回资源路径,方法不可重写 return this.path; } @Override public boolean exists() { return this.file.exists(); } @Override public boolean isReadable() { return (this.file.canRead() && !this.file.isDirectory()); } public InputStream getInputStream() throws IOException { //InputStreamSource接口的实现方法 return new FileInputStream(this.file); } @Override public URL getURL() throws IOException { //可见这个url是通过uri得到的 return this.file.toURI().toURL(); } @Override public URI getURI() throws IOException { return this.file.toURI(); } @Override public File getFile() { return this.file; } @Override public long contentLength() throws IOException { return this.file.length(); } @Override public Resource createRelative(String relativePath) { String pathToUse = StringUtils.applyRelativePath(this.path, relativePath); return new FileSystemResource(pathToUse); } @Override public String getFilename() { return this.file.getName(); } public String getDescription() { // 资源描述,直接用绝对路径来构造 return "file [" + this.file.getAbsolutePath() + "]"; } public boolean isWritable() { // WritableResource接口的实现方法 return (this.file.canWrite() && !this.file.isDirectory()); } public OutputStream getOutputStream() throws IOException { return new FileOutputStream(this.file); } @Override public boolean equals(Object obj) { //通过path来比较 return (obj == this || (obj instanceof FileSystemResource && this.path.equals(((FileSystemResource) obj).path))); } @Override public int hashCode() { // 文件资源的HashCode就是path的hashCode return this.path.hashCode(); } }
二、常用的ClassPathResource
ClassPathResource这个资源类表示的是类路径下的资源,资源以相对于类路径的方式表示,是基于class的 getResourceAsStream(this.path) 或者 this.classLoader.getResourceAsStream(this.path) 。
public class ClassPathResource extends AbstractFileResolvingResource { private final String path; private ClassLoader classLoader; private Class<?> clazz; /** * Create a new ClassPathResource for ClassLoader usage. * A leading slash will be removed, as the ClassLoader * resource access methods will not accept it. * <p>The thread context class loader will be used for * loading the resource. * @param path the absolute path within the class path * @see java.lang.ClassLoader#getResourceAsStream(String) * @see org.springframework.util.ClassUtils#getDefaultClassLoader() */ public ClassPathResource(String path) { this(path, (ClassLoader) null); } /** * Create a new ClassPathResource for ClassLoader usage. * A leading slash will be removed, as the ClassLoader * resource access methods will not accept it. * @param path the absolute path within the classpath * @param classLoader the class loader to load the resource with, * or {@code null} for the thread context class loader * @see ClassLoader#getResourceAsStream(String) */ public ClassPathResource(String path, ClassLoader classLoader) { Assert.notNull(path, "Path must not be null"); String pathToUse = StringUtils.cleanPath(path); if (pathToUse.startsWith("/")) { pathToUse = pathToUse.substring(1); } this.path = pathToUse; this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader()); } /** * Create a new ClassPathResource for Class usage. * The path can be relative to the given class, * or absolute within the classpath via a leading slash. * @param path relative or absolute path within the class path * @param clazz the class to load resources with * @see java.lang.Class#getResourceAsStream */ public ClassPathResource(String path, Class<?> clazz) { Assert.notNull(path, "Path must not be null"); this.path = StringUtils.cleanPath(path); this.clazz = clazz; } /** * Create a new ClassPathResource with optional ClassLoader and Class. * Only for internal usage. * @param path relative or absolute path within the classpath * @param classLoader the class loader to load the resource with, if any * @param clazz the class to load resources with, if any */ protected ClassPathResource(String path, ClassLoader classLoader, Class<?> clazz) { this.path = StringUtils.cleanPath(path); this.classLoader = classLoader; this.clazz = clazz; } /** * Return the path for this resource (as resource path within the class path). */ public final String getPath() { return this.path; } /** * Return the ClassLoader that this resource will be obtained from. */ public final ClassLoader getClassLoader() { return (this.classLoader != null ? this.classLoader : this.clazz.getClassLoader()); } /** * This implementation checks for the resolution of a resource URL. * @see java.lang.ClassLoader#getResource(String) * @see java.lang.Class#getResource(String) */ @Override public boolean exists() { URL url; if (this.clazz != null) { url = this.clazz.getResource(this.path); } else { url = this.classLoader.getResource(this.path); } return (url != null); } /** * This implementation opens an InputStream for the given class path resource. * @see java.lang.ClassLoader#getResourceAsStream(String) * @see java.lang.Class#getResourceAsStream(String) */ public InputStream getInputStream() throws IOException { InputStream is; if (this.clazz != null) { is = this.clazz.getResourceAsStream(this.path); } else { is = this.classLoader.getResourceAsStream(this.path); } if (is == null) { throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist"); } return is; } /** * This implementation returns a URL for the underlying class path resource. * @see java.lang.ClassLoader#getResource(String) * @see java.lang.Class#getResource(String) */ @Override public URL getURL() throws IOException { URL url; if (this.clazz != null) { url = this.clazz.getResource(this.path); } else { url = this.classLoader.getResource(this.path); } if (url == null) { throw new FileNotFoundException(getDescription() + " cannot be resolved to URL because it does not exist"); } return url; } /** * This implementation creates a ClassPathResource, applying the given path * relative to the path of the underlying resource of this descriptor. * @see org.springframework.util.StringUtils#applyRelativePath(String, String) */ @Override public Resource createRelative(String relativePath) { String pathToUse = StringUtils.applyRelativePath(this.path, relativePath); return new ClassPathResource(pathToUse, this.classLoader, this.clazz); } /** * This implementation returns the name of the file that this class path * resource refers to. * @see org.springframework.util.StringUtils#getFilename(String) */ @Override public String getFilename() { return StringUtils.getFilename(this.path); } /** * This implementation returns a description that includes the class path location. */ public String getDescription() { StringBuilder builder = new StringBuilder("class path resource ["); String pathToUse = path; if (this.clazz != null && !pathToUse.startsWith("/")) { builder.append(ClassUtils.classPackageAsResourcePath(this.clazz)); builder.append('/'); } if (pathToUse.startsWith("/")) { pathToUse = pathToUse.substring(1); } builder.append(pathToUse); builder.append(']'); return builder.toString(); } /** * This implementation compares the underlying class path locations. */ @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof ClassPathResource) { ClassPathResource otherRes = (ClassPathResource) obj; return (this.path.equals(otherRes.path) && ObjectUtils.nullSafeEquals(this.classLoader, otherRes.classLoader) && ObjectUtils.nullSafeEquals(this.clazz, otherRes.clazz)); } return false; } /** * This implementation returns the hash code of the underlying * class path location. */ @Override public int hashCode() { return this.path.hashCode(); } }
三、Url资源——UrlResource
UrlResource这个资源类封装了可以以URL表示的各种资源。这个资源类有3个属性,一个URI、一个URL,以及一个规范化后的URL,用于资源间的比较以及计算HashCode。
public class UrlResource extends AbstractFileResolvingResource { /** * Original URI, if available; used for URI and File access. */ private final URI uri; /** * Original URL, used for actual access. */ private final URL url; /** * Cleaned URL (with normalized path), used for comparisons. */ private final URL cleanedUrl; /** * Create a new UrlResource based on the given URI object. * @param uri a URI * @throws MalformedURLException if the given URL path is not valid */ public UrlResource(URI uri) throws MalformedURLException { Assert.notNull(uri, "URI must not be null"); this.uri = uri; this.url = uri.toURL(); this.cleanedUrl = getCleanedUrl(this.url, uri.toString()); } /** * Create a new UrlResource based on the given URL object. * @param url a URL */ public UrlResource(URL url) { Assert.notNull(url, "URL must not be null"); this.url = url; this.cleanedUrl = getCleanedUrl(this.url, url.toString()); this.uri = null; } /** * Create a new UrlResource based on a URL path. * <p>Note: The given path needs to be pre-encoded if necessary. * @param path a URL path * @throws MalformedURLException if the given URL path is not valid * @see java.net.URL#URL(String) */ public UrlResource(String path) throws MalformedURLException { Assert.notNull(path, "Path must not be null"); this.uri = null; this.url = new URL(path); this.cleanedUrl = getCleanedUrl(this.url, path); } /** * Create a new UrlResource based on a URI specification. * <p>The given parts will automatically get encoded if necessary. * @param protocol the URL protocol to use (e.g. "jar" or "file" - without colon); * also known as "scheme" * @param location the location (e.g. the file path within that protocol); * also known as "scheme-specific part" * @throws MalformedURLException if the given URL specification is not valid * @see java.net.URI#URI(String, String, String) */ public UrlResource(String protocol, String location) throws MalformedURLException { this(protocol, location, null); } /** * Create a new UrlResource based on a URI specification. * <p>The given parts will automatically get encoded if necessary. * @param protocol the URL protocol to use (e.g. "jar" or "file" - without colon); * also known as "scheme" * @param location the location (e.g. the file path within that protocol); * also known as "scheme-specific part" * @param fragment the fragment within that location (e.g. anchor on an HTML page, * as following after a "#" separator) * @throws MalformedURLException if the given URL specification is not valid * @see java.net.URI#URI(String, String, String) */ public UrlResource(String protocol, String location, String fragment) throws MalformedURLException { try { this.uri = new URI(protocol, location, fragment); this.url = this.uri.toURL(); this.cleanedUrl = getCleanedUrl(this.url, this.uri.toString()); } catch (URISyntaxException ex) { MalformedURLException exToThrow = new MalformedURLException(ex.getMessage()); exToThrow.initCause(ex); throw exToThrow; } } /** * Determine a cleaned URL for the given original URL. * @param originalUrl the original URL * @param originalPath the original URL path * @return the cleaned URL * @see org.springframework.util.StringUtils#cleanPath */ private URL getCleanedUrl(URL originalUrl, String originalPath) { try { return new URL(StringUtils.cleanPath(originalPath)); } catch (MalformedURLException ex) { // Cleaned URL path cannot be converted to URL // -> take original URL. return originalUrl; } } /** * This implementation opens an InputStream for the given URL. * It sets the "UseCaches" flag to {@code false}, * mainly to avoid jar file locking on Windows. * @see java.net.URL#openConnection() * @see java.net.URLConnection#setUseCaches(boolean) * @see java.net.URLConnection#getInputStream() */ public InputStream getInputStream() throws IOException { URLConnection con = this.url.openConnection(); ResourceUtils.useCachesIfNecessary(con); try { return con.getInputStream(); } catch (IOException ex) { // Close the HTTP connection (if applicable). if (con instanceof HttpURLConnection) { ((HttpURLConnection) con).disconnect(); } throw ex; } } /** * This implementation returns the underlying URL reference. */ @Override public URL getURL() throws IOException { return this.url; } /** * This implementation returns the underlying URI directly, * if possible. */ @Override public URI getURI() throws IOException { if (this.uri != null) { return this.uri; } else { return super.getURI(); } } /** * This implementation returns a File reference for the underlying URL/URI, * provided that it refers to a file in the file system. * @see org.springframework.util.ResourceUtils#getFile(java.net.URL, String) */ @Override public File getFile() throws IOException { if (this.uri != null) { return super.getFile(this.uri); } else { return super.getFile(); } } /** * This implementation creates a UrlResource, applying the given path * relative to the path of the underlying URL of this resource descriptor. * @see java.net.URL#URL(java.net.URL, String) */ @Override public Resource createRelative(String relativePath) throws MalformedURLException { if (relativePath.startsWith("/")) { relativePath = relativePath.substring(1); } return new UrlResource(new URL(this.url, relativePath)); } /** * This implementation returns the name of the file that this URL refers to. * @see java.net.URL#getFile() * @see java.io.File#getName() */ @Override public String getFilename() { return new File(this.url.getFile()).getName(); } /** * This implementation returns a description that includes the URL. */ public String getDescription() { return "URL [" + this.url + "]"; } /** * This implementation compares the underlying URL references. */ @Override public boolean equals(Object obj) { return (obj == this || (obj instanceof UrlResource && this.cleanedUrl.equals(((UrlResource) obj).cleanedUrl))); } /** * This implementation returns the hash code of the underlying URL reference. */ @Override public int hashCode() { return this.cleanedUrl.hashCode(); } }
四、Servlet上下文资源——ServletContextResource
实现基本就是基于 this.servletContext.getResource(this.path) 或 this.servletContext.getResourceAsStream(this.path) 这两个方法。
public class ServletContextResource extends AbstractFileResolvingResource implements ContextResource { private final ServletContext servletContext; private final String path; /** * Create a new ServletContextResource. * <p>The Servlet spec requires that resource paths start with a slash, * even if many containers accept paths without leading slash too. * Consequently, the given path will be prepended with a slash if it * doesn't already start with one. * @param servletContext the ServletContext to load from * @param path the path of the resource */ public ServletContextResource(ServletContext servletContext, String path) { // check ServletContext Assert.notNull(servletContext, "Cannot resolve ServletContextResource without ServletContext"); this.servletContext = servletContext; // check path Assert.notNull(path, "Path is required"); String pathToUse = StringUtils.cleanPath(path); if (!pathToUse.startsWith("/")) { pathToUse = "/" + pathToUse; } this.path = pathToUse; } /** * Return the ServletContext for this resource. */ public final ServletContext getServletContext() { return this.servletContext; } /** * Return the path for this resource. */ public final String getPath() { return this.path; } /** * This implementation checks {@code ServletContext.getResource}. * @see javax.servlet.ServletContext#getResource(String) */ @Override public boolean exists() { try { URL url = this.servletContext.getResource(this.path); return (url != null); } catch (MalformedURLException ex) { return false; } } /** * This implementation delegates to {@code ServletContext.getResourceAsStream}, * which returns {@code null} in case of a non-readable resource (e.g. a directory). * @see javax.servlet.ServletContext#getResourceAsStream(String) */ @Override public boolean isReadable() { InputStream is = this.servletContext.getResourceAsStream(this.path); if (is != null) { try { is.close(); } catch (IOException ex) { // ignore } return true; } else { return false; } } /** * This implementation delegates to {@code ServletContext.getResourceAsStream}, * but throws a FileNotFoundException if no resource found. * @see javax.servlet.ServletContext#getResourceAsStream(String) */ public InputStream getInputStream() throws IOException { InputStream is = this.servletContext.getResourceAsStream(this.path); if (is == null) { throw new FileNotFoundException("Could not open " + getDescription()); } return is; } /** * This implementation delegates to {@code ServletContext.getResource}, * but throws a FileNotFoundException if no resource found. * @see javax.servlet.ServletContext#getResource(String) */ @Override public URL getURL() throws IOException { URL url = this.servletContext.getResource(this.path); if (url == null) { throw new FileNotFoundException( getDescription() + " cannot be resolved to URL because it does not exist"); } return url; } /** * This implementation resolves "file:" URLs or alternatively delegates to * {@code ServletContext.getRealPath}, throwing a FileNotFoundException * if not found or not resolvable. * @see javax.servlet.ServletContext#getResource(String) * @see javax.servlet.ServletContext#getRealPath(String) */ @Override public File getFile() throws IOException { URL url = this.servletContext.getResource(this.path); if (url != null && ResourceUtils.isFileURL(url)) { // Proceed with file system resolution... return super.getFile(); } else { String realPath = WebUtils.getRealPath(this.servletContext, this.path); return new File(realPath); } } /** * This implementation creates a ServletContextResource, applying the given path * relative to the path of the underlying file of this resource descriptor. * @see org.springframework.util.StringUtils#applyRelativePath(String, String) */ @Override public Resource createRelative(String relativePath) { String pathToUse = StringUtils.applyRelativePath(this.path, relativePath); return new ServletContextResource(this.servletContext, pathToUse); } /** * This implementation returns the name of the file that this ServletContext * resource refers to. * @see org.springframework.util.StringUtils#getFilename(String) */ @Override public String getFilename() { return StringUtils.getFilename(this.path); } /** * This implementation returns a description that includes the ServletContext * resource location. */ public String getDescription() { return "ServletContext resource [" + this.path + "]"; } public String getPathWithinContext() { return this.path; } /** * This implementation compares the underlying ServletContext resource locations. */ @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof ServletContextResource) { ServletContextResource otherRes = (ServletContextResource) obj; return (this.servletContext.equals(otherRes.servletContext) && this.path.equals(otherRes.path)); } return false; } /** * This implementation returns the hash code of the underlying * ServletContext resource location. */ @Override public int hashCode() { return this.path.hashCode(); } }
五、其它不常用的实现类
1、字节数组资源——ByteArrayResource
若需要操作描述一个字节数组,可以用这个资源类。ByteArrayResource可多次读取数组资源。
2、描述性资源——DescriptiveResource
若一个资源,仅仅有一个描述,非常抽象的这种情况,可以用这个资源类,它并没有指向一个实际的可读的资源。
3、输入流资源——InputStreamResource
输入流资源InputStreamResource,是一个不可变InputStream的包装和一个不可变的描述字符串。此外还有一个私有成员变量Boolean read用于限制本资源的InputStream不可被重复获取。这个包装类指向的是一个已经打开的资源,所以它的 isOpen()总是返回true。而且它不能重复获取资源,只能读取一次
4、VFS资源——VfsResource
vfs是Virtual File System虚拟文件系统,也称为虚拟文件系统开关(Virtual Filesystem Switch).是Linux档案系统对外的接口。任何要使用档案系统的程序都必须经由这层接口来使用它。(摘自百度百科...)它能一致的访问物理文件系统、jar资源、zip资源、war资源等,VFS能把这些资源一致的映射到一个目录上,访问它们就像访问物理文件资源一样,而其实这些资源不存在于物理文件系统。
5、Portlet上下文资源——PortletContextResource
Portlet是基于java的web组件,由portlet容器管理,并由容器处理请求,生产动态内容。这个资源类封装了一个不可变的javax.portlet.PortletContext对象和一个不可变的String对象代表路径。类中所有操作都基于这两个属性。PortletContextResource对象实现了ContextResource接口,实现了方法String getPathWithinContext(),即返回自身的path属性。
http://www.cnblogs.com/zrtqsk/p/4015985.html