add JavaFX demo application

- Add FxMain as JavaFX application entry with IOC integration
- Add FxConfig with @Bean factory methods for DateTimeFormatter
- Add MainController with constructor injection
- Add UserService and MessageService layers
- Add main.fxml view with user management UI
- Add javafx-fxml dependency and javafx-maven-plugin
- Add demo documentation and run script
- Demonstrate @Controller, @Service, @Qualifier, @PostConstruct in JavaFX context

Run with: mvn javafx:run or run-javafx-demo.bat

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Timi
2026-01-11 12:31:50 +08:00
parent 71be7c07c0
commit 13926ea24a
9 changed files with 588 additions and 0 deletions

View File

@ -0,0 +1,30 @@
package com.imyeyu.inject.javafxdemo;
import com.imyeyu.inject.annotation.Bean;
import com.imyeyu.inject.annotation.Configuration;
import java.time.format.DateTimeFormatter;
/**
* JavaFX 应用配置
*
* @author 夜雨
*/
@Configuration
public class FxConfig {
@Bean
public DateTimeFormatter dateTimeFormatter() {
return DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
}
@Bean("appTitle")
public String appTitle() {
return "Timi-Inject JavaFX Demo";
}
@Bean("version")
public String version() {
return "0.0.2";
}
}

View File

@ -0,0 +1,51 @@
package com.imyeyu.inject.javafxdemo;
import com.imyeyu.inject.TimiInject;
import com.imyeyu.inject.annotation.Import;
import com.imyeyu.inject.annotation.TimiInjectApplication;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
/**
* JavaFX 应用入口
*
* @author 夜雨
*/
@TimiInjectApplication("com.imyeyu.inject.javafxdemo")
@Import(FxConfig.class)
public class FxMain extends Application {
private static TimiInject inject;
public static void main(String[] args) {
// 启动 IOC 容器
inject = TimiInject.run(FxMain.class);
// 启动 JavaFX 应用
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
// 创建 FXMLLoader 并设置控制器工厂
FXMLLoader loader = new FXMLLoader(getClass().getResource("/javafxdemo/main.fxml"));
loader.setControllerFactory(type -> inject.di(type));
Parent root = loader.load();
Scene scene = new Scene(root, 600, 400);
primaryStage.setTitle("Timi-Inject JavaFX Demo");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* 获取 IOC 容器实例
*/
public static TimiInject getInject() {
return inject;
}
}

View File

@ -0,0 +1,132 @@
package com.imyeyu.inject.javafxdemo;
import com.imyeyu.inject.annotation.Controller;
import com.imyeyu.inject.annotation.PostConstruct;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.*;
/**
* 主界面控制器
*
* @author 夜雨
*/
@Controller
public class MainController {
@FXML
private Label welcomeLabel;
@FXML
private Label timeLabel;
@FXML
private Label countLabel;
@FXML
private TextField usernameField;
@FXML
private ListView<String> userListView;
@FXML
private TextArea logArea;
private final UserService userService;
private final MessageService messageService;
private final ObservableList<String> userList = FXCollections.observableArrayList();
public MainController(UserService userService, MessageService messageService) {
this.userService = userService;
this.messageService = messageService;
}
@PostConstruct
public void init() {
log("MainController initialized");
}
@FXML
public void initialize() {
// 设置欢迎消息
welcomeLabel.setText(messageService.getWelcomeMessage());
// 加载用户列表
refreshUserList();
// 更新时间
updateTime();
log("UI initialized");
}
@FXML
private void handleAddUser() {
String username = usernameField.getText().trim();
if (username.isEmpty()) {
showError("Please enter a username");
return;
}
try {
userService.addUser(username);
refreshUserList();
usernameField.clear();
log(messageService.getSuccessMessage("User added"));
} catch (Exception e) {
showError(e.getMessage());
}
}
@FXML
private void handleRemoveUser() {
String selectedUser = userListView.getSelectionModel().getSelectedItem();
if (selectedUser == null) {
showError("Please select a user to remove");
return;
}
userService.removeUser(selectedUser);
refreshUserList();
log(messageService.getSuccessMessage("User removed"));
}
@FXML
private void handleRefresh() {
refreshUserList();
updateTime();
log("Refreshed");
}
@FXML
private void handleClearLog() {
logArea.clear();
log("Log cleared");
}
private void refreshUserList() {
userList.clear();
userList.addAll(userService.getAllUsers());
userListView.setItems(userList);
countLabel.setText("Total Users: " + userService.getUserCount());
}
private void updateTime() {
timeLabel.setText("Current Time: " + userService.getCurrentTime());
}
private void showError(String message) {
log(messageService.getErrorMessage(message));
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setTitle("Error");
alert.setHeaderText(null);
alert.setContentText(message);
alert.showAndWait();
}
private void log(String message) {
String timestamp = userService.getCurrentTime();
logArea.appendText(String.format("[%s] %s%n", timestamp, message));
}
}

View File

@ -0,0 +1,34 @@
package com.imyeyu.inject.javafxdemo;
import com.imyeyu.inject.annotation.Qualifier;
import com.imyeyu.inject.annotation.Service;
/**
* 消息服务
*
* @author 夜雨
*/
@Service
public class MessageService {
private final String appTitle;
private final String version;
public MessageService(@Qualifier("appTitle") String appTitle,
@Qualifier("version") String version) {
this.appTitle = appTitle;
this.version = version;
}
public String getWelcomeMessage() {
return String.format("Welcome to %s v%s!", appTitle, version);
}
public String getSuccessMessage(String action) {
return action + " successfully!";
}
public String getErrorMessage(String error) {
return "Error: " + error;
}
}

View File

@ -0,0 +1,59 @@
package com.imyeyu.inject.javafxdemo;
import com.imyeyu.inject.annotation.PostConstruct;
import com.imyeyu.inject.annotation.Service;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
/**
* 用户服务
*
* @author 夜雨
*/
@Service
public class UserService {
private final DateTimeFormatter dateTimeFormatter;
private final List<String> users = new ArrayList<>();
public UserService(DateTimeFormatter dateTimeFormatter) {
this.dateTimeFormatter = dateTimeFormatter;
}
@PostConstruct
public void init() {
users.add("Admin");
users.add("User1");
users.add("User2");
System.out.println("UserService initialized with " + users.size() + " users");
}
public List<String> getAllUsers() {
return new ArrayList<>(users);
}
public void addUser(String username) {
if (username == null || username.isBlank()) {
throw new IllegalArgumentException("Username cannot be empty");
}
if (users.contains(username)) {
throw new IllegalArgumentException("User already exists");
}
users.add(username);
}
public void removeUser(String username) {
users.remove(username);
}
public String getCurrentTime() {
return LocalDateTime.now().format(dateTimeFormatter);
}
public int getUserCount() {
return users.size();
}
}