【问题标题】:JavaFX app overwriting files while being open causes exceptionJavaFX 应用程序在打开时覆盖文件会导致异常
【发布时间】:2022-06-21 04:00:52
【问题描述】:

我有一个可运行的 jar 文件(带有一个包含所有依赖项 jar 的 lib 文件夹)。它位于网络共享上,任何有权访问的人都可以从中运行。除了一个巨大的警告外,这很好用。如果我要部署新版本的软件,我得先请大家退出应用程序。这是因为如果我用新版本覆盖 jars(或者如果有网络 blip),正在运行的程序会保持打开状态,但是一旦它们执行需要依赖项中的代码的操作(lib 文件夹中的 jar 文件),它会引发异常:

Exception in thread "JavaFX Application Thread" java.lang.NoClassDefFoundError

程序不会产生错误,但某些操作会中断,例如与 API 通信等。

有没有办法可以解决这个问题,以便我可以在用户工作时发布更新,或者至少产生一个提示,迫使他们关闭/重新打开应用等。

【问题讨论】:

    标签: java javafx


    【解决方案1】:

    一种方法:

    1. 提供从远程代码的本地副本启动应用程序的脚本。
    2. 在您的应用中存储版本号。
    3. 脚本检查计算机上是否有应用程序的本地副本。
      • 如果不存在本地版本,脚本会将 jar 从您的网络共享复制到本地副本。
      • 如果已经有本地副本,它会根据网络版本检查版本。
        • 如果网络版本更新,它会在启动应用程序之前用新的远程版本覆盖本地副本,
        • 否则它只会启动本地副本。

    如果您希望提醒用户他们当前正在运行一个过时的副本,您可以创建一个 JavaFX 任务来轮询远程版本号并根据当前运行的版本号检查它。如果它们不同,您可以发出警报并(如果您愿意)关闭应用程序并重新触发启动器脚本。

    【讨论】:

    • 没有库或工具包可以做到这一点吗?
    • 可能有一个库或工具包,或者至少其中的一部分,你可以做一些调查。例如,使用从 yum 存储库分发的 jpackage 制作的本机 rpm 包将实现其中的许多任务。同样,maven 或 gradle 也做类似的事情。您还可以通过 wix 等 jpackage 调查 3rd 方 Java 应用程序安装程序或本机安装程序的功能。或者查看想法源或任何更新的 Java 应用程序。库建议与 StackOverflow 无关,我真的不知道该推荐什么最适合您的情况。
    【解决方案2】:

    我能够创建一个方案,其中我有多个服务器文件夹位置来存放可分发的 jar。这个 jar 基本上会检查这些位置以获取应用程序的最新副本并运行该最新副本。通过检测操作系统,我能够让它在 Mac 和 Windows 上运行(没有测试 Linux)。

    所以现在,我可以在最旧的应用上发布更新,并且下次用户打开该应用时,它将是最新的副本。

    process.properties

    location.a=Application/A
    location.b=Application/B
    app=app.jar
    

    您可以添加文件夹 A-Z,但只需将它们添加到属性中。

    Main.java

    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.nio.file.Paths;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Properties;
    import java.util.TreeMap;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import org.apache.commons.io.FileUtils;
    import org.apache.commons.lang3.StringUtils;
    
    
    public class Main
    {
    
        public static Properties properties;
        private static final String DEFAULT_PROPERTY_FILE_LOCATION = Paths.get("").toAbsolutePath().toString() + File.separator + "process.properties";
        private static final String JAVE_EXEC;
    
        static
        {
            String os = System.getProperty("os.name");
    
            if (StringUtils.containsIgnoreCase(os, "win"))
            {
                JAVA_EXEC = "java";
            } else if (StringUtils.containsIgnoreCase(os, "mac"))
            {
                JAVA_EXEC = "/usr/bin/java";
    
            } else if (StringUtils.containsIgnoreCase(os, "nux") || StringUtils.containsIgnoreCase(os, "nix"))
            {
                JAVA_EXEC = "/usr/bin/java";
            } else
            {
                JAVA_EXEC = "java";
            }
        }
    
        /**
         * @param args the command line arguments
         */
        public static void main(String[] args)
        {
    
            Main.properties = new Properties();
    
            try
            {
    
                InputStream in = new FileInputStream(DEFAULT_PROPERTY_FILE_LOCATION);
                Main.properties.load(in);
                System.out.println("Loaded property file: " + DEFAULT_PROPERTY_FILE_LOCATION);
    
                TreeMap<Long, String> locations = new TreeMap<>();
                String appName = Main.properties.getProperty("app");
    
                if (validateProperties(properties))
                {
                    for (int letter = 'a'; letter <= 'z'; ++letter)
                    {
                        String location = "location." + (char) letter;
                        if (Main.properties.getProperty(location) != null)
                        {
                            String networkLocation = Paths.get("").toAbsolutePath() + File.separator + Main.properties.getProperty(location);
                            File file = new File(networkLocation + File.separator + appName);
                            if (file.exists())
                            {
                                locations.put(FileUtils.lastModified(file), networkLocation);
                            }
                        }
    
                    }
                    if (!locations.isEmpty())
                    {
                        Runtime.getRuntime().exec(new String[]
                        {
                            JAVA_EXEC, "-jar", locations.lastEntry().getValue() + File.separator + appName
                        }, null, new File(locations.lastEntry().getValue()));
                    }
                }
            } catch (IOException ex)
            {
                Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
            }
    
        }
    
        private static boolean validateProperties(Properties properties)
        {
            List<String> mandatoryProperties = new ArrayList<>();
    
            mandatoryProperties.add("app");
    
            for (String mandatoryProperty : mandatoryProperties)
            {
                if (properties.get(mandatoryProperty) == null)
                {
                    System.out.println("Failed - Property: " + mandatoryProperty + " doesn't exist.");
                    return false;
                }
            }
            return true;
    
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 2014-02-17
      • 1970-01-01
      • 2015-08-28
      • 1970-01-01
      • 2016-11-05
      • 2013-01-04
      • 1970-01-01
      • 1970-01-01
      • 2017-04-10
      相关资源
      最近更新 更多