IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> java扫描jar包路径下文件(warjar都能使用) -> 正文阅读

[Java知识库]java扫描jar包路径下文件(warjar都能使用)

百度找了一堆垃圾没一个有用的,在这里感觉jfinal作者提供的思路,话不多说直接上代码


import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;


/**
 * PathScanner 扫描 @Path 注解,实现路由扫描功能
 */
public class ClassScanner {

	// 存放已被扫描过的 controller,避免被多次扫描
	private static final Set<Class<?>> scannedClass = new HashSet<>();

	// 扫描的基础 package,只扫描该包及其子包之下的类
	private String basePackage;

	private ClassLoader classLoader;

	public ClassScanner(String basePackage) {
		if (basePackage == null || basePackage.equals("")) {
			throw new IllegalArgumentException("basePackage can not be blank");
		}

		String bp = basePackage.replace('.', '/');
		bp = bp.endsWith("/") ? bp : bp + '/'; // 添加后缀字符 '/'
		bp = bp.startsWith("/") ? bp.substring(1) : bp; // 删除前缀字符 '/'

		this.basePackage = bp;
	}

	public Set<Class<?>> scan() {
		try {
			classLoader = getClassLoader();
			List<URL> urlList = getResources();
			scanResources(urlList);
			return scannedClass;
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	private ClassLoader getClassLoader() {
		ClassLoader ret = Thread.currentThread().getContextClassLoader();
		return ret != null ? ret : ClassScanner.class.getClassLoader();
	}

	private List<URL> getResources() throws IOException {
		List<URL> ret = new ArrayList<>();

		// 用于去除重复
		Set<String> urlSet = new HashSet<>();
		// ClassLoader.getResources(...) 参数只支持包路径分隔符为 '/',而不支持 '\'
		Enumeration<URL> urls = classLoader.getResources(basePackage);
		while (urls.hasMoreElements()) {
			URL url = urls.nextElement();

			String urlStr = url.toString();
			if (!urlSet.contains(urlStr)) {
				urlSet.add(urlStr);
				ret.add(url);
			}
		}
		return ret;
	}

	private void scanResources(List<URL> urlList) throws IOException {
		for (URL url : urlList) {
			String protocol = url.getProtocol();
			if ("jar".equals(protocol)) {
				scanJar(url);
			} else if ("file".equals(protocol)) {
				scanFile(url);
			}
		}
	}

	private void scanJar(URL url) throws IOException {
		URLConnection urlConn = url.openConnection();
		if (urlConn instanceof JarURLConnection) {
			JarURLConnection jarUrlConn = (JarURLConnection) urlConn;
			try (JarFile jarFile = jarUrlConn.getJarFile()) {
				Enumeration<JarEntry> jarFileEntries = jarFile.entries();
				while (jarFileEntries.hasMoreElements()) {
					JarEntry jarEntry = jarFileEntries.nextElement();
					String en = jarEntry.getName();
					// 只扫描 basePackage 之下的类
					if (en.endsWith(".class") && en.startsWith(basePackage)) {
						// JarEntry.getName() 返回值中的路径分隔符在所有操作系统下都是 '/'
						en = en.substring(0, en.length() - 6).replace('/', '.');
						scanClass(en);
					}
				}
			}
		}
	}

	private void scanFile(URL url) {
		String path = url.getPath();
		path = decodeUrl(path);
		File file = new File(path);
		String classPath = getClassPath(file);
		scanFile(file, classPath);
	}

	private void scanFile(File file, String classPath) {
		if (file.isDirectory()) {
			File[] files = file.listFiles();
			if (files != null) {
				for (File fi : files) {
					scanFile(fi, classPath);
				}
			}
		} else if (file.isFile()) {
			String fullName = file.getAbsolutePath();
			if (fullName != null && fullName.endsWith(".class")) {
				String className = fullName.substring(classPath.length(), fullName.length() - 6).replace(File.separatorChar, '.');
				scanClass(className);
			}
		}
	}

	private String getClassPath(File file) {
		String ret = file.getAbsolutePath();
		// 添加后缀,以便后续的 indexOf(bp) 可以正确获得下标值,因为 bp 确定有后缀
		if (!ret.endsWith(File.separator)) {
			ret = ret + File.separator;
		}

		// 将 basePackage 中的路径分隔字符转换成与 OS 相同,方便处理路径
		String bp = basePackage.replace('/', File.separatorChar);
		int index = ret.lastIndexOf(bp);
		if (index != -1) {
			ret = ret.substring(0, index);
		}

		return ret;
	}

	private void scanClass(String className) {
		// 跳过不需要被扫描的 className
		Class<?> c = loadClass(className);
		if (c != null && !scannedClass.contains(c)) {
			// 确保 class 只被扫描一次
			scannedClass.add(c);
		}
	}

	private Class<?> loadClass(String className) {
		try {
			return classLoader.loadClass(className);
		}
		// 此处不能 catch Exception,否则抓不到 NoClassDefFoundError,因为它是 Error 的子类
		catch (Throwable t) {
			//log.debug("PathScanner can not load the class \"" + className + "\"");

			/**
			 * 由于扫描是一种主动行为,所以 pom.xml 中的 provided 依赖会在此被 loadClass, 从而抛出
			 * NoClassDefFoundError、UnsupportedClassVersionError、 ClassNotFoundException
			 * 异常。return null 跳过这些 class 不处理
			 * 
			 * 如果这些异常并不是 provided 依赖的原因而引发,也会在后续实际用到它们时再次抛出异常, 所以 return null 并不会错过这些异常
			 */
			return null;
		}
	}

	/**
	 * 支持路径中存在空格百分号等等字符
	 */
	private String decodeUrl(String url) {
		try {
			return URLDecoder.decode(url, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException(e);
		}
	}
}

要是这都不会使用,就看下面的代码

for (Class<?> className : new ClassScanner(scanPackage).scan()) {
			xxx
		}

再次感觉jfinal

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-09-27 13:57:03  更:2021-09-27 13:59:11 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 19:10:00-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码