也许这个问题很愚蠢。但我以前没有使用过JavaFX,所以我寻求帮助。我试图创建一个应用程序,允许您通过单击按钮创建文档。但当我尝试运行它时,我得到以下错误:
2023-11-06T10:52:27.409+05:00 INFO 17156 --- [JavaFX-Launcher] o.s.boot.SpringApplication : Starting application using Java 17.0.2 with PID 17156 (started by днс in E:\MaximDocuments)
2023-11-06T10:52:27.412+05:00 INFO 17156 --- [JavaFX-Launcher] o.s.boot.SpringApplication : No active profile set, falling back to 1 default profile: "default"
2023-11-06T10:52:27.486+05:00 INFO 17156 --- [JavaFX-Launcher] o.s.boot.SpringApplication : Started application in 0.454 seconds (process running for 1.741)
javafx.fxml.LoadException:
/E:/MaximDocuments/target/classes/mainWindow.fxml:10
at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2727)
at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:946)
at javafx.fxml.FXMLLoader$InstanceDeclarationElement.processAttribute(FXMLLoader.java:983)
at javafx.fxml.FXMLLoader$Element.processStartElement(FXMLLoader.java:230)
at javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:757)
at javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2858)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2654)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2568)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2536)
at documents.JavaFxApplication.start(JavaFxApplication.java:32)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:839)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:483)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:456)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:455)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:185)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'documents.controller.MainWindowController' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:341)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:332)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1176)
at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:943)
... 17 more
字符串
以下是我的班级:
mainWindow.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<BorderPane xmlns:fx="http://javafx.com/fxml" fx:controller="documents.controller.MainWindowController">
<top>
<HBox spacing="10" padding="10">
<Button text="Счет" onAction="#handleInvoiceAction"/>
<Button text="Платежка" fx:id="paymentButton" onAction="#handlePaymentAction"/>
<Button text="Заказ на оплату" fx:id="paymentOrderButton" onAction="#handlePaymentOrderAction"/>
<Button text="Сохранить" fx:id="saveButton" onAction="#handleSaveAction"/>
<Button text="Загрузить" fx:id="loadButton" onAction="#handleLoadAction"/>
<Button text="Просмотр" fx:id="viewButton" onAction="#handleViewAction"/>
</HBox>
</top>
<center>
<VBox spacing="10" padding="10">
<ListView fx:id="documentListView" />
</VBox>
</center>
<bottom>
<HBox spacing="10" padding="10" alignment="bottom_right">
<Button text="Выход" fx:id="exitButton" onAction="#handleExitAction"/>
</HBox>
</bottom>
</BorderPane>
型
主窗口控制器:
package documents.controller;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import documents.model.DisplayableDocument;
import documents.model.Invoice;
import documents.model.Payment;
import documents.model.PaymentOrder;
import org.springframework.stereotype.Controller;
import java.io.*;
import java.math.BigDecimal;
import java.time.LocalDate;
@Controller
public class MainWindowController {
private DisplayableDocument currentDocument;
@FXML
private void handleInvoiceAction(ActionEvent event) {
loadWindow("/invoice.fxml", "Счет");
}
@FXML
private void handlePaymentAction(ActionEvent event) {
loadWindow("/payment.fxml", "Платеж");
}
@FXML
private void handlePaymentOrderAction(ActionEvent event) {
loadWindow("/paymentOrder.fxml", "Платежное поручение");
}
@FXML
private void handleSaveAction(ActionEvent event) {
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Сохранить документ");
fileChooser.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("Text Files", "*.txt"));
File selectedFile = fileChooser.showSaveDialog(((Node) event.getSource()).getScene().getWindow());
if (selectedFile != null) {
saveDocumentToFile(selectedFile);
}
}
private void saveDocumentToFile(File file) {
if (currentDocument == null) {
return;
}
try (FileWriter fileWriter = new FileWriter(file)) {
if (currentDocument instanceof Invoice invoice) {
fileWriter.write(convertInvoiceToString(invoice));
} else if (currentDocument instanceof Payment payment) {
fileWriter.write(convertPaymentToString(payment));
} else if (currentDocument instanceof PaymentOrder paymentOrder) {
fileWriter.write(convertPaymentOrderToString(paymentOrder));
}
} catch (IOException e) {
e.printStackTrace();
}
}
private String convertInvoiceToString(Invoice invoice) {
return String.format(
"Invoice,%s,%s,%s,%s,%s,%s,%s,%s%n",
invoice.getId(),
invoice.getNumber(),
invoice.getDate(),
invoice.getUser(),
invoice.getAmount(),
invoice.getCurrency(),
invoice.getCurrencyRate(),
invoice.getProduct(),
invoice.getQuantity()
);
}
private String convertPaymentToString(Payment payment) {
return String.format(
"Payment,%s,%s,%s,%s,%s,%s%n",
payment.getId(),
payment.getNumber(),
payment.getDate(),
payment.getUser(),
payment.getAmount(),
payment.getEmployee()
);
}
private String convertPaymentOrderToString(PaymentOrder paymentOrder) {
return String.format(
"PaymentOrder,%s,%s,%s,%s,%s,%s,%s,%s,%s%n",
paymentOrder.getId(),
paymentOrder.getNumber(),
paymentOrder.getDate(),
paymentOrder.getUser(),
paymentOrder.getContractor(),
paymentOrder.getAmount(),
paymentOrder.getCurrency(),
paymentOrder.getCurrencyRate(),
paymentOrder.getCommission()
);
}
@FXML
private void handleLoadAction(ActionEvent event) {
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Загрузить документ");
fileChooser.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("Text Files", "*.txt"));
File selectedFile = fileChooser.showOpenDialog(((Node) event.getSource()).getScene().getWindow());
if (selectedFile != null) {
loadDocumentFromFile(selectedFile);
}
}
private void loadDocumentFromFile(File file) {
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
String line;
while ((line = reader.readLine()) != null) {
if (line.startsWith("Invoice:")) {
Invoice invoice = parseInvoice(String.valueOf(reader));
} else if (line.startsWith("Payment:")) {
Payment payment = parsePayment(String.valueOf(reader));
} else if (line.startsWith("PaymentOrder:")) {
PaymentOrder paymentOrder = parsePaymentOrder(String.valueOf(reader));
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
private Invoice parseInvoice(String line) {
String[] data = line.split(",");
return new Invoice(
Integer.parseInt(data[1]),
data[2],
LocalDate.parse(data[3]),
data[4],
new BigDecimal(data[5]),
data[6],
new BigDecimal(data[7]),
data[8],
Integer.parseInt(data[9])
);
}
private Payment parsePayment(String line) {
String[] data = line.split(",");
return new Payment(
Integer.parseInt(data[1]),
data[2],
LocalDate.parse(data[3]),
data[4],
new BigDecimal(data[5]),
data[6]
);
}
private PaymentOrder parsePaymentOrder(String line) {
String[] data = line.split(",");
return new PaymentOrder(
Integer.parseInt(data[1]),
data[2],
LocalDate.parse(data[3]),
data[4],
data[5],
new BigDecimal(data[6]),
data[7],
new BigDecimal(data[8]),
new BigDecimal(data[9])
);
}
@FXML
private void handleViewAction(ActionEvent event) {
loadWindow("/documentDetails.fxml", "Детали документа");
}
@FXML
private void handleExitAction(ActionEvent event) {
cancel(event);
}
private void loadWindow(String path, String title) {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource(path));
Parent root = loader.load();
Stage stage = new Stage();
stage.setTitle(title);
stage.setScene(new Scene(root));
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
private void cancel(ActionEvent event) {
Stage stage = (Stage) ((Node) event.getSource()).getScene().getWindow();
stage.close();
}
}
型
ApplicationRunner:
package documents;
import javafx.application.Application;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ApplicationRunner {
public static void main(String[] args) {
Application.launch(JavaFxApplication.class, args);
}
}
型
JavaFx应用程序:
package documents;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
import java.io.IOException;
public class JavaFxApplication extends Application {
private ConfigurableApplicationContext context;
@Override
public void init() {
SpringApplicationBuilder builder = new SpringApplicationBuilder(ApplicationRunner.class);
String[] args = getParameters().getRaw().toArray(new String[0]);
this.context = builder.run(args);
}
@Override
public void start(Stage stage) {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/mainWindow.fxml"));
fxmlLoader.setControllerFactory(context::getBean);
try {
Parent root = fxmlLoader.load();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.setTitle("Main Window");
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void stop() {
this.context.close();
Platform.exit();
}
}
型
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.maxim.documents</groupId>
<artifactId>TestMaximDociments</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.4</version>
</parent>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>22-ea+16</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>22-ea+16</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>8.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.8</version>
<configuration>
<mainClass>org/maxim/documents/JavaFxApplication</mainClass>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
型
我尝试使用其他fxml文件,但错误是一样的。添加一个方案,但它也没有帮助。我读到如果你使用构造函数,可能会出现这个问题。我试图通过字段实现这一点,但错误没有改变。
1条答案
按热度按时间t5zmwmid1#
您正在尝试运行错误的
ApplicationRunner
。你有一个名为
documents.ApplicationRunner
的类,但是你从Spring导入了org.springframework.boot.ApplicationRunner
,并尝试使用它来初始化你的应用程序。你自己的ApplicationRunner
在你自己的包中,默认情况下会删除包和子包中的所有bean,但是Spring的ApplicationRunner
不知道你的包,也不会这样做。为了避免混淆,我建议您将
ApplicationRunner
命名为其他名称(在下面的示例中,我使用了MySpringApplication
,但如果需要,您可以使用特定于您的应用程序的名称)。参考资料
关于这个主题的更多信息在这里的答案中提供:
工作代码
为了创建这个,我在Idea中创建了一个新的JavaFX项目,删除了生成的
module-info.java
以使项目非模块化(不幸的是,Java模块化和Spring 6混合得很差)。从Gluon下载并提取了JavaFX 21 SDK。右键单击类MySpringApplication
选择“更多运行/修改:修改运行配置.”将运行配置的VM参数设置为:字符串
我修改了代码来调用你的spring应用程序
MySpringApplication
,并在你的JavaFXApplication
中导入和使用它。我删除了对缺失类的所有引用(大多数这些东西可能在服务层中处理得更好,而不是在Controller类中)。
我将数据库依赖从postgres改为h2,这样我就不必设置postgres了。
我删除了lombok依赖项,因为我看到其他有经验的开发人员在JavaFX环境中使用时注意到它的问题,并建议一般不要使用它。
我修改了fxml,使其能够加载(它错误地定义了insets,所以我删除了那些引用)。
FXML控制器不是Spring控制器,Spring控制器用于Java Servlet风格的框架,不要用Spring
@Controller
annotation注解FXML控制器,带有prototype
范围的@Component
annotation可能是最好的。(我在示例中使用了推荐的annotation)。不要使用名称中带有
ea
的JavaFX版本,它们是抢先体验版本,可能不稳定(在我的示例中,我使用的是稳定版本21)。未决问题
您的代码中还有另一个可能的问题,我没有尝试解决。尽管您正确地设置了控制器工厂,以便在加载主窗口FXML时使用spring上下文将Spring bean引用注入控制器:
型
在
MainWindowController.loadWindow
方法中执行的后续页面加载没有设置控制器因子。这意味着这些后续页面加载都不会将Spring Bean注入到其相关控制器中。我将把解决这个悬而未决的问题作为读者的练习;-)
工作源代码
型
型
型
型
型
输出
x1c 0d1x的数据
型