SpringBoot3整合JavaFx与MyBatisPlus:桌面端开发实战指南

发布时间:2026/10/18 18:28:37

SpringBoot3整合JavaFx与MyBatisPlus:桌面端开发实战指南 简介本资源面向具备一定Java基础的开发者提供SpringBoot3整合JavaFx与MyBatisPlus的完整项目实践帮助解决桌面端应用快速搭建、界面与数据层协同开发的问题。项目以SpringBoot3为底层框架借助JavaFx构建跨平台富客户端界面并通过MyBatisPlus简化数据持久化操作适合学习企业级桌面应用架构与前后端一体化开发。压缩包共79个文件约110.76MB包含16个java源码、19个class、12个fxml界面文件、7个xml配置、2个yml配置及sql脚本、css样式、图标与演示视频等覆盖从界面布局到数据访问的完整结构。目前已有2422人学习下载。通过该资源读者可参考项目目录组织与依赖配置理解JavaFx场景启动、MyBatisPlus数据源整合及通用CRUD、分页等用法并借助演示视频与SQL脚本快速运行调试为自身项目开发提供可复用的整合思路。1. 桌面端不想写两套代码SpringBoot3 整合 JavaFx MyBatisPlus 到底能解决什么很多做后台管理系统的团队都遇到过这个场景业务逻辑、权限、数据访问全在 SpringBoot 里跑得好好的突然产品说要做个桌面客户端要求能离线查数据、能连本地数据库、还要跟服务端共用一套实体和 Mapper。这时候如果重新用 Electron 或者 WPF 写一遍等于把 Service 层和 DAO 层全部重写维护成本直接翻倍。SpringBoot3 整合 JavaFx MyBatisPlus 这套组合核心思路就是让 JavaFx 只做界面渲染和事件分发Spring 容器负责 Bean 管理、事务和数据库访问MyBatisPlus 继续干它最擅长的单表 CRUD 和条件构造。适合谁适合已经有 SpringBoot 后端代码、想低成本加一个桌面壳的团队或者做内部工具、数据采集客户端、本地报表工具的开发者。它不是让你抛弃 Web而是让同一套业务代码多一个桌面入口。2. 环境搭建与依赖选型JDK17、SpringBoot3 和 JavaFx 的版本对齐2.1 为什么 JavaFx 必须单独引依赖JDK11 之后 JavaFx 从 JDK 里剥离了所以哪怕你用的是 JDK17也得显式引入javafx-controls、javafx-fxml这些模块。SpringBoot3 要求 JDK17 起步JavaFx 这边建议用 17.0.6 以上的 LTS 版本跟 JDK 大版本对齐避免UnsupportedClassVersionError。常见做法是在pom.xml里用javafx-maven-plugin来管理这样mvn javafx:run能直接启动不用手动配 VM 参数。properties java.version17/java.version javafx.version17.0.6/javafx.version /properties dependencies !-- SpringBoot3 基础 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter/artifactId /dependency !-- MyBatisPlus 对 SpringBoot3 的适配 -- dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.5/version /dependency !-- JavaFx 控件与 FXML -- dependency groupIdorg.openjfx/groupId artifactIdjavafx-controls/artifactId version${javafx.version}/version /dependency dependency groupIdorg.openjfx/groupId artifactIdjavafx-fxml/artifactId version${javafx.version}/version /dependency /dependencies这里有个参数要盯住MyBatisPlus 3.5.5 是明确支持 SpringBoot3 的版本低于 3.5.3 的会报NoClassDefFoundError: org/springframework/boot/context/properties/ConfigurationProperties这类错。JavaFx 的classifier一般不用手动写javafx-maven-plugin会根据当前操作系统自动拉对应平台的 native 包。2.2 启动类怎么把 Spring 容器和 JavaFx 线程接起来JavaFx 的Application.launch()会阻塞主线程而 SpringBoot 的SpringApplication.run()也要占住主线程。常见做法是让 JavaFx 的Application子类持有 Spring 的ConfigurableApplicationContext在init()里启动 Spring在start()里从容器拿 Controller 或 View 对象。public class Launcher extends Application { private ConfigurableApplicationContext context; Override public void init() { // 启动 Spring 容器注册所有 Bean context SpringApplication.run(SpringBootApp.class); } Override public void start(Stage stage) throws Exception { // 从 Spring 容器获取 FXML 加载器保证 Controller 能被注入 FXMLLoader loader context.getBean(FXMLLoader.class); Parent root loader.load(getClass().getResource(/view/main.fxml)); stage.setScene(new Scene(root, 900, 600)); stage.setTitle(桌面客户端); stage.show(); } Override public void stop() { // 关闭时释放 Spring 容器避免数据库连接池悬挂 context.close(); Platform.exit(); } public static void main(String[] args) { launch(args); } }逻辑说明init()在 JavaFx 启动线程之前执行此时启动 Spring 不会跟 UI 线程抢资源。start()里用context.getBean(FXMLLoader.class)是关键因为默认的new FXMLLoader()不会走 Spring 的依赖注入Controller 里的Autowired全是 null。参数上Scene的宽高按你实际布局调stage.setTitle只是窗口标题不影响功能。3. 把 MyBatisPlus 塞进 JavaFx数据层与 UI 层的解耦写法3.1 Controller 里直接调 Service 还是走事件总线JavaFx 的 FXML Controller 本质上就是个普通 Java 对象只要它被 Spring 管理就能直接Autowired注入 Service。但这里有个坑如果你在 Controller 里直接调userService.list()数据库查询会跑在 JavaFx 的 UI 线程上数据量一大界面就卡死。常见做法是引入一个简单的线程池或者用 JavaFx 的Task把查询包起来。Controller public class UserController { Autowired private UserService userService; FXML private TableViewUser userTable; FXML public void initialize() { // 用 Task 把数据库查询放到后台线程 TaskListUser task new Task() { Override protected ListUser call() { return userService.list(); } }; // 查询成功后回填 UIsetOnSucceeded 保证在 UI 线程执行 task.setOnSucceeded(e - userTable.getItems().setAll(task.getValue())); new Thread(task).start(); } }逻辑说明Task的call()跑在后台线程setOnSucceeded的回调自动切回 JavaFx Application Thread这样既不会卡 UI也不用自己写Platform.runLater()。参数上userService.list()是 MyBatisPlus 的默认全表查询实际项目里要换成lambdaQuery().eq(...).list()并加分页。3.2 MyBatisPlus 分页插件在桌面端的配置差异Web 项目里分页插件通常配在MybatisPlusInterceptor里桌面端一样要配但有个区别桌面端没有 HTTP 请求上下文Page对象的current和size得从 UI 控件手动读。Configuration public class MybatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); // 分页插件指定数据库类型为 MySQL interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }// 在 Controller 里手动构造分页参数 PageUser page new Page(currentPage, pageSize); LambdaQueryWrapperUser wrapper new LambdaQueryWrapper(); wrapper.like(StringUtils.hasText(keyword), User::getName, keyword); PageUser result userService.page(page, wrapper); userTable.getItems().setAll(result.getRecords());参数说明DbType.MYSQL要跟你实际数据库一致换成DbType.POSTGRE_SQL或DbType.H2都行。currentPage和pageSize一般绑定到 JavaFx 的Pagination控件或两个TextField。注意PaginationInnerInterceptor必须放在其他内部拦截器之前否则分页 SQL 可能不生效。3.3 实体类与表映射的桌面端注意点MyBatisPlus 的TableName、TableId在桌面端和 Web 端没区别但桌面端经常要连本地 SQLite 或 H2这时候主键策略要改。MySQL 用IdType.AUTOSQLite 也用AUTO但 H2 在某些版本下要显式指定IdType.INPUT并手动赋值。另外桌面端如果要做离线缓存实体类里加TableField(exist false)的临时字段别太多否则selectList返回的对象会带一堆 null序列化到本地文件时体积会涨。4. 避坑排查JavaFx 与 SpringBoot3 整合时最容易翻车的五个点4.1 现象启动报 “No toolkit found” 或 “Toolkit not initialized”原因JavaFx 的 native 库没被正确加载常见于用spring-boot:run直接启动而不是javafx:run。SpringBoot 的 Maven 插件不会自动加--module-path和--add-modules。解决要么改用javafx-maven-plugin的javafx:run要么在 IDE 的 VM options 里手动加--module-path /path/to/javafx-sdk/lib --add-modules javafx.controls,javafx.fxml。我一般直接在 pom 里配好插件省得每台机器重新配。4.2 现象Controller 里的Autowired注入为 null原因FXML 文件里用fx:controller指定了 Controller 类JavaFx 默认会用反射 new 一个实例不走 Spring 容器。解决把FXMLLoader交给 Spring 管理用loader.setControllerFactory(context::getBean)或者在FXMLLoader的Bean方法里设置setControllerFactory。这样 FXML 里写的 Controller 类名会被 Spring 解析成 Bean。4.3 现象数据库连接池在窗口关闭后不释放进程残留原因JavaFx 的stop()方法里没有关闭 Spring 容器HikariCP 的线程还在跑。解决在stop()里调context.close()并且加Platform.exit()。如果用了System.exit(0)硬杀连接池可能来不及回滚事务下次启动会看到锁表。4.4 现象MyBatisPlus 的selectById返回 null但数据库里明明有数据原因桌面端连的数据库文件路径是相对路径工作目录变了之后连到了另一个空库。解决在application.yml里把url写成绝对路径或者用System.getProperty(user.dir)拼。另外SQLite 的jdbc:sqlite:./data.db在打包成 exe 后./会变成安装目录不是 jar 所在目录。4.5 现象打包成可执行 jar 后 JavaFx 报 “Missing JavaFX runtime components”原因JavaFx 的 native 库没被打进 fat jar或者Launcher类没有继承Application导致 JavaFx 启动器识别不到。解决用javafx-maven-plugin的jlink目标生成运行时镜像或者用shadow插件时把 JavaFx 的 classifier 依赖也打进去。更稳的做法是直接用jpackage打成 exe/msi把 JDK 运行时一起带上。5. 进阶技巧用 Spring 事件机制做桌面端模块解耦与数据刷新桌面端做到后面最烦的不是 CRUD而是“A 窗口改了数据B 窗口的表格怎么自动刷新”。常见做法是搞一个全局静态的ObservableList但那样模块之间耦合太紧测试也没法写。我一般会用 Spring 的ApplicationEventPublisher配合 JavaFx 的Platform.runLater让数据变更事件在 Spring 容器里广播UI 层按需订阅。先定义一个事件类携带变更的实体类型和操作类型public class DataChangeEvent extends ApplicationEvent { private final Class? entityType; private final String action; // INSERT / UPDATE / DELETE public DataChangeEvent(Object source, Class? entityType, String action) { super(source); this.entityType entityType; this.action action; } // getter 省略 }然后在 Service 层写完数据库操作后发事件Service public class UserServiceImpl extends ServiceImplUserMapper, User implements UserService { Autowired private ApplicationEventPublisher publisher; Override public boolean saveUser(User user) { boolean saved save(user); if (saved) { // 发布事件通知所有订阅者 publisher.publishEvent(new DataChangeEvent(this, User.class, INSERT)); } return saved; } }UI 层用一个 Spring Bean 来订阅收到事件后切回 JavaFx 线程刷新表格Component public class UserTableRefresher { Autowired private UserService userService; private TableViewUser tableView; public void bind(TableViewUser tableView) { this.tableView tableView; } EventListener public void onDataChange(DataChangeEvent event) { if (event.getEntityType() User.class tableView ! null) { // 切回 UI 线程更新控件 Platform.runLater(() - tableView.getItems().setAll(userService.list())); } } }这套写法的好处是Service 层完全不知道 UI 的存在只负责发事件UI 层只订阅自己关心的实体类型新增一个窗口只要加一个EventListener就行。参数上要注意Platform.runLater不能省否则setAll会在非 UI 线程抛IllegalStateException。另外事件是同步发布的如果订阅者里有耗时操作会拖慢 Service 的返回所以订阅者里只做 UI 刷新别塞数据库查询。验证方法很简单开两个窗口一个改数据另一个看表格是否自动变。如果没变先检查EventListener所在类有没有被 Spring 扫描到再检查bind方法有没有在initialize里调用。我踩过的坑是EventListener方法所在的 Bean 如果是Component但没被ComponentScan覆盖事件发了也没人接日志里连报错都没有纯玄学。从那以后我每次加事件订阅都强制在启动日志里打一行“listener registered”确认它真的进了容器。希望帮到你。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/10/18 18:28:37

Dhtmlx三组件实战:树表联动、日历约束与版本避坑指南

简介:一份面向Web前端开发者的DHTMLX组件示例合集,集中演示树形控件、数据网格、日历和分层面板等常用交互模块的用法,适合需要在项目中快速搭建后台管理界面、数据看板或日程面板的初中级开发者参考。压缩包共274个文件,包含js、…

2026/10/18 18:28:37

性能测试与代码覆盖率联动:精准定位压测盲区

做性能测试的人常被一个问题反复折腾:压测报告显示接口响应时间稳定,覆盖率报告也显示行覆盖在80%以上,可等服务一上生产,总有几个请求慢到离谱。我刚开始做性能测试的时候也这样,两个数据分开看,怎么看都正…

2026/10/18 18:23:37

YOLO火焰烟雾检测数据集标注质量治理与训练避坑指南

简介:YOLO火焰和烟雾检测数据集专为火灾预警与安全监控场景打造,适用于目标检测入门及算法优化研究。包内包含482个txt标签、481张jpg图像及481个xml标注,对应YOLO与PASCAL VOC两种常用格式,可直接用于训练、验证或格式转换。全部…

2026/10/18 20:33:52

基于MFC与OpenCV的米粒计数及最大颗粒测量实现

简介:这套VS2008环境下的OpenCVMFC工程用于统计图像中米粒的数量,并计算最大米粒的面积与周长,适合具备一定C基础、正在学习图像处理轮廓分析和几何测量的开发者。资源包共29个文件,以核心源代码(.cpp/.h)、…

2026/10/18 20:33:52

用Python从零手写最小AI Agent,揭秘工具调用与记忆原理

最近聊AI Agent的人特别多,但很多教程一上来就抛抽象概念:规划、记忆、工具调用、多Agent协作……听起来很唬人,实际动手却不知道第一行代码该写在哪。这篇文章换个路子,用Python从零手写一个能跑的最小Agent系统,不依…

2026/10/18 20:33:52

电动汽车充电负荷预测:蒙特卡洛模拟与用户响应度分析

1. 项目概述与核心需求解析做电动汽车充电负荷研究的同行,应该都绕不开一个问题:大规模电动车接入电网后,充电负荷到底怎么变?随机性太大,不好预测。某天在某技术社区看到一个项目标题,原文是“研究电动汽车…

2026/10/18 20:33:52

西南科技大学操作系统实验:可调试类Unix内核沙盒

简介:本资源是西南科技大学计算机专业《操作系统》课程配套实验材料包,面向高校本科生及操作系统初学者,聚焦进程管理、内存管理和文件系统三大核心模块的实践训练。压缩包共10个文件,含4个可执行程序(exe)…

2026/10/18 20:33:52

大模型微调三选一:全参、LoRA与QLoRA实战取舍指南

简介:面向希望掌握大模型微调实战的开发者,提供基于LLama3.1的全参微调、LoRA微调与QLoRA微调完整项目源码及流程教程。资源覆盖数据准备、环境配置、微调脚本编写、模型评估与优化等关键环节,适合具备一定Python与深度学习基础、正在开展大模…

2026/10/18 20:28:51

JPA List字段转String存储:@Convert与AttributeConverter实战

在使用 JPA 时,把一个 List 字段转成 String 存入数据库,最简单直接的方案就是 Convert 注解配合一个 AttributeConverter 实现。这个场景在业务里实在太常见了:用户标签、兴趣分组、图片地址列表、功能开关编号……这些数据说重要也重要&…

2026/10/18 0:01:50

金融AI落地指南:从调研报告到技术选型与工程实践

简介:这份PDF报告聚焦2025年金融服务业中国AI现状与趋势,面向金融科技从业者、AI战略规划人员及关注行业数字化转型的研究者,帮助读者把握生成式AI在银行、支付、交易等场景中的落地路径与投资方向。资源包内含1个PDF文件,大小约1…

2026/10/18 0:01:50

金融AI落地指南:从调研报告到技术选型与工程实践

简介:这份PDF报告聚焦2025年金融服务业中国AI现状与趋势,面向金融科技从业者、AI战略规划人员及关注行业数字化转型的研究者,帮助读者把握生成式AI在银行、支付、交易等场景中的落地路径与投资方向。资源包内含1个PDF文件,大小约1…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