关于Maven项目在tomcat服务器中运行输出的System.getProperty(“user.dir“)值不一致的问题

user.dir属性根据不同的运行环境有不同的返回值:在Eclipse或IDEA中为项目目录,Windows下Tomcat中为Tomcat的bin目录,Linux下Tomcat中为Tomcat根目录,启动脚本执行位置不同,该值也相应变化。

user.dir字面解释是用户工作目录,实际上因项目的不同运行环境和启动位置有关。

1. 项目运行在EclipseIEAD开发工具中,System.getProperty("user.dir")的值就是项目目录所在路径。

2. 项目运行在Windows下的tomcat中,System.getProperty("user.dir")的值就是tomcatbin目录所在路径。

3. 项目运行在Linux下的tomcat中,System.getProperty("user.dir")的值就是tomcat的根目录所在路径。

4.startup.batstartup.sh启动脚本的执行位置不一样,System.getProperty("user.dir")的值就是启动脚本的执行位置所在路径。

package com.ruoyi.kettle.config; import com.ruoyi.kettle.tools.KettleUtil; import lombok.extern.slf4j.Slf4j; import org.pentaho.di.core.Const; import org.pentaho.di.core.KettleEnvironment; import org.pentaho.di.core.exception.KettleException; import org.pentaho.di.core.plugins.PluginFolder; import org.pentaho.di.core.plugins.StepPluginType; import org.pentaho.di.core.util.EnvUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.URISyntaxException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.util.Enumeration; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.jar.JarEntry; import java.util.jar.JarFile; @Slf4j public class KettleEnv { private static final String PLUGIN_DIR = "kettlePlugins"; private static final String JNDI_DIR = "simple-jndi"; private static volatile Path extractedPluginPath; private static volatile Path extractedJndiPath; private static String pluginBasePath; // 读写锁确保线程安全 private static final ReentrantReadWriteLock jndiLock = new ReentrantReadWriteLock(); public static synchronized void init() { try { String pluginPath = getConfiguredPluginPath(); if (pluginPath == null) { // 自动检测并处理插件目录 pluginPath = resolvePluginPath(); } log.info("使用的Kettle插件路径: {}", pluginPath); // 添加插件路径(避免重复添加) String finalPluginPath = pluginPath; if (StepPluginType.getInstance().getPluginFolders().stream() .noneMatch(a -> a.getFolder().equals(finalPluginPath))) { StepPluginType.getInstance().getPluginFolders().add( new PluginFolder(pluginPath, false, true) ); } // 初始化Kettle环境 KettleEnvironment.init(); EnvUtil.environmentInit(); log.info("Kettle环境初始化成功"); pluginBasePath = pluginPath; } catch (Exception e) { log.error("Kettle环境初始化失败", e); } } /** * 设置JNDI环境(任务运行前调用) */ public static void setupJndiEnvironment() { jndiLock.writeLock().lock(); try { Path jndiPath = getDefaultJndiPath(); // 确保目录存在 if (!Files.exists(jndiPath)) { Files.createDirectories(jndiPath); log.info("创建JNDI目录: {}", jndiPath); } // 设置JNDI系统属性 System.setProperty("org.osjava.sj.root", jndiPath.toString()); System.setProperty("org.osjava.sj.delimiter", "/"); System.setProperty("org.osjava.sj.reload", "true"); Const.JNDI_DIRECTORY = jndiPath.toString(); log.info("JNDI路径已设置: {}", jndiPath); } catch (Exception e) { log.error("JNDI环境设置失败", e); throw new RuntimeException(e); } finally { jndiLock.writeLock().unlock(); } } /** * 获取默认JNDI路径 */ public static Path getDefaultJndiPath() { // 优先使用已提取的JNDI路径 if (extractedJndiPath != null) { return extractedJndiPath; } // 检查是否有配置的外部JNDI路径 String externalJndiPath = System.getProperty("kettle.jndi.path"); if (externalJndiPath != null && Files.exists(Paths.get(externalJndiPath))) { return Paths.get(externalJndiPath); } // 默认使用项目根目录下的config/simple-jndi return Paths.get(System.getProperty("user.dir"), "config/simple-jndi"); } /** * 读取jdbc.properties文件内容为字符串(保留原始格式) */ public static String readJdbcPropertiesAsString() throws IOException { return readJdbcPropertiesAsString(getDefaultJndiPath()); } public static String readJdbcPropertiesAsString(Path jndiPath) throws IOException { jndiLock.readLock().lock(); try { Path jdbcFile = jndiPath.resolve("jdbc.properties"); if (!Files.exists(jdbcFile)) { log.warn("jdbc.properties文件存在: {}", jdbcFile); return ""; } return new String(Files.readAllBytes(jdbcFile), StandardCharsets.UTF_8); } finally { jndiLock.readLock().unlock(); } } /** * 将字符串内容写入jdbc.properties文件(保留原始格式) */ public static void writeJdbcPropertiesFromString(String content) throws IOException { writeJdbcPropertiesFromString(getDefaultJndiPath(), content); } public static void writeJdbcPropertiesFromString(Path jndiPath, String content) throws IOException { jndiLock.writeLock().lock(); try { Path jdbcFile = jndiPath.resolve("jdbc.properties"); // 确保目录存在 if (!Files.exists(jndiPath)) { Files.createDirectories(jndiPath); } Files.write(jdbcFile, content.getBytes(StandardCharsets.UTF_8)); log.info("jdbc.properties更新成功, 路径: {}", jdbcFile); } finally { jndiLock.writeLock().unlock(); } } public static String getPluginBasePath() { return pluginBasePath; } /** * 获取配置的插件路径(外部目录优先) */ public static String getConfiguredPluginPath() { // 1. 检查系统属性 String sysPropPath = System.getProperty("kettle.plugin.path"); if (sysPropPath != null && Files.exists(Paths.get(sysPropPath))) { return sysPropPath; } // 2. 检查当前工作目录下的插件目录 Path workingDirPath = Paths.get(System.getProperty("user.dir"), PLUGIN_DIR); if (Files.exists(workingDirPath)) { return workingDirPath.toString(); } // 3. 检查JAR文件同级的插件目录 Path jarDirPath = null; try { jarDirPath = Paths.get(KettleUtil.class.getProtectionDomain() .getCodeSource().getLocation().toURI()) .getParent() .resolve(PLUGIN_DIR); } catch (URISyntaxException e) { throw new RuntimeException(e); } if (Files.exists(jarDirPath)) { return jarDirPath.toString(); } return null; } /** * 解析插件路径(支持JAR包和IDE环境) */ private static String resolvePluginPath() throws Exception { // 优先返回已提取的路径(避免重复提取) if (extractedPluginPath != null) { return extractedPluginPath.toString(); } URL resourceUrl = KettleUtil.class.getClassLoader().getResource(PLUGIN_DIR); if (resourceUrl == null) { throw new FileNotFoundException("未找到Kettle插件资源目录"); } // 开发环境直接使用路径 if (!"jar".equals(resourceUrl.getProtocol())) { // 同时提取JNDI目录 extractJndiFromResources(); return Paths.get(resourceUrl.toURI()).toString(); } // 生产环境提取到临时目录 synchronized (KettleEnv.class) { if (extractedPluginPath == null) { extractedPluginPath = extractPluginsFromJar(resourceUrl); // 同时提取JNDI目录 extractJndiFromJar(); } return extractedPluginPath.toString(); } } /** * 从JAR包提取插件到临时目录(优化版) */ private static Path extractPluginsFromJar(URL jarResourceUrl) throws Exception { // 创建临时目录(带随机后缀) Path tempDir = Files.createTempDirectory("kettle-plugins-"); tempDir.toFile().deleteOnExit(); log.info("创建临时插件目录: {}", tempDir); // 解析JAR文件路径 String jarPath = jarResourceUrl.getPath().split("!")[0].replace("file:", ""); File jarFile = new File(jarPath); try (JarFile jar = new JarFile(jarFile)) { Enumeration<JarEntry> entries = jar.entries(); while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); String entryName = entry.getName(); // 只处理插件目录下的文件 if (entryName.startsWith(PLUGIN_DIR + "/") && !entry.isDirectory()) { // 计算目标路径(去掉插件目录前缀) String relativePath = entryName.substring(PLUGIN_DIR.length() + 1); Path targetPath = tempDir.resolve(relativePath); // 创建父目录 Files.createDirectories(targetPath.getParent()); // 复制文件内容 try (InputStream in = jar.getInputStream(entry)) { Files.copy(in, targetPath, StandardCopyOption.REPLACE_EXISTING); log.debug("提取插件文件: {} -> {}", entryName, targetPath); } } } } log.info("成功提取 {} 个插件文件到临时目录", Files.list(tempDir).count()); return tempDir; } /** * 从JAR包提取JNDI配置到临时目录 */ private static void extractJndiFromJar() throws Exception { URL jndiResourceUrl = KettleUtil.class.getClassLoader().getResource(JNDI_DIR); if (jndiResourceUrl == null) { log.warn("未找到JNDI资源目录"); return; } // 创建临时目录(带随机后缀) Path tempDir = Files.createTempDirectory("kettle-jndi-"); tempDir.toFile().deleteOnExit(); log.info("创建临时JNDI目录: {}", tempDir); // 解析JAR文件路径 String jarPath = jndiResourceUrl.getPath().split("!")[0].replace("file:", ""); File jarFile = new File(jarPath); try (JarFile jar = new JarFile(jarFile)) { Enumeration<JarEntry> entries = jar.entries(); while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); String entryName = entry.getName(); // 只处理JNDI目录下的文件 if (entryName.startsWith(JNDI_DIR + "/") && !entry.isDirectory()) { // 计算目标路径(去掉JNDI目录前缀) String relativePath = entryName.substring(JNDI_DIR.length() + 1); Path targetPath = tempDir.resolve(relativePath); // 创建父目录 Files.createDirectories(targetPath.getParent()); // 复制文件内容 try (InputStream in = jar.getInputStream(entry)) { Files.copy(in, targetPath, StandardCopyOption.REPLACE_EXISTING); log.debug("提取JNDI文件: {} -> {}", entryName, targetPath); } } } } extractedJndiPath = tempDir; log.info("成功提取JNDI配置到临时目录: {}", tempDir); } /** * 在开发环境中提取JNDI配置 */ private static void extractJndiFromResources() throws Exception { URL jndiResourceUrl = KettleUtil.class.getClassLoader().getResource(JNDI_DIR); if (jndiResourceUrl == null) { log.warn("未找到JNDI资源目录"); return; } // 开发环境直接使用资源路径 extractedJndiPath = Paths.get(jndiResourceUrl.toURI()); log.info("使用开发环境JNDI目录: {}", extractedJndiPath); } /** * 重新加载Kettle环境(包括JNDI配置) */ public static synchronized void reload() { try { // 停止所有正在运行的作业 KettleJobManager.stopAllJobs(); // 1. 关闭当前Kettle环境 KettleEnvironment.shutdown(); log.info("Kettle环境已关闭"); // 3. 重新初始化 init(); log.info("Kettle环境重新初始化完成"); } catch (Exception e) { log.error("Kettle环境重新加载失败", e); throw new RuntimeException(e); } } } // 保存配置内容(保留原始格式) @PostMapping("/saveConfig") @ResponseBody public AjaxResult saveConfig(@RequestParam String content) { try { // 直接保存原始内容,解析为Properties KettleEnv.writeJdbcPropertiesFromString(content); // 重新加载Kettle环境 KettleEnv.reload(); return success("配置保存成功"); } catch (Exception e) { return error("保存配置失败: " + e.getMessage()); } } 保存配置时把原文件也修改 ruoyi-admin/src/main/resources/simple-jndi/jdbc.properties ruoyi-admin/target/classes/simple-jndi/jdbc.properties
最新发布
09-17
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值