我的控制器中所有 @FXML 属性均为 NULL(SPRING BOOT - JAVA-FX 集成)

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

我正在开发一个会员管理软件,我使用的是spring boot,spring data与JAVA-FX集成。 一切都很好,直到我创建了一个视图,该视图有一个表,其中包含与主要成员关联的所有依附成员。当我打开视图时,它加载得很好,但是在我用于加载依从成员的数据的方法中,它抛出了异常。

这是我的代码:

FXML:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>

<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="522.0" prefWidth="834.0" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.ebernet.bomberos_socios.controller.VistaAdherenteSocioController">
    <top>
        <HBox alignment="CENTER" prefHeight="100.0" prefWidth="859.0" BorderPane.alignment="CENTER">
            <children>
                <Label fx:id="lblTitulo" text="Socios adherentes de: ">
                    <font>
                        <Font name="Arial" size="18.0" />
                    </font>
                </Label>
            </children>
        </HBox>
    </top>
    <center>
        <VBox prefHeight="280.0" prefWidth="784.0" BorderPane.alignment="CENTER">
            <children>
                <ScrollPane prefHeight="273.0" prefWidth="784.0">
                    <content>
                        <TableView fx:id="tblSociosAdh" prefHeight="239.0" prefWidth="782.0">
                            <columns>
                                <TableColumn fx:id="colNombre" editable="false" prefWidth="231.0"    text="Nombre Completo" />
                                <TableColumn fx:id="colTipoDoc" editable="false" prefWidth="106.0" text="Tipo Doc." />
                                <TableColumn fx:id="colNroDoc" editable="false" prefWidth="145.0" text="Nro. Documento" />
                                <TableColumn fx:id="colFechaNac" editable="false" minWidth="8.0" prefWidth="135.0" text="Fecha de Nac." />
                                <TableColumn fx:id="colVinculo" prefWidth="87.0" text="Vinculo" />
                                <TableColumn fx:id="colDeBaja" prefWidth="75.0" text="Baja" />
                            </columns>
                        </TableView>
                    </content>
                </ScrollPane>
            </children>
            <BorderPane.margin>
                <Insets left="25.0" right="25.0" />
            </BorderPane.margin>
        </VBox>
    </center>
    <bottom>
        <VBox alignment="TOP_CENTER" prefHeight="181.0" prefWidth="834.0" BorderPane.alignment="CENTER">
            <children>
                <Label fx:id="lblSocioSelec" text="Socio adherente seleccionado:">
                    <VBox.margin>
                        <Insets bottom="25.0" top="15.0" />
                    </VBox.margin>
                    <font>
                        <Font name="Arial" size="14.0" />
                    </font>
                </Label>
                <HBox alignment="TOP_CENTER" prefHeight="38.0" prefWidth="834.0">
                    <children>
                        <Button fx:id="btnBaja" mnemonicParsing="false" prefHeight="28.0" prefWidth="65.0" text="Baja">
                            <HBox.margin>
                                <Insets left="10.0" right="10.0" />
                            </HBox.margin>
                        </Button>
                        <Button fx:id="btnEditar" mnemonicParsing="false" prefHeight="29.0" prefWidth="62.0" text="Editar">
                            <HBox.margin>
                                <Insets left="10.0" right="10.0" />
                            </HBox.margin>
                        </Button>
                        <Button fx:id="btnDetalles" mnemonicParsing="false" prefHeight="28.0" prefWidth="66.0" text="Detalles">
                            <HBox.margin>
                                <Insets left="10.0" right="10.0" />
                            </HBox.margin>
                        </Button>
                    </children>
                </HBox>
                <VBox alignment="CENTER" prefHeight="90.0" prefWidth="844.0">
                    <children>
                        <Button fx:id="btnNuevo" mnemonicParsing="false" prefHeight="31.0" prefWidth="235.0" text="Nuevo">
                            <VBox.margin>
                                <Insets top="10.0" />
                            </VBox.margin>
                        </Button>
                        <Button fx:id="btnVolver" mnemonicParsing="false" prefHeight="32.0" prefWidth="233.0" text="Volver">
                            <VBox.margin>
                                <Insets bottom="10.0" top="10.0" />
                            </VBox.margin>
                        </Button>
                    </children>
                </VBox>
            </children>
        </VBox>
    </bottom>
