如何将Spring Boot项目文件默认路径改为你猜猜看是哪里?

摘要:springboot中File默认路径 1. 背景 在Springboot项目开发中,针对文件解析类业务,以及文件生成类业务,正对默认的文件路径比较容易混淆,这里通过代码示例,记录每一种方式对应的默认路径.方便以后开发中快速查询. 项目信息
springboot中File默认路径 1. 背景 在Springboot项目开发中,针对文件解析类业务,以及文件生成类业务,正对默认的文件路径比较容易混淆,这里通过代码示例,记录每一种方式对应的默认路径.方便以后开发中快速查询. 项目信息如下: 项目目录: D:\projects\javaprj 项目名称: springboottest POM文件路径: D:\projects\javaprj\springboottest\pom.xml 需要依次测试一下几种情况 参数为 "" 参数为 "." 参数为 "./" 参数为 "../" 参数为 "/" 2. 获取文件(资源)几种方式 3. 通过File类获取文件默认路径 File通过File(String pathname)构造函数传递具体的路径信息,得到文件默认路径.getCanonicalPath是获取对应串的真实路径,路径上会去掉路径相对表示../.测试代码如下: // 小游戏 地心侠士 公众号:小满小慢 public static void filePath() throws IOException { System.out.println("=========小游戏 地心侠士 File类默认路径========="); File file = new File(""); System.out.println("File \"\" 路径: " + file.getCanonicalPath()); file = new File("."); System.out.println("File \".\" 路径: " + file.getCanonicalPath()); file = new File("./"); System.out.println("File \"./\" 路径: " + file.getCanonicalPath()); file = new File("../"); System.out.println("File \"../\"路径: " + file.getCanonicalPath()); file = new File("/"); System.out.println("File \"/\" 路径: " + file.getCanonicalPath()); } 以上代码对应输输出结果如下: =========小游戏 地心侠士 File类默认路径========= File "" 路径: D:\projects\javaprj\springboottest File "." 路径: D:\projects\javaprj\springboottest File "./" 路径: D:\projects\javaprj\springboottest File "../"路径: D:\projects\javaprj File "/" 路径: D:\ 打包把springboottest-0.0.1-SNAPSHOT.jar放在D:\,jdk所在的目录:C:\Program Files\Java\jdk17.0.8\bin,切换到jdk所在的目录执行如下命令:java -jar d:\springboottest-0.0.1-SNAPSHOT.jar,得到的输出结果如下: =========小游戏 地心侠士 File类默认路径========= File "" 路径: C:\Program Files\Java\jdk17.0.8\bin File "." 路径: C:\Program Files\Java\jdk17.0.8\bin File "./" 路径: C:\Program Files\Java\jdk17.0.8\bin File "../"路径: C:\Program Files\Java\jdk17.0.8 File "/" 路径: C:\ 切换到jar所在目录执行如下命令:"C:\Program Files\Java\jdk17.0.8\bin\java.exe" -jar springboottest-0.0.1-SNAPSHOT.jar 得到的输出结果如下: =========小游戏 地心侠士 File类默认路径========= File "" 路径: D:\ File "." 路径: D:\ File "./" 路径: D:\ File "../"路径: D:\ File "/" 路径: D:\ 从以上场景中,可以知道在调用File(String pathname)构造函数时,得到如下结论 参数" ",".","./"都指向相同的目录. 支持相对目录写法, 如"../"会向上一级目录. 参数"/",表示获取工作目录的跟目录 默认目录和jar包所在的目录并没有关系.只和工作目录有关系 可以通过以下代码获取到工作目录: --小游戏 地心侠士 String workingDir = System.getProperty("user.dir"); System.out.println("当前工作目录为: "+workingDir); 如果想要输出目录始终一直,可以在启动时指定工作目录,可以使用-Duser.dir修改,如启动命令调整为:java -Duser.dir=D:\ -jar d:\springboottest-0.0.1-SNAPSHOT.jar此时,Filel类的默认目录一定是为D:\ 4. 通过Class类获取文件默认路径 使用class的getResource()方法获取文件默认路径.为了说明问题,特地使用处于不同包的两个类测试 com.RootClass com.herbert.springboottest.SpringboottestApplication 测试代码如下: public static void classgetResource() { System.out.println("===小游戏 地心侠士 class.getResource 默认路径==="); URL resource = SpringboottestApplication.class.getResource(""); System.out.println("class.getResource \"\" 路径: " + resource.getPath()); resource = SpringboottestApplication.class.getResource("."); System.out.println("class.getResource \".\" 路径: " + resource.getPath()); resource = SpringboottestApplication.class.getResource("./"); System.out.println("class.getResource \"./\"路径: " + resource.getPath()); resource = SpringboottestApplication.class.getResource("../"); System.out.println("class.getResource \"../\"路径: " + resource.getPath()); resource = SpringboottestApplication.class.getResource("/"); System.out.println("class.getResource \"/\" 路径: " + resource.getPath()); } 以上代码对应的输出结果如下: ===小游戏 地心侠士 class.getResource 默认路径=== class.getResource "" 路径: /D:/projects/javaprj/springboottest/target/classes/com/herbert/springboottest/ class.getResource "." 路径: /D:/projects/javaprj/springboottest/target/classes/com/herbert/springboottest/ class.getResource "./"路径: /D:/projects/javaprj/springboottest/target/classes/com/herbert/springboottest/ class.getResource "../"路径: /D:/projects/javaprj/springboottest/target/classes/com/herbert/ class.getResource "/" 路径: /D:/projects/javaprj/springboottest/target/classes/ RootClass.getResource "" 路径: /D:/projects/javaprj/springboottest/target/classes/com/ 打包成jar后执行,不管工作目录如何,class.getResource()方法得到的目录都是jar包所在目录. ===小游戏 地心侠士 class.getResource 默认路径=== class.getResource "" 路径: nested:/D:/springboottest-0.0.1-SNAPSHOT.jar/!BOOT-INF/classes/!/com/herbert/springboottest/ class.getResource "." 路径: nested:/D:/springboottest-0.0.1-SNAPSHOT.jar/!BOOT-INF/classes/!/com/herbert/springboottest/ class.getResource "./"路径: nested:/D:/springboottest-0.0.1-SNAPSHOT.jar/!BOOT-INF/classes/!/com/herbert/springboottest/ class.getResource "../"路径: nested:/D:/springboottest-0.0.1-SNAPSHOT.jar/!BOOT-INF/classes/!/com/herbert/ class.getResource "/" 路径: nested:/D:/springboottest-0.0.1-SNAPSHOT.jar/!BOOT-INF/classes/!/ RootClass.getResource "" 路径: nested:/D:/springboottest-0.0.1-SNAPSHOT.jar/!BOOT-INF/classes/!/com/ 从测试结果可以知道 " ",".","." 都指向当前class所在的目录. 支持相对目录写法, 如"../"会向上一级目录. "/"指向classes目录或者class所在jar的根目录. 和工作目录没有关系.和class在哪里有关系 5. 通过ClassLoader类获取文件默认路径 使用classloader的getResource()方法获取文件默认路径 测试代码如下: public static void classLoaderGetResource(ClassLoader classLoader) { System.out.println("===小游戏 地心侠士 classLoader.getResource 默认路径==="); System.out.println("classLoader信息: " + classLoader.getName() + " " + classLoader.getClass().getSimpleName()); URL resource = classLoader.getResource("application.properties"); System.out.println("classLoader.getResource \"\" 路径: " + resource.getPath()); resource = classLoader.getResource("."); System.out.println("classLoader.getResource \".\" 路径: " + resource.getPath()); resource = classLoader.getResource("./"); System.out.println("classLoader.getResource \"./\" 路径: " + resource.getPath()); resource = classLoader.getResource("com"); System.out.println("classLoader.getResource \"com\" 路径: " + resource.getPath()); // 不支持上级目录 resource = classLoader.getResource("../"); if (resource != null) { System.out.println("classLoader.getResource \"../\" 路径: " + resource.getPath()); } else { System.out.println("classLoader.getResource \"../\" 路径: 不支持 "); } // 不支持绝对目录 resource = classLoader.getResource("/"); System.out.println("classLoader.getResource \"/\" 路径: 不支持"); } AppClassLoader 执行情况 测试代码: classLoaderGetResource(ClassLoader.getSystemClassLoader()) 在IDE中输输出结果如下: ===小游戏 地心侠士 classLoader.getResource 默认路径=== classLoader信息: app AppClassLoader classLoader.getResource "" 路径: /D:/projects/javaprj/springboottest/target/classes/application.properties classLoader.getResource "." 路径: /D:/projects/javaprj/springboottest/target/classes/ classLoader.getResource "./" 路径: /D:/projects/javaprj/springboottest/target/classes/ classLoader.getResource "com" 路径: /D:/projects/javaprj/springboottest/target/classes/com classLoader.getResource "../" 路径: 不支持 classLoader.getResource "/" 路径: 不支持 打包成jar后执行,直接获取不到resouce,直接报错,可能与我打包的fat包有关系. PlatformClassLoader 执行情况 测试代码: classLoaderGetResource(ClassLoader.getPlatformClassLoader()) 在IDE中输输出结果如下: 无论是IDE中,还是打包成jar执行,都获取不到对应resource. 通过两类系统classloader的测试,总结如下 classLoader.getResource 受类加载器影响明显,不建议直接使用 class.getResource 相对于类所在路径,比较清晰 6. 使用ResourceUtils获取资源 Spring提供的工具类了 ResourceUtils 获取资源,测试代码如下 public static void springResourceUtilsFilePath() throws IOException { System.out.println("=========小游戏 地心侠士 ResourceUtils类默认路径========="); File file = ResourceUtils.getFile(""); System.out.println("ResourceUtils \"\" 路径: " + file.getCanonicalPath()); file = ResourceUtils.getFile("."); System.out.println("ResourceUtils \".\" 路径: " + file.getCanonicalPath()); file = ResourceUtils.getFile("./"); System.out.println("ResourceUtils \"./\" 路径: " + file.getCanonicalPath()); file = ResourceUtils.getFile("../"); System.out.println("ResourceUtils \"../\"路径: " + file.getCanonicalPath()); file = ResourceUtils.getFile("/"); System.out.println("ResourceUtils \"/\" 路径: " + file.getCanonicalPath()); file = ResourceUtils.getFile("classpath:application.properties"); System.out.println("ResourceUtils classpath: 路径: " + file.getCanonicalPath()); file = ResourceUtils.getFile("file:application.properties"); System.out.println("ResourceUtils file: 路径: " + file.getCanonicalPath()); } IDE运行后输出结果如下 =========小游戏 地心侠士 ResourceUtils类默认路径========= ResourceUtils "" 路径: D:\projects\javaprj\springboottest ResourceUtils "." 路径: D:\projects\javaprj\springboottest ResourceUtils "./" 路径: D:\projects\javaprj\springboottest ResourceUtils "../"路径: D:\projects\javaprj ResourceUtils "/" 路径: D:\ ResourceUtils classpath: 路径: D:\projects\javaprj\springboottest\target\classes\application.properties ResourceUtils file: 路径: D:\projects\javaprj\springboottest\application.properties 打包把springboottest-0.0.1-SNAPSHOT.jar放在D:\,jdk所在的目录:C:\Program Files\Java\jdk17.0.8\bin,切换到jdk所在的目录执行如下命令:java -jar d:\springboottest-0.0.1-SNAPSHOT.jar,得到的输出结果如下: =========小游戏 地心侠士 ResourceUtils类默认路径========= ResourceUtils "" 路径: C:\Program Files\Java\jdk17.0.8\bin ResourceUtils "." 路径: C:\Program Files\Java\jdk17.0.8\bin ResourceUtils "./" 路径: C:\Program Files\Java\jdk17.0.8\bin ResourceUtils "../"路径: C:\Program Files\Java\jdk17.0.8 ResourceUtils "/" 路径: C:\ ResourceUtils classpath: 路径: class path resource [application.properties] cannot be resolved to absolute file path because it does not reside in the file system: jar:nested:/D:/springboottest-0.0.1-SNAPSHOT.jar/!BOOT-INF/classes/!/application.properties ResourceUtils file: 路径: C:\Program Files\Java\jdk17.0.8\bin\application.properties 切换到jar所在目录执行如下命令:"C:\Program Files\Java\jdk17.0.8\bin\java.exe" -jar springboottest-0.0.1-SNAPSHOT.jar 得到的输出结果如下: =========小游戏 地心侠士 ResourceUtils类默认路径========= ResourceUtils "" 路径: D:\ ResourceUtils "." 路径: D:\ ResourceUtils "./" 路径: D:\ ResourceUtils "../"路径: D:\ ResourceUtils "/" 路径: D:\ ResourceUtils classpath: 路径: class path resource [application.properties] cannot be resolved to absolute file path because it does not reside in the file system: jar:nested:/D:/springboottest-0.0.1-SNAPSHOT.jar/!BOOT-INF/classes/!/application.properties ResourceUtils file: 路径: D:\application.properties 通过ResourceUtils测试,总结如下: 不同场景下运行程序得到到的默认路径同File保持一致特性.同工作目录强相关. 使用Spring的classpath前缀获取文件时,默认从运行的jar包查找 使用Spring的file前缀获取文件时,默认从当前根目录查找 7. 总结 ResourceUtils 和 File 类使用路径获取资源时,是以工作目录为参考 class.getResource 方法使用路径参数获取资源时,是以这个类的位置为参考 classLoader.getResource正常情况下以classpth目录为基准,不支持路径参数不支持绝对路径.并且java9使用模块化机制,影响很大 不管那种方式"",".","./"都表示当前目录 SpringBoot中提供了很多有用的类,合理使用,绝对事半功倍.不知道各位javaer们都经常使用哪些内置类 原文地址: https://mp.weixin.qq.com/s/NTsa0FtPt0UNSZeTHbQ4Cw