Springboot整合JAVAFX

news2025/4/18 22:16:54

Springboot整合JAVAFX

实体与VO设计

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>com.elitedatai</groupId>
    <artifactId>javafxTest</artifactId>
    <version>1.0</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.3.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <javafx.version>21</javafx.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- Spring Boot Starter -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!-- javaFX -->
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-controls</artifactId>
            <version>${javafx.version}</version>
        </dependency>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-fxml</artifactId>
            <version>${javafx.version}</version>
        </dependency>

        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>


            <!-- JavaFX Maven Plugin -->
            <plugin>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-maven-plugin</artifactId>
                <version>0.0.8</version>
                <configuration>
                    <mainClass>com.elitedatai.MainApp</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>


</project>

实体类设计:

package com.elitedatai.model;

import jakarta.persistence.*;
import lombok.Data;

import java.time.LocalDateTime;

/**
 * @author llg
 * @slogan 致敬大师,致敬未来的你
 * @create 2025-04-10 15:57
 */
@Data
@Table(name = "Work_Order")
@Entity
public class WorkOrder {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, length = 50)
    private String orderNo;          // 工单编号

    @Column(nullable = false, length = 100)
    private String productName;      // 产品名称

    @Column(nullable = false, length = 50)
    private String productCode;      // 产品编码

    @Column(nullable = false)
    private Integer plannedQuantity; // 计划数量

    @Column(nullable = false)
    private Integer completedQuantity = 0; // 已完成数量

    @Column(nullable = false)
    private LocalDateTime startTime; // 计划开始时间

    @Column(nullable = false)
    private LocalDateTime endTime;   // 计划结束时间

    @Enumerated(EnumType.STRING)
    @Column(nullable = false, length = 20)
    private OrderStatus status;      // 工单状态

    @Column(length = 500)
    private String remark;           // 备注

    // 工单状态枚举
    public enum OrderStatus {
        PENDING,        // 待开始
        IN_PROGRESS,    // 进行中
        PAUSED,         // 已暂停
        COMPLETED,      // 已完成
        CANCELLED       // 已取消
    }
}

VO类设计:

/**
 * 工单值对象 - 用于前后端数据传输
 * 这个类可以被Spring MVC和JavaFX共同使用
 */
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class WorkOrderVO {
    private Long id;
    private String orderNo;
    private String productName;
    private String productCode;
    private Integer plannedQuantity;
    private Integer completedQuantity;
    private LocalDateTime startTime;
    private LocalDateTime endTime;
    private WorkOrder.OrderStatus status;
    private String remark;
    
    // 计算进度百分比
    public Double getProgress() {
        if (plannedQuantity == null || plannedQuantity == 0) {
            return 0.0;
        }
        return (completedQuantity.doubleValue()  / plannedQuantity.doubleValue())  * 100;
    }
    
    // 从实体类转换
    public static WorkOrderVO fromEntity(WorkOrder entity) {
        if (entity == null) return null;
        
        WorkOrderVO vo = new WorkOrderVO();
        vo.setId(entity.getId()); 
        vo.setOrderNo(entity.getOrderNo()); 
        vo.setProductName(entity.getProductName()); 
        vo.setProductCode(entity.getProductCode()); 
        vo.setPlannedQuantity(entity.getPlannedQuantity()); 
        vo.setCompletedQuantity(entity.getCompletedQuantity()); 
        vo.setStartTime(entity.getStartTime()); 
        vo.setEndTime(entity.getEndTime()); 
        vo.setStatus(entity.getStatus()); 
        vo.setRemark(entity.getRemark()); 
        return vo;
    }
    
    // 转换为实体类
    public WorkOrder toEntity() {
        WorkOrder entity = new WorkOrder();
        entity.setId(this.getId()); 
        entity.setOrderNo(this.getOrderNo()); 
        entity.setProductName(this.getProductName()); 
        entity.setProductCode(this.getProductCode()); 
        entity.setPlannedQuantity(this.getPlannedQuantity()); 
        entity.setCompletedQuantity(this.getCompletedQuantity()); 
        entity.setStartTime(this.getStartTime()); 
        entity.setEndTime(this.getEndTime()); 
        entity.setStatus(this.getStatus()); 
        entity.setRemark(this.getRemark()); 
        return entity;
    }
}