</BorderPane>

控制器:

package com.ebernet.bomberos_socios.controller;

import com.ebernet.bomberos_socios.model.SocioAdherente;
import com.ebernet.bomberos_socios.model.SocioTitular;
import com.ebernet.bomberos_socios.service.ISocioAdherenteService;
import com.ebernet.bomberos_socios.service.ISocioTitularService;
import com.ebernet.bomberos_socios.ui.SocioAdherenteWrapper;
import jakarta.transaction.Transactional;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.ResourceBundle;
import java.util.stream.Collectors;
import javafx.collections.FXCollections;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import org.hibernate.Hibernate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class VistaAdherenteSocioController implements Initializable {

    private SocioTitular socio;

    private HashMap<Long, SocioAdherente> socios;

    private SocioAdherente socioSeleccionado;

    //autowired inyection of service classes here
    
    @FXML
    private Label lblTitulo;

    @FXML
    private TableView<SocioAdherenteWrapper> tblSociosAdh;

    @FXML
    private TableColumn<SocioAdherenteWrapper, String> colNombre;

    @FXML
    private TableColumn<SocioAdherenteWrapper, String> colTipoDoc;

    //other FXML atributes

   

    @Transactional
    public void initData(SocioTitular socioTit) {
        this.socio = sociotitser.findById(socioTit.getNroSocio());
        //Decirle a hibernate que traiga la coleccion
        Hibernate.initialize(socio.getSociosAdherentes());
        //setear titulo
        if (lblTitulo != null) {
            lblTitulo.setText("Socios adherentes de: " + socio.getNroDocumento() + " - " + socio.getNombreCompleto());
            // Resto del código...
        } else {
            System.err.println("lblTitulo es nulo en initData.");
        }
        //obtener socios adherentes del socio en cuestion
        List<SocioAdherente> sociosAdherentes = socio.getSociosAdherentes();
        // Convertir a wrappers
        List<SocioAdherenteWrapper> wrappers = sociosAdherentes.stream()
                .map(SocioAdherenteWrapper::new)
                .collect(Collectors.toList());
        //convertir a hashmap
        this.socios = (HashMap<Long, SocioAdherente>) sociosAdherentes.stream()
                .collect(Collectors.toMap(SocioAdherente::getNroSocio, socio -> socio));

        //Mapeo de columnas :)
        colNombre.setCellValueFactory(cell -> cell.getValue().nombreCompletoProperty());
        colTipoDoc.setCellValueFactory(cell -> cell.getValue().tipoDocProperty());
        colNroDoc.setCellValueFactory(cell -> cell.getValue().nroDocumentoProperty());
        colVinculo.setCellValueFactory(cell -> cell.getValue().vinculoProperty());
        colDeBaja.setCellValueFactory(cell -> cell.getValue().bajaProperty());

        //Setear items
        tblSociosAdh.setItems(FXCollections.observableArrayList(wrappers));

        //other listeners for tables, buttons, etc.
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        //btn y label de acciones disabled por defecto
        /*lblSocioSelec.setDisable(true);
        btnBaja.setDisable(true);
        btnEditar.setDisable(true);
        btnDetalles.setDisable(true);*/
    }

}

索引: (这是我根据用户选择加载不同视图的位置,例如侧面导航栏)

package com.ebernet.bomberos_socios.controller;

import com.ebernet.bomberos_socios.model.SocioTitular;
import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.layout.Pane;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

