将JavaFX8与JSF2.2集成

将JavaFX8与JSF2.2集成,jsf,javafx,Jsf,Javafx,作为一个实验,我正在尝试一些将JavaFX与JavaServerFaces2.2集成的测试。我正在使用EclipseMars.2版本4.5.2和Java1.8,其中包括JavaFX8,以及Windows10计算机上的Glassfish 4.1.1服务器。我们的想法是看看是否有可能在服务器上运行JSF应用程序并调用一些JavaFXGUI,最终目标是能够在客户端上显示3D图形 但是,我遇到了一些问题,所以这里展示一个非常简单的示例。xhtml代码只是: 用JSF测试JavaFX 用JSF测试Jav

作为一个实验,我正在尝试一些将JavaFX与JavaServerFaces2.2集成的测试。我正在使用EclipseMars.2版本4.5.2和Java1.8,其中包括JavaFX8,以及Windows10计算机上的Glassfish 4.1.1服务器。我们的想法是看看是否有可能在服务器上运行JSF应用程序并调用一些JavaFXGUI,最终目标是能够在客户端上显示3D图形

但是,我遇到了一些问题,所以这里展示一个非常简单的示例。xhtml代码只是:


用JSF测试JavaFX
用JSF测试JavaFX

它只在浏览器窗口中的
localhost:8080/Test
上显示两个按钮,一个用于启动JavaFX应用程序,另一个最终用于关闭应用程序

bean的代码是:

package shape3dfxjsf;

import java.io.Serializable;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

@SessionScoped
@ManagedBean(name="myBean")
public class MyBean implements Serializable {
    private static final long serialVersionUID = 1L;
    private static boolean launched = false;

    public static void launchApp() {
        if (launched) return;
        launched = true;
        TestJavaFX.main(null);
    }

    public static void stopApp() {
        launched = false;
    }
}
JavaFX应用程序的代码去掉了所有的图形,只是屏幕上有:

package shape3dfxjsf;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class TestJavaFX extends Application {

    @Override
    public void start(Stage primaryStage) {
        try {
          BorderPane root = new BorderPane();
          Scene scene = new Scene(root,400,400);
          primaryStage.setScene(scene);
          primaryStage.show();
        } catch(Exception e) {
          e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}
当在服务器上使用JSF时,类MyBean调用TestJavaFX的上一个清单中的
main()
方法,当作为Java应用程序运行时,也可以直接调用它,这是一个有用的测试

当Glassfish启动并打开浏览器窗口时,我单击“启动JavaFX应用程序”按钮并调用MyBean中的
launchApp()
方法。由于启动标志最初为false,因此会调用TestJavaFX中的
main()
方法,并且确实会在我的屏幕上显示一个JavaFX窗口,就像我直接从TestJavaFX调用
main()
方法一样,因此这是正确的

由于launched标志现在为true,再次单击launch按钮无效(在代码的更高版本中可以禁用该按钮)。关闭JavaFX窗口后,启动标志仍然为真,因此必须单击“停止JavaFX应用程序”按钮,使其再次为假,以重新启用“启动JavaFX应用程序”。手动将标志设置回false这个小问题可以很容易地实现自动化

然而,主要的问题是我无法重新启动JavaFX应用程序,即使它显然已经关闭。如果在重新启用并关闭JavaFX应用程序后单击“启动JavaFX应用程序”,我会不断收到错误:

java.lang.IllegalStateException: Application launch must not be called more than once
我读过这篇文章,也看过其他帖子。问题是,据我所知,JavaFX已经关闭,所以我不明白为什么会出现这个错误。在JavaTestFX类中尝试
Platform.exit()


从JSFbean调用JavaFX时,如何重新启动JavaFX,而不关闭所有内容并重新启动?一定有人尝试过这个方法,我非常希望能想出一些解决这个问题的办法。

我被这个设置搞糊涂了。JSFbean中的代码是在服务器上执行的,而不是在客户机上执行的,因此您的JavaFXGUI是在服务器端运行的。很明显,您不能多次调用
launch()
(在JVM的生命周期中)。因此,为了实现这一点,您应该有一个应用程序类,其中包含一个空的
start()
方法,该方法从应用程序上下文侦听器调用,并且您的JSF bean应该只创建并显示一个stage。当然,这仍然会在服务器上运行JavaFX GUI,这一点完全不清楚。“如何使用空的start()方法设置应用程序类?”。正如它所说的,定义
应用程序
子类,并将其
start()
方法设为禁止操作。调用
启动()
。我发布了一个稍微复杂一些的示例作为答案,这可能会有所帮助(尽管我仍然不知道您希望它如何工作)。以下是我可以说服您的一个方法。关闭除Glassfish之外的所有Java应用程序。如果生成一个进程列表,您将只看到一个Java进程。打开web浏览器,点击应用程序,然后启动JavaFX窗口。再次检查进程列表:仍然只有一个Java进程正在运行-因此JavaFX应用程序on与服务器在同一个JVM中运行。它不能在客户端上运行。因此,基本上,您在这里尝试的操作毫无意义(除非我假设您打算使用在本地主机上运行的Glassfish作为JavaFX应用程序的包装器,这也毫无意义)。您可能对web应用程序有根本性的误解,或者对JavaFX有根本性的误解,或者两者都有。我对这种设置感到困惑。JSF bean中的代码是在服务器上执行的,而不是在客户端,因此您的JavaFX GUI是在服务器端运行的。很明显,您不能调用
launch()
不止一次(在JVM的生命周期中)。因此,为了实现这一点,您应该有一个带有空
start()的应用程序类
方法,该方法是从应用程序上下文侦听器调用的,您的JSF bean应该只创建并显示一个阶段。当然,这仍然会在服务器上运行JavaFX GUI,这一点完全不清楚。“如何使用空的start()方法设置应用程序类?”?“。正如它所说的,定义
应用程序
子类,并使其
开始()
方法成为无操作调用
启动()
。我发布了一个稍微复杂一点的例子作为答案,这可能会有所帮助(尽管我仍然不知道你期望它如何工作)。关闭除Glassfish之外的所有Java应用程序。如果生成一个进程列表,您将只看到一个Java进程。打开web浏览器,点击应用程序,然后启动JavaFX窗口。再次检查进程列表:仍然只有一个Java进程在运行,因此JavaFX应用程序与服务器运行在同一个JVM中。它不能在客户端上运行。所以基本上,