SpringBoot与JavaFX集成配置

JavaFX配置类 (JavaFXConfiguration.java)

package com.elitedatai.config;

/**
 * @author llg
 * @slogan 致敬大师,致敬未来的你
 * @create 2025-04-10 15:47
 */

import javafx.application.Application;
import javafx.application.HostServices;
import javafx.application.Platform;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.GenericApplicationContext;

import java.util.function.Consumer;

/**
 * JavaFX配置类,负责启动JavaFX应用并集成Spring上下文
 * 核心功能:
 * 1. 初始化Spring应用上下文
 * 2. 加载JavaFX主舞台(Stage)
 * 3. 管理两者生命周期
 */
public class JavaFXConfiguration extends Application {

    // Spring应用上下文,用于依赖注入
    private ConfigurableApplicationContext context;
    // JavaFX根节点,所有UI组件的容器
    private Parent root;
    // Stage自定义配置回调函数
    private Consumer<Stage> stageConsumer;

    @Override
    public void init() throws Exception {
        // // 创建Spring上下文初始化器,注册JavaFX核心对象
        ApplicationContextInitializer<GenericApplicationContext> initializer = ac -> {
            // 将JavaFX Application实例注册为Spring Bean
            ac.registerBean(Application.class,  () -> JavaFXConfiguration.this);
            // 注册启动参数(命令行参数)
            ac.registerBean(Parameters.class,  this::getParameters);
            // 注册HostServices(用于打开网页等操作)
            ac.registerBean(HostServices.class,  this::getHostServices);
        };
        // 构建Spring应用(关键步骤)
        this.context  = new SpringApplicationBuilder()
                .sources(com.elitedatai.Application.class)  // 指定SpringBoot主类
                .initializers(initializer)                  // 添加上文初始化器
                .run(getParameters().getRaw().toArray(new String[0])); // 传递启动参数
    }

    /**
     * JavaFX主入口(UI线程开始执行)
     * @param primaryStage 主舞台(相当于主窗口)
     */
    @Override
    public void start(Stage primaryStage) throws Exception {
        // 从Spring容器获取FXML加载配置
        FxmlViewConfiguration viewConfig = context.getBean(FxmlViewConfiguration.class);

        // 加载主视图(触发FXML文件的解析和控制器初始化)
        this.root  = viewConfig.mainView();

        // 创建场景图(Scene是UI组件的根容器)
        Scene scene = new Scene(root, 1200, 800);

        // 配置主舞台
        primaryStage.setScene(scene);           // 绑定场景到舞台
        primaryStage.setTitle(" 工厂MES上位机系统"); // 设置窗口标题
        primaryStage.centerOnScreen();           // 窗口居中显示

        // 执行自定义舞台配置(如果有)
        if (stageConsumer != null) {
            stageConsumer.accept(primaryStage);
        }

        // 显示窗口(至此UI可见)
        primaryStage.show();
    }

    /**
     * JavaFX停止方法(窗口关闭时调用)
     */
    @Override
    public void stop() throws Exception {
        // 关闭Spring应用上下文(触发@PreDestroy等生命周期回调)
        this.context.close();
        // 确保JavaFX平台完全退出
        Platform.exit();
    }

    /**
     * 设置舞台自定义配置器
     * @param stageConsumer 接收Stage对象的函数式接口
     */
    public void setStageConsumer(Consumer<Stage> stageConsumer) {
        this.stageConsumer  = stageConsumer;
    }
}

FXML视图配置 (FxmlViewConfiguration.java)

package com.elitedatai.config;

/**
 * @author llg
 * @slogan 致敬大师,致敬未来的你
 * @create 2025-04-10 15:48
 */

import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.net.URL;

/**
 * FXML视图配置类,负责加载FXML文件并注入Spring管理的控制器
 */
@Component
public class FxmlViewConfiguration {

    private final ApplicationContext context;

    @Autowired
    public FxmlViewConfiguration(ApplicationContext context) {
        this.context  = context;
    }

    /**
     * 加载主视图
     */
    public Parent mainView() throws IOException {
        return loadView("/fxml/main.fxml");
    }

