如何使用springboot配置javafx并具有超过1个窗口?

问题描述 投票:0回答:2

我有问题。 这是我的主要内容:

    @SpringBootApplication
public class MyAppSpringApplication extends Application {

    public static ConfigurableApplicationContext springContext;
    private FXMLLoader fxmlLoader;


    public static void main(String[] args) {
        Application.launch(args);
    }

    @Override
    public void start(Stage stage) throws Exception {
        fxmlLoader.setLocation(getClass().getResource("/sample.fxml"));
        Parent root = fxmlLoader.load();
        stage.setTitle("Sample app");
        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.show();
    }

    @Override
    public void stop() throws Exception {
        springContext.stop();
    }

    @Override
    public void init() throws Exception {
        springContext = SpringApplication.run(MyAppSpringApplication.class);
        fxmlLoader = new FXMLLoader();
        fxmlLoader.setControllerFactory(springContext::getBean);
    }
}

我的第一个窗口(sample.fxml)与samplecontroller和sampleservice工作正常。但是我用他们的控制器和服务创建了另一个

dish-builder.fxml
,但是当我尝试在那里使用我的服务时,它不起作用,因为在dishbuilderservice中为空(albo在新控制器中不起作用sampleservice)。我听说我也应该使用它:

public static ConfigurableApplicationContext springContext;

但我不知道应该如何使用它。抱歉我的知识和英语很薄弱。

     @Controller
    public class DishBuilderController implements Initializable {
    
        @Autowired
        DishBuilderService dishBuilderService;
    
        @Autowired
        SampleService sampleService;
    
        private void somefun(){
            sampleService.somefunInService(); //here sampleService and 
        every other service has null.

}

这是我打开新的菜肴构建器窗口(位于 SampleController 中)的时刻:

@FXML
    void addNoweOknoClicked(ActionEvent event) {
        try {
            Stage stage = (Stage)anchorPane.getScene().getWindow();
            FXMLLoader fxmlLoader = new FXMLLoader();
            fxmlLoader.setLocation(getClass().getResource("/dish-builder.fxml"));
            AnchorPane root = fxmlLoader.load();
            stage.setTitle("Sample app");
            Scene scene = new Scene(root);
            stage.setScene(scene);
            stage.show();
        }catch (IOException e){
            e.printStackTrace();
        }
    }
java spring javafx null
2个回答
1
投票

加载

dish-builder.fxml
时,您并未在
FXMLLoader
上设置控制器工厂。这意味着
FXMLLoader
只是通过调用其无参数构造函数来创建控制器。由于控制器不是 spring 管理的 bean,因此 spring 无法向其中注入任何组件。

您需要设置控制器工厂,就像加载

sample.fxml
时所做的那样,以便
FXMLLoader
会要求 Spring 从应用程序上下文中检索控制器。

有几点与您的问题并不严格相关:

  • 无需将
    ApplicationContext
    公开为公共静态字段。您可以将其注入到任何需要访问它的 spring 管理的 bean 中
  • 不建议重复使用
    FXMLLoader
    。 因此,将
    FXMLLoader
    作为实例变量是没有意义的。
  • @Controller
    注释适用于 Spring MVC 应用程序中的web控制器。它们与 JavaFX 意义上的控制器有很大不同。您应该对 JavaFX 控制器使用通用
    @Component
    注释。
  • 如果您要重新加载 FXML 文件,您将需要一个新的控制器实例。这意味着如果控制器由 Spring 管理,则需要具有
    PROTOTYPE
    范围,而不是默认的
    SINGLETON
    范围。

所以你需要:

@SpringBootApplication
public class MyAppSpringApplication extends Application {

    private ConfigurableApplicationContext springContext;


    public static void main(String[] args) {
        Application.launch(args);
    }

    @Override
    public void start(Stage stage) throws Exception {
        FXMLLoader fxmlLoader = new FXMLLoader();
        fxmlLoader.setControllerFactory(springContext::getBean);
        fxmlLoader.setLocation(getClass().getResource("/sample.fxml"));
        Parent root = fxmlLoader.load();
        stage.setTitle("Sample app");
        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.show();
    }

    @Override
    public void stop() throws Exception {
        springContext.stop();
    }

    @Override
    public void init() throws Exception {
        springContext = SpringApplication.run(MyAppSpringApplication.class);
    }
}

那么你的

SampleController
应该看起来像

@Component
@Scope("prototype")
public class SampleController {

    @Autowired
    private ConfigurableApplicationContext springContext ;

    @FXML
    void addNoweOknoClicked(ActionEvent event) {
        try {
            Stage stage = (Stage)anchorPane.getScene().getWindow();
            FXMLLoader fxmlLoader = new FXMLLoader();
            fxmlLoader.setControllerFactory(springContext::getBean);
            fxmlLoader.setLocation(getClass().getResource("/dish-builder.fxml"));
            AnchorPane root = fxmlLoader.load();
            stage.setTitle("Sample app");
            Scene scene = new Scene(root);
            stage.setScene(scene);
            stage.show();
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

同样

@Component
@Scope("prototype")
public class DishBuilderController implements Initializable {

    @Autowired
    DishBuilderService dishBuilderService;

    @Autowired
    SampleService sampleService;

    private void somefun(){
        // this should now work, since the controller is managed by Spring:
        sampleService.somefunInService();   
    }

}

0
投票

补充:这里有两个现成的模板,包含 JavaFX、Spring Boot 和 Maven/Gradle。

我将感谢 GitHub 上的明星支持它的免费开源,从而帮助您解决问题。 <3

https://github.com/davidweber411/javafx-JavaFxSpringBootGradleApp

https://github.com/davidweber411/javafx-JavaFxSpringBootMavenApp

© www.soinside.com 2019 - 2024. All rights reserved.