001package io.jboot.app; 002 003 004import java.io.File; 005import java.util.ArrayList; 006import java.util.List; 007 008/** 009 * 参考 JFinal Undertow 的 PathKitExt,目的是在启动的时候 为 PathKit 配置参数 010 */ 011public class PathKitExt { 012 013 private static String locationPath = null; // 定位路径 014 015 private static String rootClassPath = null; 016 private static String webRootPath = null; 017 018 /** 019 * 1:获取 PathKitExt 类文件所处 jar 包文件所在的目录,注意在 "非部署" 环境中获取到的 020 * 通常是 maven 本地库中的某个目录,因为在开发时项目所依赖的 jar 包在 maven 本地库中 021 * 这种情况不能使用 022 * <p> 023 * 2:PathKitExt 自身在开发时,也就是未打成 jar 包时,获取到的是 APP_BASE/target/classes 024 * 这种情况多数不必关心,因为 PathKitExt 在使用时必定处于 jar 包之中 025 * <p> 026 * 3:获取到的 locationPath 目录用于生成部署时的 config 目录,该值只会在 "部署" 环境下被获取 027 * 也用于生成 webRootPath、rootClassPath,这两个值也只会在 "部署" 时被获取 028 * 这样就兼容了部署与非部署两种场景 029 * <p> 030 * 注意:该路径尾部的 "/" 或 "\\" 已被去除 031 */ 032 public static String getLocationPath() { 033 if (locationPath != null) { 034 return locationPath; 035 } 036 037 try { 038 // Class<?> clazz = io.undertow.Undertow.class; // 仅测试用 039 Class<?> clazz = PathKitExt.class; 040 String path = clazz.getProtectionDomain().getCodeSource().getLocation().getPath(); 041 path = java.net.URLDecoder.decode(path, "UTF-8"); 042 path = path.trim(); 043 File file = new File(path); 044 if (file.isFile()) { 045 path = file.getParent(); 046 } 047 048 path = removeSlashEnd(path); // 去除尾部 '/' 或 '\' 字符 049 locationPath = path; 050 051 return locationPath; 052 053 } catch (Exception e) { 054 throw new RuntimeException(e); 055 } 056 } 057 058 public static String getRootClassPath() { 059 if (rootClassPath == null) { 060 rootClassPath = buildRootClassPath(); 061 } 062 return rootClassPath; 063 } 064 065 066 private static String buildRootClassPath() { 067 String classPathDirEndsWith_classes = getClassPathDirEndsWith_classes(); 068 if (classPathDirEndsWith_classes != null) { 069 return classPathDirEndsWith_classes; 070 } 071 072 String path = getLocationPath(); 073 return processRootClassPath(path); 074 } 075 076 /** 077 * 获取以 "classes" 结尾的 class path 078 */ 079 private static String getClassPathDirEndsWith_classes() { 080 String[] classPathDirs = getClassPathDirs(); 081 if (classPathDirs == null || classPathDirs.length == 0) { 082 return null; 083 } 084 085 for (String dir : classPathDirs) { 086 if (dir != null) { 087 dir = removeSlashEnd(dir.trim()); 088 if (dir != null && dir.endsWith("classes")) { 089 return dir; 090 } 091 } 092 } 093 094 return null; 095 } 096 097 /** 098 * 1:开发环境 path 会以 classes 结尾 099 * <p> 100 * 2:打包以后的部署环境不会以 classes 结尾,约定一个合理的项目打包结构 101 * 暂时约定 APP_BASE/config 为 rootClassPath,因为要读取外部配置文件 102 */ 103 private static String processRootClassPath(String path) { 104 if (path.endsWith("classes")) { 105 return path; 106 } 107 108 if (path.endsWith(File.separatorChar + "lib")) { 109 path = path.substring(0, path.lastIndexOf(File.separatorChar)); 110 } 111 112 return new File(path + File.separator + "config").getAbsolutePath(); 113 } 114 115 public static String removeSlashEnd(String path) { 116 if (path.endsWith(File.separator)) { 117 return path.substring(0, path.length() - 1); 118 } else { 119 return path; 120 } 121 } 122 123 // -------------------------------------------------------------------------------------- 124 125 public static String getWebRootPath() { 126 if (webRootPath == null) { 127 webRootPath = buildWebRootPath(); 128 } 129 return webRootPath; 130 } 131 132 private static String buildWebRootPath() { 133 String classPathDirEndsWith_classes = getClassPathDirEndsWith_classes(); 134 if (classPathDirEndsWith_classes != null) { 135 return classPathDirEndsWith_classes; 136 } 137 138 String path = getLocationPath(); 139 return processWebRootPath(path); 140 } 141 142 private static String processWebRootPath(String path) { 143 if (path.endsWith("classes")) { 144 return path; 145 } 146 147 if (path.endsWith(File.separatorChar + "lib")) { 148 path = path.substring(0, path.lastIndexOf(File.separatorChar)); 149 } 150 151 return new File(path + File.separator + "webapp").getAbsolutePath(); 152 } 153 154 // --------- 155 156 private static String[] classPathDirs = null; 157 158 public static String[] getClassPathDirs() { 159 if (classPathDirs == null) { 160 classPathDirs = buildClassPathDirs(); 161 } 162 return classPathDirs; 163 } 164 165 private static String[] buildClassPathDirs() { 166 List<String> list = new ArrayList<>(); 167 String[] classPathArray = System.getProperty("java.class.path").split(File.pathSeparator); 168 for (String classPath : classPathArray) { 169 classPath = classPath.trim(); 170 171 if (classPath.startsWith("./")) { 172 classPath = classPath.substring(2); 173 } 174 175 File file = new File(classPath); 176 if (file.exists() && file.isDirectory()) { 177 // if (!classPath.endsWith("/") && !classPath.endsWith("\\")) { 178 if (!classPath.endsWith(File.separator)) { 179 classPath = classPath + File.separator; // append postfix char "/" 180 } 181 182 list.add(classPath); 183 } 184 } 185 return list.toArray(new String[list.size()]); 186 } 187 188}