    /**
     * 加载工单管理视图
     */
    public Parent workOrderView() throws IOException {
        return loadView("/fxml/work_order.fxml");
    }

    /**
     * 通用视图加载方法
     */
    private Parent loadView(String fxmlPath) throws IOException {
        FXMLLoader loader = new FXMLLoader();
        URL resource = getClass().getResource(fxmlPath);
        loader.setLocation(resource);
        loader.setControllerFactory(context::getBean);  // 使用Spring管理的控制器
        return loader.load();
    }
}

服务层接口

我使用的是JPA框架,根据实体,写好实体相关仓库接口和业务层接口,直接贴代码:

/**
 * 工单服务类 - 业务逻辑处理
 */
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class WorkOrderService {
    
    private final WorkOrderRepository workOrderRepository;
    private final ModelMapper modelMapper;
    
    /**
     * 创建工单
     */
    @Transactional
    public WorkOrderVO create(WorkOrderVO vo) {
        WorkOrder entity = vo.toEntity(); 
        WorkOrder saved = workOrderRepository.save(entity); 
        return WorkOrderVO.fromEntity(saved); 
    }
    
    /**
     * 更新工单
     */
    @Transactional
    public WorkOrderVO update(WorkOrderVO vo) {
        WorkOrder existing = workOrderRepository.findById(vo.getId()) 
                .orElseThrow(() -> new RuntimeException("工单不存在"));
        
        // 更新字段
        existing.setOrderNo(vo.getOrderNo()); 
        existing.setProductName(vo.getProductName()); 
        existing.setProductCode(vo.getProductCode()); 
        existing.setPlannedQuantity(vo.getPlannedQuantity()); 
        existing.setCompletedQuantity(vo.getCompletedQuantity()); 
        existing.setStartTime(vo.getStartTime()); 
        existing.setEndTime(vo.getEndTime()); 
        existing.setStatus(vo.getStatus()); 
        existing.setRemark(vo.getRemark()); 
        
        WorkOrder updated = workOrderRepository.save(existing); 
        return WorkOrderVO.fromEntity(updated); 
    }
    
    /**
     * 获取所有工单
     */
    public List<WorkOrderVO> findAll() {
        return workOrderRepository.findAll().stream() 
                .map(WorkOrderVO::fromEntity)
                .collect(Collectors.toList()); 
    }
    
    /**
     * 分页查询工单
     */
    public Page<WorkOrderVO> findAll(Pageable pageable) {
        return workOrderRepository.findAll(pageable) 
                .map(WorkOrderVO::fromEntity);
    }
    
    /**
     * 根据ID获取工单
     */
    public WorkOrderVO findById(Long id) {
        return workOrderRepository.findById(id) 
                .map(WorkOrderVO::fromEntity)
                .orElseThrow(() -> new RuntimeException("工单不存在"));
    }
    
    /**
     * 删除工单
     */
    @Transactional
    public void delete(Long id) {
        workOrderRepository.deleteById(id); 
    }
    
    /**
     * 更新工单进度
     */
    @Transactional
    public WorkOrderVO updateProgress(Long id, Integer completed) {
        WorkOrder order = workOrderRepository.findById(id) 
                .orElseThrow(() -> new RuntimeException("工单不存在"));
        
        order.setCompletedQuantity(completed); 
        if (completed >= order.getPlannedQuantity())  {
            order.setStatus(WorkOrder.OrderStatus.COMPLETED); 
        }
        
        WorkOrder updated = workOrderRepository.save(order); 
        return WorkOrderVO.fromEntity(updated); 
    }
}

控制层

javafx相关控制层

Main控制层:
package com.elitedatai.controller.fx;

import com.elitedatai.config.FxmlViewConfiguration;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import org.springframework.stereotype.Controller;

/**
 * 主界面控制器 - 负责管理主界面的导航和状态显示
 */
@Controller
public class MainController {

    @FXML private StackPane contentPane;
    @FXML private Label statusLabel;

    private final FxmlViewConfiguration viewConfig;

    public MainController(FxmlViewConfiguration viewConfig) {
        this.viewConfig  = viewConfig;
    }

    /**
     * 初始化方法,FXML加载后自动调用
     */
    @FXML
    public void initialize() {
        // 默认加载工单管理视图
        showWorkOrderView();
    }