@Component
public class IndexController implements Initializable {`

    @Autowired
    private ApplicationContext context;

    @FXML
    private Pane mainContent;

    //another methods for opening other views

     //this one here works perfectly, and has the same logic behind that the 
      one im having problems.
    public void editarSocio(SocioTitular socioToEdit) {
        //se carga la vista
        loadView("/fxml/editarSocio.fxml");
        //se obtiene el objeto EditarSocioController gracias a el application context (Gracias SPRING!!!)
        EditarSocioController controller = context.getBean(EditarSocioController.class);
        //se le setea al controlador el objeto socio el cual tiene que editar
        controller.setSocioEditar(socioToEdit);
    }

     //this is the one that doesn't work
    public void vistaSociosAdherentes(SocioTitular socio) {        
        //se carga la vista y el controller!
        loadView("/fxml/vistaAdherenteSocio.fxml");    
        //se obtiene el objeto DetalleSocioController gracias a el application context (Gracias SPRING!!!)        
        VistaAdherenteSocioController controller = context.getBean(VistaAdherenteSocioController.class);
        //se le setea al controlador el objeto socio el cual se quiere ver detalle
        if (controller != null) {
            System.out.println("CONTROLLER: "+controller);
            // Imprime todas las instancias gestionadas por Spring de VistaAdherenteSocioController
            String[] beanNames = context.getBeanNamesForType(VistaAdherenteSocioController.class);
            System.out.println("Instancias gestionadas por Spring de VistaAdherenteSocioController: " + Arrays.toString(beanNames));
            controller.initData(socio);
            
        } else {
            System.err.println("El controlador es nulo después de cargar la vista.");
        }

    }
    //general method for loading the view
    private void loadView(String view) {
        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource(view));   
            loader.setControllerFactory(context::getBean);
            Pane newLoadedPane = loader.load();        

            mainContent.getChildren().clear();
            mainContent.getChildren().add(newLoadedPane);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    

    @Override
    public void initialize(URL url, ResourceBundle rb) {

    }

}

最后出现错误:

引起:java.lang.NullPointerException:无法调用“javafx.scene.control.TableColumn.setCellValueFactory(javafx.util.Callback)”,因为“this.colNombre”为空

它的工作原理如下: 我有一个侧面导航栏,其作用类似于菜单,用户选择其中一个选项,索引控制器负责在中心窗格中加载视图。另外,当需要时,其他视图(实际上是该视图的控制器)可以调用indexcontroller的方法之一(我使用autowired将实例注入其他控制器中)以加载用户需要的视图。

我测试了很多东西,但没有一个起作用。

我还有另外 5 个视图,它们各自的控制器工作得很好! 我不知道为什么这不行。

感谢您阅读本文并尝试帮助我解决我的问题,这真的让我很沮丧。这是我的第一个开发项目,也是第一个将 java fx 与 spring boot 集成的开发项目。

也为我生疏的英语道歉!

我尝试删除控制器和 FXML 视图,以在没有 Spring Boot 的情况下加载视图,多次检查 fx:id 和 @FXML 属性的名称是否匹配。

以防万一,这是我的 @SpringBootApplication 和我的 @Application 类,也是一个 StageListener。

public class JavaFXApplication extends Application{
    private ConfigurableApplicationContext context;
    
    @Override
    public void init() throws Exception{
        //here we do any kind of work that DO NOT runs on the user interface
        //to prepare the aplication, to begin, to load
        ApplicationContextInitializer<GenericApplicationContext> initializer = 
            ac->{
               ac.registerBean(Application.class, ()->JavaFXApplication.this);
               ac.registerBean(Parameters.class, this::getParameters);
               ac.registerBean(HostServices.class, this::getHostServices);
            };
        this.context = new SpringApplicationBuilder()
                .sources(BomberosSociosApplication.class)
                .initializers(initializer)
                .run(getParameters().getRaw().toArray(new String[0]));
    }
    
    @Override
    public void start(Stage primaryStage) throws Exception {
        this.context.publishEvent(new StageReadyEvent(primaryStage));
    }
    
    @Override
    public void stop() throws Exception{
        this.context.close();
        Platform.exit();
    }
}

class StageReadyEvent extends ApplicationEvent{
    
    public Stage getStage() {
        return Stage.class.cast(getSource());
    }

    public StageReadyEvent(Stage source) {
        super(source);
    }

}

@SpringBootApplication
public class BomberosSociosApplication {

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

}

@Component
public class StageListener implements ApplicationListener<StageReadyEvent>{

    private final String appTitle;
    private final Resource fxml;
    private final ApplicationContext ac;

    StageListener(@Value("${spring.application.ui.title}")String appTitle,
                  @Value("${classpath:/fxml/index.fxml}") Resource resource, ApplicationContext ac) {
        this.appTitle = appTitle;
        this.fxml = resource;
        this.ac = ac;
    }
    
    
    
    @Override
    public void onApplicationEvent(StageReadyEvent event) {
        try {
            Stage stage = event.getStage();
            URL url = this.fxml.getURL();
            FXMLLoader fxmlLoader = new FXMLLoader(url);
            fxmlLoader.setControllerFactory(ac::getBean);
            Parent root = fxmlLoader.load();
            Scene scene = new Scene(root, 600, 600);
            stage.setScene(scene);
            stage.setTitle(appTitle);
            stage.show();
        } catch (IOException ex) {
            Logger.getLogger(StageListener.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
}

此外,这是我的课程 SocioTitular 和 SocioAdherente:

@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@Entity(name="socio_titular")
public class SocioTitular {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="nro_socio")
    private Long nroSocio;
    @Column(name="nombre_completo")
    private String nombreCompleto;
    @ManyToOne
    @JoinColumn(name = "id_tipo_documento")
    private TipoDocumento tipoDoc;
    @Column(name="nro_documento")
    private Long nroDocumento;
    @Column(name="fecha_nacimiento")
    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
    private LocalDate fechaNacimiento;
    @Column(name="fecha_ingreso")
    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
    private LocalDate fechaIngreso;
    @Column(name="fecha_baja")
    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
    private LocalDate fechaBaja;
    private boolean baja;
    @ManyToOne
    @JoinColumn(name = "id_tipo_baja")
    private TipoBaja tipoBaja;
    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "id_domicilio")
    private Domicilio domicilio;
    @ManyToOne
    @JoinColumn(name = "id_categoria")
    private Categoria categoria;
    @ManyToOne
    @JoinColumn(name = "id_cobrador")
    private Cobrador cobrador;
    @OneToMany(mappedBy = "socioDeudor", cascade = CascadeType.ALL)
    private List<Deuda> deudas;
    @OneToMany(mappedBy = "socioTitular", cascade = CascadeType.ALL)
    private List<SocioAdherente>sociosAdherentes;
    
}
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@Entity(name="socio_adherente")
public class SocioAdherente {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="nro_socio_adherente")
    private Long nroSocio;
    @Column(name="nombre_completo")
    private String nombreCompleto;
    @ManyToOne
    @JoinColumn(name = "id_tipo_documento")
    private TipoDocumento tipoDoc;
    @Column(name="nro_documento")
    private Long nroDocumento;
    @Column(name="fecha_nacimiento")
    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
    private LocalDate fechaNacimiento;
    @Column(name="fecha_baja")
    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
    private LocalDate fechaBaja;
    private boolean baja;
    @ManyToOne
    @JoinColumn(name = "id_tipo_baja")
    private TipoBaja tipoBaja;
    @ManyToOne
    @JoinColumn(name = "id_socio_titular")
    private SocioTitular socioTitular;
    @ManyToOne
    @JoinColumn(name = "id_vinculo")
    private Vinculo vinculo;
}
java spring javafx nullpointerexception
1个回答
0
投票

我解决了问题,就是@Transactional注解的问题。我不知道为什么,但这在某种程度上导致我所有的 @FXML 属性都为空。 我意识到,因为我从头开始重新做了一切,包括视图和控制器......并且对于我添加的每个新组件,我测试了它是否有效。

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