问题描述
我正在尝试使用 web 和 thymleaf 在一个简单的 springboot 应用程序中托管 javafx 应用程序。
它向本地主机提供静态 html,我可以使用 webengine.load("localhost:port") 从浏览器和通过独立 javafx 的 webview 获取这些内容
当我尝试在 Spring Boot 中实例化 javafx 应用程序/bean 时会出现问题。我成功实例化了客户端,使 fxml 和控制器运行良好,但 webengine.load 方法返回一个空窗口。我尝试加载从单独运行的应用程序提供的内容,并且可以正常工作,因此问题在于尝试使用由同一 springboot 应用程序实例化的 javafx 客户端加载 springboot 应用程序提供的内容。
JAVAfx 应用程序像这样被实例化为一个 bean,
@Component
public class Cool extends Application {
public void start(Stage stage) throws IOException {
Parent parent = FXMLLoader.load(getClass().getResource("/rendum/webView.fxml"));
Scene scene = new Scene(parent,300,300);
stage.setScene(scene);
stage.show();
}
@Bean
public void go() {
launch();
}
}
尝试像这样加载网页内容
public class Controller {
@FXML
WebView webView;
public void initialize() {
System.out.println("Controller up");
WebEngine webEngine = webView.getEngine();
webEngine.load("http://localhost:8080/");
JSObject window = (JSObject) webEngine.executeScript("window");
window.setMember("java",new JSApi());
webEngine.setonAlert((e)-> {
System.out.println(e.getData());
});
}
}
所以只是为了确认,我已经尝试将 url 更改为其他正在运行的应用程序并且它可以工作,并且我可以在不同的 javafx 应用程序中使用相同的控制器设置并显示内容。
我正在使用 jdk 8. 有谁知道为什么内容无法加载? 入口点
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class,args);
}
}
控制器实例化。它在“/”(入口点)处提供带有 som js 的 html
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class ViewController {
@GetMapping("/")
public String index() {
return "index";
}
}
项目结构。
因此它实例化了向本地主机提供 html 和 js 的控制器。这个对javafxbean中的webengine是不可用的,但是对于这个springboot应用之外的应用是可用的
解决方法
事实证明有一种方法可以实现这一目标。您实际上想从 Springboot 入口点启动 JavaFx 应用程序,而不是像普通的 spring-boot 应用程序一样运行它。在您的 Javafx 应用程序中,您将需要一个 ConfigurableApplicationContext,它将用于启动一个事件,该事件将告诉您的应用程序您的初级阶段已准备就绪。可以通过初始化 spring-boot ApplicationListener 的 bean 来监听此事件,您将从其 onApplicationEvent 方法创建您的场景。
您可以像往常一样使用 spring 初始化程序并添加依赖项。 一个普通的 spring-boot 应用程序像这样启动
public class SpringApplication{
public static void main(String[] args) {
SpringApplication.run(SpringApplication.class,args);
}
}
相反,使用 java fx 中的 Application 类来启动应用程序
public class SpringApplication{
public static void main(String[] args) {
Application.launch(JavaFXApplication.class,args);
}
}
通过使用 SpringApplicationBuilder 在 init 方法中创建可配置应用程序上下文来配置 JavaFXApplication。在 start 方法中从中启动 ApplicationEvent 的实例并将其传递给舞台。 ApplicationEvent 是抽象的,因此您需要从中扩展自定义类。
JavaFXApplication 看起来像这样
public class JavaFxApplication extends Application {
ConfigurableApplicationContext applicationContext;
@Override
public void start(Stage stage) throws Exception {
applicationContext.publishEvent(new StageReadyEvent(stage));
}
public void init() {
applicationContext = new SpringApplicationBuilder(SpringApplication.class).run();
}
public void stop() {
applicationContext.close();
}
public static class StageReadyEvent extends ApplicationEvent {
public StageReadyEvent(Stage stage) {
super(stage);
}
}
}
最后,通过实现 ApplicationListener 实例化一个监听该事件的 Bean
@Component
public class StageReadyListener implements ApplicationListener<JavaFxApplication.StageReadyEvent> {
@Override
public void onApplicationEvent(JavaFxApplication.StageReadyEvent stageReadyEvent) {
Stage stage = (Stage)stageReadyEvent.getSource();
stage.setScene(new Scene(new Label("Hello"),300,300));
stage.show();
}
}
通过这种方式,现在也可以在 javafx 应用程序中使用 spring 依赖注入。