    /**
     * 显示工单管理视图
     */
    @FXML
    public void showWorkOrderView() {
        try {
            contentPane.getChildren().clear();
            contentPane.getChildren().add(viewConfig.workOrderView());
            updateStatus("工单管理视图已加载");
        } catch (Exception e) {
            updateStatus("加载工单视图失败: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 退出应用程序
     */
    @FXML
    public void handleExit() {
        javafx.application.Platform.exit();
    }

    /**
     * 更新状态栏信息
     */
    private void updateStatus(String message) {
        statusLabel.setText(message);
    }
}

main.fxml:
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>

<BorderPane xmlns="http://javafx.com/javafx/17"  xmlns:fx="http://javafx.com/fxml/1"
            fx:controller="com.elitedatai.controller.fx.MainController">

    <top>
        <MenuBar BorderPane.alignment="CENTER">
            <menus>
                <Menu text="文件">
                    <items>
                        <MenuItem text="退出" onAction="#handleExit" />
                    </items>
                </Menu>
                <Menu text="工单管理">
                    <items>
                        <MenuItem text="工单列表" onAction="#showWorkOrderView" />
                    </items>
                </Menu>
                <Menu text="帮助">
                    <items>
                        <MenuItem text="关于" />
                    </items>
                </Menu>
            </menus>
        </MenuBar>
    </top>

    <center>
        <StackPane fx:id="contentPane" />
    </center>

    <bottom>
        <HBox alignment="CENTER" spacing="10" style="-fx-background-color: #f0f0f0; -fx-padding: 5;">
            <Label text="工厂MES上位机系统" />
            <Label text="版本: 1.0.0" />
            <Label fx:id="statusLabel" text="就绪" />
        </HBox>
    </bottom>
</BorderPane>

WorkOrderController:
package com.elitedatai.controller.fx;

import com.elitedatai.model.Test;
import com.elitedatai.service.WorkOrderService;
import com.elitedatai.vo.TestVO;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;

import java.time.LocalDateTime;
import java.util.List;

/**
 * JavaFX工单控制器
 */
@Controller
@RequiredArgsConstructor
public class WorkOrderController {

    private final WorkOrderService workOrderService;

    // FXML注入的UI组件
    @FXML private TableView<TestVO> workOrderTable;
    @FXML private TableColumn<TestVO, String> orderNoColumn;
    @FXML private TableColumn<TestVO, String> productNameColumn;
    @FXML private TableColumn<TestVO, Integer> plannedQuantityColumn;
    @FXML private TableColumn<TestVO, Integer> completedQuantityColumn;
    @FXML private TableColumn<TestVO, String> progressColumn;
    @FXML private TableColumn<TestVO, String> statusColumn;

    @FXML private TextField orderNoField;
    @FXML private TextField productNameField;
    @FXML private TextField productCodeField;
    @FXML private TextField plannedQuantityField;
    @FXML private DatePicker startDatePicker;
    @FXML private DatePicker endDatePicker;
    @FXML private ComboBox<String> statusComboBox;
    @FXML private TextArea remarkArea;

    private final ObservableList<TestVO> workOrderData = FXCollections.observableArrayList();

    /**
     * 初始化方法,由FXML加载器调用
     */
    @FXML
    public void initialize() {
        // 配置表格列
        orderNoColumn.setCellValueFactory(new PropertyValueFactory<>("orderNo"));
        productNameColumn.setCellValueFactory(new  PropertyValueFactory<>("productName"));
        plannedQuantityColumn.setCellValueFactory(new  PropertyValueFactory<>("plannedQuantity"));
        completedQuantityColumn.setCellValueFactory(new  PropertyValueFactory<>("completedQuantity"));
        progressColumn.setCellValueFactory(cellData  -> {
            double progress = cellData.getValue().getProgress();
            return new javafx.beans.property.SimpleStringProperty(String.format("%.2f%%",  progress));
        });
        statusColumn.setCellValueFactory(new  PropertyValueFactory<>("status"));

        // 绑定数据
        workOrderTable.setItems(workOrderData);

        // 加载数据
        refreshData();

        // 配置状态下拉框
        statusComboBox.getItems().addAll(
                "PENDING", "IN_PROGRESS", "PAUSED", "COMPLETED", "CANCELLED"
        );
    }

    /**
     * 刷新表格数据
     */
    private void refreshData() {
        List<TestVO> orders = workOrderService.findAll();
        workOrderData.clear();
        workOrderData.addAll(orders);
    }

    /**
     * 创建新工单
     */
    @FXML
    private void handleCreate() {
        try {
            TestVO vo = new TestVO();
            vo.setOrderNo(orderNoField.getText());
            vo.setProductName(productNameField.getText());
            vo.setProductCode(productCodeField.getText());
            vo.setPlannedQuantity(Integer.parseInt(plannedQuantityField.getText()));
            vo.setCompletedQuantity(0);
            vo.setStartTime(LocalDateTime.from(startDatePicker.getValue().atStartOfDay()));
            vo.setEndTime(LocalDateTime.from(endDatePicker.getValue().atStartOfDay()));
            vo.setStatus(Test.OrderStatus.valueOf(statusComboBox.getValue()));
            vo.setRemark(remarkArea.getText());

            workOrderService.create(vo);
            refreshData();
            clearFields();

            showAlert("成功", "工单创建成功", Alert.AlertType.INFORMATION);
        } catch (Exception e) {
            showAlert("错误", "创建工单失败: " + e.getMessage(),  Alert.AlertType.ERROR);
        }
    }

    /**
     * 更新工单进度
     */
    @FXML
    private void handleUpdateProgress() {
        TestVO selected = workOrderTable.getSelectionModel().getSelectedItem();
        if (selected == null) {
            showAlert("警告", "请先选择一条工单", Alert.AlertType.WARNING);
            return;
        }

        TextInputDialog dialog = new TextInputDialog(selected.getCompletedQuantity().toString());
        dialog.setTitle(" 更新进度");
        dialog.setHeaderText(" 请输入已完成数量");
        dialog.setContentText(" 数量:");

        dialog.showAndWait().ifPresent(completed  -> {
            try {
                int completedQty = Integer.parseInt(completed);
                workOrderService.updateProgress(selected.getId(),  completedQty);
                refreshData();
                showAlert("成功", "工单进度更新成功", Alert.AlertType.INFORMATION);
            } catch (NumberFormatException e) {
                showAlert("错误", "请输入有效的数字", Alert.AlertType.ERROR);
            } catch (Exception e) {
                showAlert("错误", "更新进度失败: " + e.getMessage(),  Alert.AlertType.ERROR);
            }
        });
    }

    /**
     * 显示警告对话框
     */
    private void showAlert(String title, String message, Alert.AlertType type) {
        Alert alert = new Alert(type);
        alert.setTitle(title);
        alert.setHeaderText(null);
        alert.setContentText(message);
        alert.showAndWait();
    }

    /**
     * 清空输入字段
     */
    private void clearFields() {
        orderNoField.clear();
        productNameField.clear();
        productCodeField.clear();
        plannedQuantityField.clear();
        startDatePicker.setValue(null);
        endDatePicker.setValue(null);
        statusComboBox.setValue(null);
        remarkArea.clear();
    }
}

workorder.fxml:
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>

<VBox xmlns="http://javafx.com/javafx/17"  xmlns:fx="http://javafx.com/fxml/1"
      fx:controller="com.elitedatai.controller.fx.WorkOrderController"  spacing="10">

    <Label text="工单管理" style="-fx-font-size: 16pt; -fx-font-weight: bold;" />

    <HBox spacing="10" alignment="CENTER_LEFT">
        <Label text="工单编号:" />
        <TextField fx:id="orderNoField" promptText="请输入工单编号" />

        <Label text="产品名称:" />
        <TextField fx:id="productNameField" promptText="请输入产品名称" />

        <Label text="产品编码:" />
        <TextField fx:id="productCodeField" promptText="请输入产品编码" />
    </HBox>

    <HBox spacing="10" alignment="CENTER_LEFT">
        <Label text="计划数量:" />
        <TextField fx:id="plannedQuantityField" promptText="请输入计划数量" />

        <Label text="开始日期:" />
        <DatePicker fx:id="startDatePicker" />

        <Label text="结束日期:" />
        <DatePicker fx:id="endDatePicker" />

        <Label text="状态:" />
        <ComboBox fx:id="statusComboBox" promptText="选择状态" />
    </HBox>

    <HBox spacing="10" alignment="CENTER_LEFT">
        <Label text="备注:" />
        <TextArea fx:id="remarkArea" promptText="请输入备注信息" wrapText="true" prefRowCount="2" />
    </HBox>

    <HBox spacing="10">
        <Button text="创建工单" onAction="#handleCreate" style="-fx-base: #4CAF50;" />
        <Button text="更新进度" onAction="#handleUpdateProgress" style="-fx-base: #2196F3;" />
    </HBox>

    <TableView fx:id="workOrderTable" prefHeight="400">
        <columns>
            <TableColumn text="工单编号" fx:id="orderNoColumn" prefWidth="120" />
            <TableColumn text="产品名称" fx:id="productNameColumn" prefWidth="150" />
            <TableColumn text="计划数量" fx:id="plannedQuantityColumn" prefWidth="80" />
            <TableColumn text="完成数量" fx:id="completedQuantityColumn" prefWidth="80" />
            <TableColumn text="进度" fx:id="progressColumn" prefWidth="80" />
            <TableColumn text="状态" fx:id="statusColumn" prefWidth="100" />
        </columns>
    </TableView>
</VBox>

web控制层

package com.elitedatai.controller.web;

/**
 * @author llg
 * @slogan 致敬大师,致敬未来的你
 * @create 2025-04-10 16:19
 */

import com.elitedatai.service.WorkOrderService;
import com.elitedatai.vo.TestVO;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;

/**
 * 工单REST API控制器
 */
@RestController
@RequestMapping("/api/work-orders")
@RequiredArgsConstructor
public class WorkOrderApiController {

    private final WorkOrderService workOrderService;

    /**
     * 获取所有工单
     */
    @GetMapping
    public ResponseEntity<List<TestVO>> findAll() {
        return ResponseEntity.ok(workOrderService.findAll());
    }

    /**
     * 分页查询工单
     */
    @GetMapping("/page")
    public ResponseEntity<Page<TestVO>> findAll(Pageable pageable) {
        return ResponseEntity.ok(workOrderService.findAll(pageable));
    }

    /**
     * 根据ID获取工单
     */
    @GetMapping("/{id}")
    public ResponseEntity<TestVO> findById(@PathVariable Long id) {
        return ResponseEntity.ok(workOrderService.findById(id));
    }

    /**
     * 创建工单
     */
    @PostMapping
    public ResponseEntity<TestVO> create(@RequestBody TestVO vo) {
        return ResponseEntity.ok(workOrderService.create(vo));
    }

    /**
     * 更新工单
     */
    @PutMapping("/{id}")
    public ResponseEntity<TestVO> update(@PathVariable Long id, @RequestBody TestVO vo) {
        vo.setId(id);
        return ResponseEntity.ok(workOrderService.update(vo));
    }

    /**
     * 删除工单
     */
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> delete(@PathVariable Long id) {
        workOrderService.delete(id);
        return ResponseEntity.noContent().build();
    }

    /**
     * 更新工单进度
     */
    @PatchMapping("/{id}/progress")
    public ResponseEntity<TestVO> updateProgress(
            @PathVariable Long id,
            @RequestParam Integer completed) {
        return ResponseEntity.ok(workOrderService.updateProgress(id,  completed));
    }
}

启动类与主应用

SpringBoot主类 (Application.java)

package com.elitedatai;

/**
 * @author llg
 * @slogan 致敬大师,致敬未来的你
 * @create 2025-04-10 16:12
 */

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * SpringBoot主启动类
 */
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        // 检查是否以JavaFX模式启动
        if (args.length  > 0 && args[0].equals("--javafx")) {
            com.elitedatai.MainApp.main(args);
        } else {
            SpringApplication.run(Application.class,  args);
        }
    }
}

JavaFX主类 (MainApp.java)

package com.elitedatai;

import com.elitedatai.config.JavaFXConfiguration;
import javafx.application.Application;

/**
 * JavaFX主启动类
 */
public class MainApp {
    public static void main(String[] args) {
        // 启动JavaFX应用
        Application.launch(JavaFXConfiguration.class,  "--javafx");
    }
}

运行与部署

1. 运行应用

直接想启动web就运行web主类,想启动javafx就运行javafx主类

2.打包应用

创建可执行JAR:

mvn clean package

然后运行:

java -jar target/mes-upper-machine-1.0.0.jar  --javafx

或者作为Web应用运行:

java -jar target/mes-upper-machine-1.0.0.jar 

JavaFx在Springboot中的依赖关系如图:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2332506.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

01分数规划

好久没发博客了……浅浅复活一下&#xff0c;讲个冷门些的算法。 算法目的&#xff1a;选出k组ai,bi使得 最大。 算法过程&#xff1a; 不妨考虑二分答案&#xff0c;那么答案的形式便是 的形式&#xff0c;则可通过移项转化为&#xff0c;进一步的&#xff0c;我们可以将…

网络安全防护技术

边界安全防护——防火墙 控制&#xff1a;在网络连接点上建立一个安全控制点&#xff0c;对进出数据进行限制隔离&#xff1a;将需要保护的网络与不可信任网络进行隔离&#xff0c;隐藏信息并进行安全防护记录&#xff1a;对进出数据进行检查&#xff0c;记录相关信息 防火墙…

课程分享 | 安全设计原则

讲师介绍 前言 在数字化时代&#xff0c;软件安全已从技术问题升级为关乎企业存亡的战略要务。从SolarWinds供应链攻击到Log4j漏洞风暴&#xff0c;一次次安全事件不断警示我们&#xff1a;传统的边界防护思维已无法应对日益复杂的威胁环境。面对不断演进的攻击手段&#xff0…

【数据结构 · 初阶】- 单链表

目录 一.相关指针知识点 二.链表 1.为什么学了顺序表还要学链表 2.优点 三.实现 1.链表的打印 —— 理解链表结构 (2) 物理结构图 2.链表的尾插 —— 入门 错误写法&#xff1a;tail ! NULL 总结&#xff1a; 正确代码物理图解&#xff1a; (2) 尾插整体代码 (思考…

在Linux系统命令行如何使用deepseek官方API调用AI大模型?

在Linux系统命令行如何调用deepseek官方API调用AI大模型&#xff1f; 书接上文&#xff1a; 同样的开头哈哈哈哈&#xff1a; ”在这个AI技术飞速发展的时代&#xff0c;每一个程序员都应该问问自己&#xff1a;如何将人工智能的强大能力融入到我们熟悉的操作系统中&#xff…

我开源了一个“宝藏”开源项目

我开源了一个“宝藏”开源项目 - AI需求分析项目 | 适合交作业和学习 &#x1f680; 前言 大家好&#xff01;最近在学习软件工程和大模型应用开发的过程中&#xff0c;我发现许多学生都遇到了需求分析AI的题目。把一份需求文档转化为用户故事、实体关系或数据库设计&#xff…

SmolDocling:一种超紧凑的视觉语言模型,用于端到端多模态文档转换

paper地址:SmolDocling: An ultra-compact vision-language model for end-to-end multi-modal document conversion Huggingface地址:SmolDocling-256M-preview 代码对应的权重文件:SmolDocling-256M-preview权重文件 一、摘要 以下是文章摘要的总结: SmolDocling 是一…

理解CSS3 的 max/min-content及fit-content等width值

本文首发在我的个人博客&#xff1a; 理解CSS3 的 max/min-content及fit-content等width值https://www.brandhuang.com/article/1744253362074 width/height 的属性值 fit-content 这是一个 CSS3 属性&#xff0c;用来设置元素的宽度和高度&#xff0c;值为 fit-content&#…

关键路径任务延误,如何快速调整

快速识别延误原因、优化资源配置、实施任务并行、调整任务优先级是关键路径任务延误后快速调整的有效方式。其中&#xff0c;快速识别延误原因尤为重要&#xff0c;需要项目管理者及时发现影响关键路径任务延误的核心问题&#xff0c;通过系统性的分析&#xff0c;确保延误的具…

Elasticsearch 全面解析

Elasticsearch 全面解析 前言一、简介核心特性应用场景 二、核心原理与架构设计1. 倒排索引&#xff08;Inverted Index&#xff09;2. 分片与副本机制&#xff08;Sharding & Replication&#xff09;3. 节点角色与集群管理 三、核心特点1. 灵活的查询语言&#xff08;Que…

linux入门四:Linux 编译器

一、C 语言编译器 GCC&#xff1a;开启编程之旅 1.1 GCC 安装&#xff1a;一站式工具链 GCC&#xff08;GNU Compiler Collection&#xff09;是 Linux 下最常用的 C/C 编译器&#xff0c;支持多种编程语言。安装命令&#xff08;适用于 Debian/Ubuntu 系统&#xff09;&…

springboot集成springcloud vault读值示例

接上三篇 Vault---机密信息管理工具安装及常用示例 Vault机密管理工具集群配置示例 vault签发根证书、中间证书、ca证书流程记录 项目里打算把所有密码都放到vault里管理&#xff0c;vault提供了springcloud vault用来在springboot里连接vault&#xff0c;启动加载vault里的值放…

edis 主从复制

Redis 主从复制是一种数据同步机制&#xff0c;主节点&#xff08;Master&#xff09;将数据复制到一个或多个从节点&#xff08;Slave&#xff09;&#xff0c;从 而实现数据备份、读写分离和高可用性。 1、解决我们的日常一个单机故障&#xff0c;而衍生出来 主从架构 2、…

机器视觉+深度学习,让电子零部件表面缺陷检测效率大幅提升

在精密加工的3C电子行业中&#xff0c;一抹0.1毫米的油渍&#xff0c;一粒肉眼难辨的灰尘或将引发整机性能隐患。当制造业迈入微米级品质竞争时代&#xff0c;产品表面看似微不足道的脏污缺陷&#xff0c;正成为制约企业高质量发展的隐形枷锁。分布无规律的污渍斑点、形态各异的…

Java基础关键_035_Lambda 表达式

目 录 一、引例&#xff1a;TreeSet 排序 1.实现 Comparable 接口 2.比较器 3.匿名内部类 4.Lambda 表达式 5.Lambda 表达式和匿名内部类的区别 二、函数式编程 三、Lambda 表达式的使用 1.无返回值函数式接口 &#xff08;1&#xff09;无返回值无参数 &#xff08;…

OPEX baota 2024.02.26

OPEX baota 2024.02.26 运维集成软件宝塔2024.02.26作废例子&#xff1a; 最重要的两个地方&#xff1a;上传文件 网站&#xff0c;重启应用服务器&#xff08;tomcat&#xff09; 其他很少用的

若依 前后端部署

后端&#xff1a;直接把代码从gitee上拉去到本地目录 (https://gitee.com/y_project/RuoYi-Vue ) 注意下redis连接时password改auth 后端启动成功 前端&#xff1a;运行前首先确保安装了node环境&#xff0c;随后执行&#xff1a; &#xff01;&#xff01;一定要用管理员权限…

LeetCode算法题(Go语言实现)_37

题目 给你一棵以 root 为根的二叉树&#xff0c;二叉树中的交错路径定义如下&#xff1a; 选择二叉树中 任意 节点和一个方向&#xff08;左或者右&#xff09;。 如果前进方向为右&#xff0c;那么移动到当前节点的的右子节点&#xff0c;否则移动到它的左子节点。 改变前进方…

使用 react-three-fiber 快速重构 Three.js 场景⚛️

不明白的知识先放在一边&#xff0c;激发兴趣是第一步&#xff0c;所以不必纠结代码的细节&#xff0c;相信我你很快就会爱上这种感觉&#xff01;&#xff01;&#xff01; 今天&#xff0c;我们将更进一步&#xff0c;将上一篇中vite npm传统 Three.js 原生代码完整 重构为 …

RT-Thread 屏蔽在线软件包的方法

说明 可能大家对 RT-Thread 的 Kconfig 配置项&#xff0c;Scons 构建有些疑惑&#xff0c;其实 BSP 的 Kconfig 可以自由的配置&#xff0c;目录也可以自由的调整 RT-Thread BSP 默认都有在线软件包的配置项&#xff0c;如果你不需要在线软件包&#xff0c;也可以把这个配置项…