JavaFx+SpringBoot农村人口管理系统实战
简介这是一套面向Java初学者与高校课程设计者的农村人口管理实战项目源码聚焦基层治理数字化场景解决农村户主、人口、员工及贫困信息等多维度数据的本地化高效管理问题。资源包含244个文件以51个Java业务类、28个FXML界面文件、90个XML配置/映射文件为主辅以SQL建表脚本、YML配置及少量图片资源整体压缩包仅980KB轻量易部署适合教学演示与二次开发。已有147人学习下载体现了其在实训项目中的实用热度。用户可直接运行完整可执行系统获得管理员与普通用户双角色权限体系、CRUD全功能模块含条件过滤查询、MyBatisPlus自动填充与逻辑删除实践、JavaFX桌面端UI与SpringBoot后端解耦集成范例以及清晰分层的Maven工程结构是理解Java全栈桌面应用开发的优质入门案例。1. 这不是又一个SpringBoot CRUD demo它用JavaFx做桌面端把MybatisPlus的CRUD能力真正“钉”进农村人口管理场景你见过几个真正跑在Windows台式机上的SpringBoot项目不是部署在Linux服务器上供浏览器访问而是双击rural-population-system.jar就弹出完整GUI界面户籍员在村委会电脑上点几下就能完成一户五口人的信息录入、贫困类型标注、务工地点更新——这个系统就是干这个的。它没用Vue或React前端是JavaFx后端是SpringBootMybatisPlus数据库是MySQL整个项目用Maven统一管理依赖和构建流程。关键在于它不是教学Demo所有Controller类如EmployeeController.class、UpdatePersonController.class都对应真实业务动作所有Service实现如AccountPersonServiceImpl.class都封装了带逻辑删除、自动填充时间戳、分页查询的完整数据操作链连PIndexController.class这种命名都暗示着“人口首页”的业务语义。适合两类人一是刚学完SpringBoot但卡在“怎么让页面动起来”的开发者能直接拆源码看JavaFx如何调用SpringBoot REST接口二是需要快速落地农村治理数字化工具的基层技术支撑人员它不依赖云服务、不强制联网、本地MySQL即可运行部署成本接近于零。2. JavaFx桌面端与SpringBoot后端的通信机制REST调用不是简单发HTTP请求而是要解决跨域、序列化、错误码映射三重关卡2.1 JavaFx客户端如何发起结构化REST请求从FXML控件绑定到HttpURLConnection封装JavaFx界面通过FXML注解绑定按钮、表格、输入框等组件但真正与后端交互的代码不在FXML里而在对应的Controller类中如RegisterController.class。以新增户主为例点击“保存”按钮触发的方法内部会构造一个标准的HTTP POST请求// RegisterController.java 片段 private void handleSaveHousehold() { String url http://localhost:8080/api/household; try { HttpURLConnection conn (HttpURLConnection) new URL(url).openConnection(); conn.setRequestMethod(POST); conn.setRequestProperty(Content-Type, application/json; charsetUTF-8); conn.setDoOutput(true); // 构造JSON请求体注意字段名必须与后端RequestBody接收对象一致 String jsonPayload String.format( {\name\:\%s\,\gender\:\%s\,\idCard\:\%s\,\address\:\%s\}, nameField.getText().trim(), genderComboBox.getValue(), idCardField.getText().trim(), addressArea.getText().trim() ); try (OutputStream os conn.getOutputStream()) { os.write(jsonPayload.getBytes(StandardCharsets.UTF_8)); } int responseCode conn.getResponseCode(); if (responseCode HttpURLConnection.HTTP_CREATED) { // 成功解析响应体中的新ID并刷新表格 String response readResponse(conn.getInputStream()); JSONObject obj new JSONObject(response); refreshHouseholdTable(); // 刷新JavaFx TableView } else { // 失败读取错误信息并弹窗提示 String error readResponse(conn.getErrorStream()); showAlert(保存失败, error); } } catch (Exception e) { showAlert(网络异常, 请检查后端服务是否运行); } }提示这段代码没有用OkHttp或Apache HttpClient而是原生HttpURLConnection原因很实际——JavaFx项目打包成单jar时避免引入额外依赖导致体积膨胀或类冲突。readResponse()方法需自行实现核心是用BufferedReader逐行读取流并拼接字符串否则中文会乱码。2.2 SpringBoot后端REST接口设计MybatisPlus的条件构造器QueryWrapper如何支撑动态过滤查询前端传来的查询参数如户主名、性别不是拼SQL而是由SpringBoot Controller接收后交由MybatisPlus的QueryWrapper动态构建WHERE条件。以IndexController.class中的户主列表查询为例// IndexController.java GetMapping(/api/household/list) public ResultListHousehold listHouseholds( RequestParam(required false) String name, RequestParam(required false) String gender) { QueryWrapperHousehold wrapper new QueryWrapper(); // 动态添加条件只有参数非空才加入WHERE子句 if (StringUtils.isNotBlank(name)) { wrapper.like(name, name); // 对应数据库字段name使用LIKE模糊匹配 } if (StringUtils.isNotBlank(gender)) { wrapper.eq(gender, gender); // 精确匹配gender字段 } // MybatisPlus自动处理分页Page对象包含当前页、每页条数、总记录数 PageHousehold page new Page(1, 20); // 默认第1页每页20条 PageHousehold resultPage householdService.page(page, wrapper); return Result.success(resultPage.getRecords()); // 返回分页数据列表 }注意Result是自定义的统一响应包装类包含code、msg、data三个字段前端JavaFx必须按此结构解析JSON。householdService是继承ServiceImplHouseholdMapper, Household的Service实现类其page()方法底层调用MybatisPlus的分页插件需在SpringBoot配置中启用。2.3 关键配置项application.yml中MybatisPlus分页插件与MySQL驱动版本的强耦合关系MybatisPlus的分页功能不是开箱即用必须显式配置分页插件且MySQL驱动版本必须匹配。若使用MySQL 8.xpom.xml中mysql-connector-java版本必须为8.0.33及以上否则分页查询会抛出SQLException: Unknown system variable tx_isolation。对应application.yml配置如下spring: datasource: url: jdbc:mysql://localhost:3306/rural_db?useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver # MySQL 8 必须用cj包 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 开启SQL日志调试必备 global-config: db-config: id-type: auto # 主键自增 logic-delete-field: deleted # 逻辑删除字段名 logic-delete-value: 1 # 已删除值 logic-not-delete-value: 0 # 未删除值 # 分页插件配置MybatisPlus 3.4.0 写法 pagination: enabled: true default-page-size: 20 max-page-size: 500提示max-page-size: 500是硬性限制防止前端恶意传入size10000导致数据库OOM。若业务真需单页500条以上必须改用游标分页Cursor Pagination而非Page对象。3. MybatisPlus在农村人口场景下的深度定制逻辑删除、自动填充、枚举类型处理如何规避“删库跑路”风险3.1 逻辑删除字段deleted的全链路生效从数据库建表到Service层拦截农村人口数据敏感任何“删除”操作都必须留痕。系统采用MybatisPlus逻辑删除数据库表中增加deleted tinyint(1) DEFAULT 0字段0表示未删除1表示已删除。但仅加字段不够需三处同步配置实体类标注Household.java中添加TableLogic注解TableLogic private Integer deleted;全局配置见2.3节application.yml指定逻辑删除字段名及值Mapper接口无需修改HouseholdMapper extends BaseMapperHouseholdMybatisPlus自动在所有SELECT/UPDATE/DELETE语句中追加AND deleted 0条件验证方式执行householdService.removeById(123)后数据库该记录deleted值变为1而非物理删除。后续listHouseholds()查询将自动过滤掉deleted1的记录。3.2 自动填充创建/更新时间TableField(fill FieldFill.INSERT)如何避免手动set时间戳农村系统要求所有数据变更可追溯created_time和updated_time字段必须由框架自动维护。MybatisPlus通过MetaObjectHandler实现Component public class MyMetaObjectHandler implements MetaObjectHandler { Override public void insertFill(MetaObject metaObject) { this.strictInsertFill(metaObject, createdTime, LocalDateTime.class, LocalDateTime.now()); // 起始版本号 3.3.0 this.strictInsertFill(metaObject, updatedTime, LocalDateTime.class, LocalDateTime.now()); } Override public void updateFill(MetaObject metaObject) { this.strictUpdateFill(metaObject, updatedTime, LocalDateTime.class, LocalDateTime.now()); } }注意实体类字段名必须与数据库列名一致如created_time对应createdTime且TableField需显式声明fill属性TableField(fill FieldFill.INSERT)TableField(fill FieldFill.UPDATE)否则MetaObjectHandler不会触发。3.3 枚举类型安全映射贫困种类PovertyType如何避免数据库存1/2/3导致的语义丢失系统中“贫困种类”是固定选项如“因病致贫”、“因学致贫”、“缺技术”若数据库用INT存1/2/3后期维护极易出错。MybatisPlus支持枚举类型处理器将Java枚举与数据库字符串/数字双向映射// PovertyType.java public enum PovertyType { ILLNESS(因病致贫), EDUCATION(因学致贫), SKILL_SHORTAGE(缺技术); private final String desc; PovertyType(String desc) { this.desc desc; } public String getDesc() { return desc; } } // 在实体类中使用 TableField(value poverty_type) private PovertyType povertyType; // 数据库存字符串ILLNESS非数字 // 配置枚举处理器application.yml mybatis-plus: type-enums-package: com.rural.enums # 扫描枚举包路径 configuration: default-enum-type-handler: org.apache.ibatis.type.EnumStringTypeHandler提示EnumStringTypeHandler将枚举名ILLNESS存入数据库前端展示时调用povertyType.getDesc()获取中文。若需存中文描述改用EnumOrdinalTypeHandler存序号或自定义TypeHandler。4. Maven多模块结构与阿里云镜像配置解决“下载依赖超时”和“依赖冲突”的实战方案4.1 项目模块划分逻辑为什么rural-population-system被拆成rural-api、rural-service、rural-javafx三个子模块源码包虽未明说模块结构但从EmployeeController.class等类名可反推典型分层。一个健壮的Maven多模块项目应如此组织模块名职责关键依赖rural-api定义DTO、VO、统一Result、Swagger文档spring-boot-starter-web,springfox-swagger2rural-service实现Service、Mapper、MybatisPlus配置mybatis-plus-boot-starter,mysql-connector-javarural-javafxJavaFx GUI、资源文件、启动类javafx-controls,javafx-fxml父pom.xml中声明模块modules modulerural-api/module modulerural-service/module modulerural-javafx/module /modules提示rural-javafx模块的pom.xml必须显式添加packagingjar/packaging并配置maven-jar-plugin否则mvn package无法生成可执行jar。JavaFx 11已从JDK移除需单独引入org.openjfx:javafx-controls等依赖。4.2 阿里云Maven镜像配置settings.xml中mirrorOf必须设为*才能覆盖中央仓库国内开发者最常遇到mvn clean install卡在Downloading: https://repo.maven.apache.org/maven2/...根源是未配置国内镜像。正确做法是在~/.m2/settings.xml中配置mirrors mirror idaliyunmaven/id mirrorOf*/mirrorOf !-- 关键必须是*不是central -- name阿里云公共仓库/name urlhttps://maven.aliyun.com/repository/public/url /mirror /mirrors注意mirrorOf*/mirrorOf表示该镜像代理所有仓库请求。若写成mirrorOfcentral/mirrorOf部分第三方依赖如com.baomidou:mybatis-plus-boot-starter可能仍走中央仓库而超时。4.3 依赖冲突排查三板斧mvn dependency:tree -Dverbose、排除传递依赖、锁定版本当出现NoSuchMethodError如LambdaQueryWrapper找不到eq方法大概率是MybatisPlus版本冲突。执行以下命令定位# 查看全量依赖树-Dverbose显示冲突详情 mvn dependency:tree -Dverbose | grep mybatis-plus # 输出示例 # [INFO] - com.baomidou:mybatis-plus-boot-starter:jar:3.5.3.1:compile # [INFO] | \- com.baomidou:mybatis-plus-core:jar:3.5.3.1:compile # [INFO] \- com.baomidou:mybatis-plus-extension:jar:3.4.3.4:compile -- 冲突解决方案在pom.xml中强制排除旧版本dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-extension/artifactId version3.5.3.1/version exclusions exclusion groupIdcom.baomidou/groupId artifactIdmybatis-plus-core/artifactId /exclusion /exclusions /dependency5. JavaFx界面与SpringBoot服务的本地化集成技巧如何让rural-javafx.jar一键启动后端并连接本地MySQL5.1 后端服务嵌入式启动SpringApplication.run()在JavaFx主线程中调用的时机控制JavaFx应用不能直接在launch()后立即启动SpringBoot因为JavaFx线程与SpringBoot的Servlet容器线程需隔离。正确做法是在JavaFx主窗口加载完成后新开线程启动SpringBoot// RuralApp.java public class RuralApp extends Application { private ConfigurableApplicationContext springContext; Override public void start(Stage primaryStage) throws Exception { FXMLLoader loader new FXMLLoader(getClass().getResource(/fxml/main.fxml)); Parent root loader.load(); // 启动SpringBoot服务后台线程 Thread springThread new Thread(() - { springContext SpringApplication.run(RuralApplication.class); }); springThread.setDaemon(true); // 设为守护线程避免阻塞JavaFx退出 springThread.start(); // 等待SpringBoot端口就绪最多等待10秒 waitForSpringBootReady(); Scene scene new Scene(root); primaryStage.setScene(scene); primaryStage.show(); } private void waitForSpringBootReady() { int timeout 0; while (timeout 100 !isSpringBootRunning()) { try { Thread.sleep(100); timeout; } catch (InterruptedException e) { break; } } } private boolean isSpringBootRunning() { try { HttpURLConnection conn (HttpURLConnection) new URL(http://localhost:8080/actuator/health).openConnection(); return conn.getResponseCode() 200; } catch (Exception e) { return false; } } }提示/actuator/health是SpringBoot Actuator的健康检查端点需在pom.xml中添加spring-boot-starter-actuator依赖并在application.yml中暴露端点management: endpoints: web: exposure: include: health5.2 MySQL本地免配置启动用H2数据库替代MySQL进行快速验证若测试环境无MySQL可临时切换为H2内存数据库避免安装配置。在application-dev.yml中# 开发环境专用配置 spring: profiles: active: dev datasource: url: jdbc:h2:mem:rural_db;DB_CLOSE_DELAY-1;DB_CLOSE_ON_EXITFALSE username: sa password: driver-class-name: org.h2.Driver h2: console: enabled: true path: /h2-console # 访问 http://localhost:8080/h2-console # MybatisPlus配置保持不变H2完全兼容 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl注意H2是内存数据库重启后数据丢失仅用于开发验证。正式部署必须切回MySQL并确保rural_db数据库已创建SQL脚本在源码包database/目录下。5.3 打包发布终极命令mvn clean package -DskipTests与jpackage生成Windows安装包最终交付给村委会的不是一堆jar包而是一个双击即用的.exe。JDK 14提供jpackage工具# 先打包JavaFx模块 cd rural-javafx mvn clean package -DskipTests # 生成Windows安装包需JDK 14 jpackage --input target/ \ --name 农村人口管理系统 \ --main-jar rural-javafx-1.0.jar \ --main-class com.rural.javafx.RuralApp \ --type exe \ --win-menu \ --win-shortcut \ --vendor 农村信息化项目组生成的农村人口管理系统.exe会自动捆绑JRE用户无需安装Java环境。安装包内含rural-javafx.jar、rural-service.jar、rural-api.jar及application.yml启动时自动拉起嵌入式Tomcat和H2/MySQL连接。本文还有配套的精品资源点击获取