All Downloads are FREE. Search and download functionalities are using the official Maven repository.

site.sorghum.anno.method.resource.ResourceFinder Maven / Gradle / Ivy

The newest version!
package site.sorghum.anno.method.resource;

import cn.hutool.core.collection.EnumerationIter;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.resource.FileResource;
import cn.hutool.core.io.resource.MultiResource;
import cn.hutool.core.io.resource.Resource;
import cn.hutool.core.text.AntPathMatcher;
import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.ClassLoaderUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;

import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.zip.ZipException;

/**
 * 资源查找器
*

* 参考Spring的PathMatchingResourcePatternResolver,实现classpath资源查找,利用{@link AntPathMatcher}筛选资源。 * * @author Spring, Looly */ public class ResourceFinder { /** * 构建新的ResourceFinder,使用当前环境的类加载器 * * @return ResourceFinder */ public static ResourceFinder of() { return of(ClassLoaderUtil.getClassLoader()); } /** * 构建新的ResourceFinder * * @param classLoader 类加载器,用于限定查找范围 * @return ResourceFinder */ public static ResourceFinder of(final ClassLoader classLoader) { return new ResourceFinder(classLoader); } private final ClassLoader classLoader; private final AntPathMatcher pathMatcher; /** * 构造 * * @param classLoader 类加载器,用于定义查找资源的范围 */ public ResourceFinder(final ClassLoader classLoader) { this.classLoader = classLoader; this.pathMatcher = new AntPathMatcher(); } /** * 查找给定表达式对应的资源 * * @param locationPattern 路径表达式 * @return {@link MultiResource} */ public MultiResource find(final String locationPattern) { // 根目录,如 "/WEB-INF/*.xml" 返回 "/WEB-INF/" final String rootDirPath = determineRootDir(locationPattern); // 子表达式,如"/WEB-INF/*.xml" 返回 "*.xml" final String subPattern = locationPattern.substring(rootDirPath.length()); final MultiResource result = new MultiResource(); // 遍历根目录下所有资源,并过滤保留符合条件的资源 for (final Resource rootResource : site.sorghum.anno.method.resource.ResourceUtil.getResources(rootDirPath, classLoader)) { if (rootResource instanceof JarResource) { // 在jar包中 try { MultiResource inJar = findInJar((JarResource) rootResource, subPattern); for (Resource resource : inJar) { result.add(resource); } } catch (final IOException e) { throw new IORuntimeException(e); } } else if (rootResource instanceof FileResource) { // 文件夹中 MultiResource inDir = findInDir((FileResource) rootResource, subPattern); for (Resource resource : inDir) { result.add(resource); } } else { throw new IORuntimeException("Unsupported resource type: {}", rootResource.getClass().getName()); } } return result; } /** * 查找jar包中的资源 * * @param rootResource 根资源,为jar包文件 * @param subPattern 子表达式,如 *.xml * @return 符合条件的资源 * @throws IOException IO异常 */ protected MultiResource findInJar(final JarResource rootResource, final String subPattern) throws IOException { final URL rootDirURL = rootResource.getUrl(); final URLConnection conn = rootDirURL.openConnection(); final JarFile jarFile; String rootEntryPath; final boolean closeJarFile; if (conn instanceof JarURLConnection) { final JarURLConnection jarCon = (JarURLConnection) conn; URLUtil.useCachesIfNecessary(jarCon); jarFile = jarCon.getJarFile(); final JarEntry jarEntry = jarCon.getJarEntry(); rootEntryPath = (jarEntry != null ? jarEntry.getName() : StrUtil.EMPTY); closeJarFile = !jarCon.getUseCaches(); } else { // 去除子路径后重新获取jar文件 final String urlFile = rootDirURL.getFile(); try { int separatorIndex = urlFile.indexOf(URLUtil.WAR_URL_SEPARATOR); if (separatorIndex == -1) { separatorIndex = urlFile.indexOf(URLUtil.JAR_URL_SEPARATOR); } if (separatorIndex != -1) { final String jarFileUrl = urlFile.substring(0, separatorIndex); rootEntryPath = urlFile.substring(separatorIndex + 2); // both separators are 2 chars jarFile = JarResource.ofJar(jarFileUrl); } else { jarFile = new JarFile(urlFile); rootEntryPath = StrUtil.EMPTY; } closeJarFile = true; } catch (final ZipException ex) { return new MultiResource(); } } rootEntryPath = StrUtil.addSuffixIfNot(rootEntryPath, StrUtil.SLASH); // 遍历jar中的entry,筛选之 final MultiResource result = new MultiResource(); try { String entryPath; for (final JarEntry entry : new EnumerationIter<>(jarFile.entries())) { entryPath = entry.getName(); if (entryPath.startsWith(rootEntryPath)) { final String relativePath = entryPath.substring(rootEntryPath.length()); if (pathMatcher.match(subPattern, relativePath)) { result.add(ResourceUtil.getResource(ResourceUtil.getURL(rootDirURL, relativePath))); } } } } finally { if (closeJarFile) { IoUtil.close(jarFile); } } return result; } /** * 遍历目录查找指定表达式匹配的文件列表 * * @param resource 文件资源 * @param subPattern 子表达式 * @return 满足条件的文件 */ protected MultiResource findInDir(final FileResource resource, final String subPattern) { final MultiResource result = new MultiResource(); final File rootDir = resource.getFile(); if (!rootDir.exists() || !rootDir.isDirectory() || !rootDir.canRead()) { // 保证给定文件存在、为目录且可读 return result; } final String fullPattern = replaceBackSlash(rootDir.getAbsolutePath() + StrUtil.SLASH + subPattern); ResourceUtil.walkFiles(rootDir, (file -> { final String currentPath = replaceBackSlash(file.getAbsolutePath()); if (file.isDirectory()) { // 检查目录是否满足表达式开始规则,满足则继续向下查找,否则跳过 return pathMatcher.matchStart(fullPattern, StrUtil.addSuffixIfNot(currentPath, StrUtil.SLASH)); } if (pathMatcher.match(fullPattern, currentPath)) { result.add(new FileResource(file)); return true; } return false; })); return result; } /** * 根据给定的路径表达式,找到跟路径
* 根路径即不包含表达式的路径,如 "/WEB-INF/*.xml" 返回 "/WEB-INF/" * * @param location 路径表达式 * @return root dir */ protected String determineRootDir(final String location) { final int prefixEnd = location.indexOf(':') + 1; int rootDirEnd = location.length(); while (rootDirEnd > prefixEnd && pathMatcher.isPattern(location.substring(prefixEnd, rootDirEnd))) { rootDirEnd = location.lastIndexOf(CharUtil.SLASH, rootDirEnd - 2) + 1; } if (rootDirEnd == 0) { rootDirEnd = prefixEnd; } return location.substring(0, rootDirEnd); } /** * 替换'\'为'/' * * @param path 路径 * @return 替换后的路径 */ private static String replaceBackSlash(final String path) { return StrUtil.isEmpty(path) ? path : path.replace(CharUtil.BACKSLASH, CharUtil.SLASH); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy