ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

基于Java与MySQL的柑橘类水果管理系统设计与实现

基于Java与MySQL的柑橘类水果管理系统设计与实现 简介本资源是一款面向农业信息化管理场景的Java企业级应用源码适用于水果种植企业、农产品流通公司及高校计算机专业课程设计与毕业项目实践。系统聚焦柑橘类水果全生命周期管理覆盖生产记录、库存监控、销售跟踪与物流追溯等核心业务助力提升农业数字化运营效率。压缩包共554个文件总大小39.79MB包含120个Java业务逻辑源文件、179个XML配置文件用于数据库连接、Spring框架及系统参数管理、2个SQL建库脚本、2个IntelliJ IDEA项目配置文件iml、1个JSON数据文件、1个Cookies会话文件及1个HTTP请求调试文件结构完整、模块清晰具备开箱即用的工程化特征。已有285人学习下载配套readme.txt提供快速部署指南doc目录下含设计文档与技术说明便于开发者理解架构、二次开发或教学演示。 做管理系统这活儿说难不难说简单也不简单。尤其是“基于Java语言的柑橘类水果管理系统”这类题目几乎是Java课设和毕设里出现频率最高的类型之一。前两天还有学弟拿这个题目来找我说自己网上找了一圈要么源码跑不起来要么代码风格乱七八糟看不懂。我干脆把自己整理过的一套完整资料重新梳理了一遍从项目结构、数据库设计到核心代码实现、环境配置再到那些一踩一个准的坑全部写出来。无论你是准备交课程设计还是想拿一个“能讲清楚、能演示、能扩展”的Java项目去面试这篇都值得收藏。这套系统本质上是典型的信息管理系统核心业务就是水果档案管理、入库、出库、库存查询和一些基础统计报表。之所以落到柑橘类水果这个具体的业务域是因为它比泛泛的“超市管理系统”更有辨识度带上了品种、产地、成熟季节、保鲜期、糖度这些农业属性字段分析和设计空间大扩展到其他农产品也顺理成章。1. 项目整体设计与技术选型1.1 为什么这种课设项目都爱用Java MySQL先说技术选型。市面上的管理系统项目主流无外乎三种路线Java Web MySQL、Java Swing 文件存储、Java Swing/JavaFX MySQL。我看过很多同学自己选型有人图省事用SQLite有人干脆把数据存在文本文档里跑是能跑但答辩的时候很容易被老师一句“如果数据量变大怎么办”问倒。我建议用 Java Swing 做界面 MySQL 做数据存储 原生 JDBC 做数据访问理由有三点。第一Swing 是Java自带的桌面GUI框架不需要引入额外的前端工程也不需要启动Tomcat。对课程设计来说一个可执行JAR或者直接IDEA里运行就能看到完整界面演示非常方便省去了部署环境的干扰。第二MySQL 是主流关系型数据库数据安全性和查询能力都比文件存储强外键、索引、事务这些数据库核心特性都能用上写文档的时候有大量可写的技术点。第三JDBC 是Java访问数据库的底层标准接口用它能真正理解连接、Statement、ResultSet、事务提交回滚这些概念之后再学MyBatis、Hibernate会快很多。很多同学一上来就想用 SSM、Spring Boot 那套不是说不行但那是另一个维度的复杂度。框架版本冲突、Maven依赖下载失败、注解扫不到包……任何一个问题都可能让你在环境阶段卡一整天。先老老实实把 JDBC 版本跑通再谈框架这是我对大部分人最真诚的建议。1.2 柑橘类水果系统的业务模块怎么拆登录模块之外我会把系统拆成五个核心模块模块职责说明典型操作水果档案模块维护柑橘类水果的品种信息比如砂糖橘、脐橙、沃柑、丑橘、蜜柚等字段包括品种名、类别、产地、参考糖度、保鲜天数、季节新增、修改、删除、按品种模糊查询供应商模块管理供货商信息记录联系人、电话、地址入库时选择对应供应商新增、修改、删除入库管理模块采购入库生成入库单和库存批次自动累加对应品种库存新增入库单、查看入库历史出库/销售模块销售出库扣减库存记录销售订单和销售明细校验库存是否充足新增销售单、查看销售历史库存与统计模块按品种统计当前库存、月度入库总量、销量Top榜、库存预警刷新统计、按时间段筛选这五个模块拆完之后功能边界就非常清晰档案和供应商是基础数据入库和出库是业务流水统计是目的。我见过有人把入库、出库、库存全写在一个类里方法几百行表面上看代码量很大但可维护性很差。模块拆开的另一个好处是写文档好写写代码好分工答辩也容易解释。1.3 代码包结构让答辩老师一眼看懂分层我知道很多人习惯把所有类都堆在同一个包下面命名也从MainFrame、Test、Utils乱取。这种代码老师一眼就能看出没有工程素养。我建议包结构按分层来组织这是Java EE和桌面应用开发里通用的思想也是一种“习惯性正确”。我整理后的源码包结构是这样的src/main/java/com/citrus/ ├── entity/ // 实体类对应数据库表 │ ├── User.java │ ├── Fruit.java │ ├── Supplier.java │ ├── StockRecord.java │ └── SaleOrder.java ├── dao/ // 数据访问对象封装JDBC操作 │ ├── UserDao.java │ ├── FruitDao.java │ ├── SupplierDao.java │ ├── StockDao.java │ └── SaleDao.java ├── service/ // 业务逻辑层处理规则校验和事务 │ ├── AuthService.java │ ├── FruitService.java │ ├── StockService.java │ └── SaleService.java ├── ui/ // Swing界面 │ ├── LoginFrame.java │ ├── MainFrame.java │ ├── FruitPanel.java │ ├── StockPanel.java │ └── StatsPanel.java └── util/ ├── DBUtil.java // 数据库连接工具 └── TableUtil.java // 表格刷新工具entity对应表结构dao只写增删改查SQLservice负责业务规则比如库存不足不能出库ui只管渲染界面和调用service。这个顺序是单向依赖ui - service - dao - entity。违反这个方向写代码后面改需求的时候就知道痛苦了。2. 数据库设计实战一张好表胜过十行代码2.1 柑橘类水果建模的特殊字段数据库设计是整个系统最核心的部分。给柑橘类水果做管理系统和给图书做管理系统的差别不在“管理”两个字而在“水果”这两个字的业务属性上。柑橘类水果有几个非常明显的行业特征。第一是品种维度多且差异大砂糖橘是宽皮柑橘脐橙是甜橙类柚子又是另一大类不同类别的存储要求不同。第二是季节性很强砂糖橘集中在冬季上市夏橙夏季成熟一个良好的管理系统应该能记录每一个品种的成熟月份和最佳销售季节。第三是保鲜期短柑橘类比不了苹果销售计划要基于保鲜周期做预警。我把这些字段都设计到了水果档案表里包括类别、产地、上市月份、参考糖度、保鲜天数、参考售价、最低库存量。这些字段看起来平平无奇但答辩时如果老师问“你这个系统的业务特点是什么”你完全可以指着表说普通的水果管理系统只记录名称和价格而这里通过保鲜天数实现了临期预警通过参考糖度辅助分级定价通过最低库存量触发补货提醒。这就是业务建模的价值。2.2 核心表结构与完整建表SQL我整理出的这套库一共六张表名字和字段我都起得比较规范全部小写加下划线没有用中文表和字段名。建表脚本如下CREATE DATABASE IF NOT EXISTS citrus_manage DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE citrus_manage; -- 用户表 CREATE TABLE sys_user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(30) NOT NULL UNIQUE, password VARCHAR(64) NOT NULL, real_name VARCHAR(30), role VARCHAR(20) DEFAULT ADMIN, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); -- 水果档案表 CREATE TABLE fruit ( id INT PRIMARY KEY AUTO_INCREMENT, variety VARCHAR(50) NOT NULL COMMENT 品种名称, category VARCHAR(20) COMMENT 类别橙类/橘类/柚类/柠檬类, origin VARCHAR(50) COMMENT 产地, season VARCHAR(30) COMMENT 上市季节如冬季, sugar_content DECIMAL(4,1) COMMENT 参考糖度如12.5, shelf_life INT COMMENT 保鲜天数, reference_price DECIMAL(10,2) COMMENT 参考售价, min_stock INT DEFAULT 50 COMMENT 最低库存预警值, remark VARCHAR(200), create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); -- 供应商表 CREATE TABLE supplier ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL, contact VARCHAR(30), phone VARCHAR(20), address VARCHAR(100), remark VARCHAR(200) ); -- 入库表 CREATE TABLE stock_in ( id INT PRIMARY KEY AUTO_INCREMENT, batch_no VARCHAR(40) NOT NULL, fruit_id INT NOT NULL, supplier_id INT, quantity INT NOT NULL, unit_price DECIMAL(10,2) DEFAULT 0, in_time DATETIME DEFAULT CURRENT_TIMESTAMP, operator VARCHAR(30), FOREIGN KEY (fruit_id) REFERENCES fruit(id), FOREIGN KEY (supplier_id) REFERENCES supplier(id) ); -- 销售表 CREATE TABLE sale_order ( id INT PRIMARY KEY AUTO_INCREMENT, order_no VARCHAR(40) NOT NULL, fruit_id INT NOT NULL, quantity INT NOT NULL, unit_price DECIMAL(10,2) DEFAULT 0, amount DECIMAL(12,2) DEFAULT 0, customer VARCHAR(50), sale_time DATETIME DEFAULT CURRENT_TIMESTAMP, operator VARCHAR(30), FOREIGN KEY (fruit_id) REFERENCES fruit(id) ); -- 库存表 CREATE TABLE inventory ( id INT PRIMARY KEY AUTO_INCREMENT, fruit_id INT NOT NULL, batch_no VARCHAR(40), quantity INT DEFAULT 0, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, UNIQUE KEY uk_fruit (fruit_id), FOREIGN KEY (fruit_id) REFERENCES fruit(id) );这里有一个需要说明的点我设计了独立 inventory 表来做库存冗余。理论上库存可以通过 stock_in 的入库量合计减去 sale_order 的销售量合计来实时计算但那种方式每次刷新页面都要聚合查询整张流水表数据一多性能就明显变差。用 inventory 表单独维护当前库存入库时加数量销售时减数量查询的时候直接查这一行速度是常量级的。这是典型的空间换时间也是很多企业级系统在用的做法。2.3 为什么用批号管理库存而不是一张流水表搞定还有人喜欢用“一张表搞定所有”字段加个类型1代表入库2代表出库然后查询的时候一个SQL把全部记录拉出来。这种台账模式在小项目里确实能跑但有几个问题第一无法区分同品种不同批次。今天进了一批砂糖橘每斤3元明天又进了一批每斤3.2元。台账模式下你想看旧批次的库存还没卖完多少做不到。第二统计口径混乱。月度报表需要入库总量、销售总量、库存结余混合表要反复GROUP BYSQL写起来绕来绕去。第三销售订单和库存批次一旦耦合出库时想追溯哪一批货卖给了谁非常麻烦。所以我坚持用“入库单/销售单两张流水表 一张库存汇总表”的结构。stock_in 每插入一条就更新 inventory 表对应 fruit_id 的 quantity 加 quantitysale_order 每插入一条就更新 quantity 减 quantity。整个过程放在一个事务里要么全部成功要么全部回滚。3. 核心功能源码解析与实操要点3.1 DBUtil别再用DriverManager重复造轮子写JDBC项目第一个要写的工具类就是数据库连接工具。如果每个Dao里都写一遍 Class.forName 和 DriverManager.getConnection代码会又臭又长而且连接参数改一处要全局搜索。我的 DBUtil 写法如下package com.citrus.util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class DBUtil { private static final String URL jdbc:mysql://localhost:3306/citrus_manage?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8; private static final String USER root; private static final String PASSWORD 123456; static { try { Class.forName(com.mysql.cj.jdbc.Driver); } catch (ClassNotFoundException e) { e.printStackTrace(); throw new ExceptionInInitializerError(MySQL驱动加载失败请检查依赖lib目录); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } public static void close(AutoCloseable... resources) { for (AutoCloseable r : resources) { if (r ! null) { try { r.close(); } catch (Exception ignored) { } } } } }重点看两个坑。一个是 URL 里的 serverTimezoneAsia/ShanghaiMySQL 8.0 以后不指定时区会报 CST 时区错误。另一个是驱动类名MySQL 5.x 用 com.mysql.jdbc.DriverMySQL 8.x 用 com.mysql.cj.jdbc.Driver搞混了就是 ClassNotFoundException。注意如果你用的是 MySQL 5.7 和 mysql-connector-java 5.xURL 和驱动类名要用老版本写法否则会报各种奇怪的 SSL 或时区问题。最好是统一用 MySQL 8.0 Connector/J 8.0少踩很多坑。3.2 登录模块密码别明文存登录模块是每个系统必须有的门面也是老师演示时第一个点击的功能。这个模块我不建议只写“select * from user where username? and password?”因为明文密码在任何正式项目里都是硬伤。教学项目里我推荐至少做一层 MD5 加盐处理。加盐的意思是密码不是直接用明文哈希而是拼上一个随机字符串再哈希防止彩虹表破解。示例代码如下public class Md5Util { public static String md5(String source) { try { MessageDigest md MessageDigest.getInstance(MD5); byte[] bytes md.digest(source.getBytes(StandardCharsets.UTF_8)); StringBuilder sb new StringBuilder(); for (byte b : bytes) { sb.append(String.format(%02x, b)); } return sb.toString(); } catch (Exception e) { throw new RuntimeException(MD5加密失败, e); } } }注册或者初始化用户时往密码里拼一个固定盐值比如 “citrus2024”然后存 md5(password salt)。登录验证时把用户输入的密码做同样处理再和数据库里的值比对。这样即使数据库泄露也无法直接逆推出原始密码。课程设计做到这一步已经能比大多数同学高一个档次。生产环境要用 BCrypt 或 PBKDF2但课设里 MD5 加盐足够你讲解清楚密码存储思路。3.3 入库与出库事务里最容易被忽略的坑入库和出库是整个系统里最容易出错的核心逻辑因为涉及两张表的数据变更。我见过很多人这么写StockInDao.add(stockIn); // 插入入库单 InventoryDao.add(inventory); // 累加库存如果第一条SQL成功、第二条SQL失败就会导致流水增加了但库存没变数据就对不上了。解决方式是在 service 层开启事务把两条操作放到同一个数据库事务里。核心代码如下public boolean stockIn(StockIn stockIn) { Connection conn null; try { conn DBUtil.getConnection(); conn.setAutoCommit(false); // 1. 插入入库单 StockInDao.add(conn, stockIn); // 2. 更新库存表如果不存在则插入 int rows InventoryDao.updateBatchAdd(conn, stockIn.getFruitId(), stockIn.getQuantity()); if (rows 0) { InventoryDao.insertFruitStock(conn, stockIn.getFruitId(), stockIn.getQuantity()); } conn.commit(); return true; } catch (Exception e) { if (conn ! null) { try { conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } } e.printStackTrace(); return false; } finally { if (conn ! null) { try { conn.setAutoCommit(true); conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }这里有个细节所有 DAO 方法都要改成接收 Connection 参数的写法而不是在 DAO 内部另外去拿连接。只有这样多条 SQL 才能复用同一个连接事务才能生效。如果你在 StockInDao.add 里再调用一次 DBUtil.getConnection()那这个事务实际上就是无效的因为两个连接不在同一个事务上下文里。这是新手最容易忽略的“事务失效”原因。出库的逻辑类似但多了一个校验动作扣减库存前必须先查询当前库存如果当前库存小于销售数量直接返回“库存不足当前库存为XX”。这个校验必须在事务里和扣减一起做防止并发情况下超卖。虽然课设系统没有并发场景但这个设计思想写进文档里很加分。3.4 库存预警与统计报表的实现思路库存预警功能实现起来不复杂但很体现产品思维。我在 Fruit 表里设计了 min_stock 字段每次刷新库存面板时执行如下查询SELECT f.variety, f.category, i.quantity, f.min_stock FROM inventory i JOIN fruit f ON i.fruit_id f.id WHERE i.quantity f.min_stock ORDER BY (f.min_stock - i.quantity) DESC;查出来的结果用醒目的红色标记在表格里并在主界面状态栏提示“当前共有N种水果需要补货”。这个功能做起来半小时都不到但演示起来视觉效果非常好老师一看就知道你考虑了业务场景。统计报表我建议做两张一张是按品种的库存汇总一张是按月份的销售Top榜。库存汇总就是 group by variety 的聚合销售Top榜用下面这条SQLSELECT f.variety, SUM(s.quantity) AS total_qty, SUM(s.amount) AS total_amount FROM sale_order s LEFT JOIN fruit f ON s.fruit_id f.id WHERE DATE_FORMAT(s.sale_time, %Y-%m) ? GROUP BY f.variety ORDER BY total_amount DESC LIMIT 10;技巧提示报表查询不要一次性把所有数据拉回Java里再for循环统计尽量把聚合逻辑交给SQL代码简单性能也更好。这也是面试里常问的“数据库聚合优于应用层聚合”的通俗体现。4. 环境搭建、运行配置与项目打包4.1 JDK安装与JAVA_HOME配置这套源码我默认用的是 JDK 8 或 JDK 11不推荐直接用 JDK 17 或更高版本除非你有把握处理各种模块化带来的兼容问题。JDK 8 在课设项目里依然是兼容性最好的选择Swing 稳定、JDBC 稳定、各种第三方库支持也最全。JDK 安装本身没什么好说的重点在环境变量。JAVA_HOME 指向 JDK 安装目录比如C:\Program Files\Java\jdk1.8.0_202Path 变量新增%JAVA_HOME%\binCLASSPATH 不需要手动配置如果你在网上看到有人让配置 CLASSPATH那是 JDK 5 时代的老黄历现在配置了反而可能干扰运行。配置完之后在命令行执行java -version和javac -version两个都有输出说明环境就绪。IDEA/Eclipse导入项目时记得在 Project Structure 里把 Project SDK 和 Project language level 都改成一致否则会出现“源发行版 XX 需要目标发行版 XX”的编译错误。4.2 MySQL建库与连接参数配置数据库安装好之后用命令行或者Navicat执行前面那一整段DDL脚本。建库时一定要用 utf8mb4不是 utf8。utf8 在MySQL里最多支持3字节遇到特殊生僻字或emoji数据会报错utf8mb4 才是完整版UTF-8。如果建库时用了默认字符集后续中文乱码问题会无休无止。连接参数里我推荐在 URL 后面固定带四个参数?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8allowPublicKeyRetrievaltrueuseSSLfalse 是因为本地开发没必要走SSL加密能省掉证书相关的警告characterEncodingutf8 确保中文编码正确serverTimezone 解决8.0版本时区报错allowPublicKeyRetrievaltrue 解决某些MySQL 8.0客户端连接时出现的公钥检索错误。JDBC连接的账号密码要和你本机一致不要照抄别人的这是运行时最容易被忽略的配置点。4.3 IDEA导入项目和打包可运行JAR导入项目时建议直接选择 Open 项目根目录然后右键项目 - Add Framework Support把 Maven 或普通工程结构认好。如果你没有用Maven最简单的方式是把 mysql-connector-java 的 jar 包放到项目根目录 lib 文件夹下然后把 lib 加入 Project Structure 的 Libraries 面板。这一步不加运行时会报 ClassNotFoundException。打包JAR文件的时候有一个大多数教程不会讲清楚的坑直接 Build Artifacts 打出来的 JAR 运行时会提示找不到数据库驱动因为 mysql-connector-java 没有被打进去。解决方式有两种一个是用 Maven 的 assembly 或者 shade 插件打 fat jar另一个是自己在 MANIFEST.MF 里配置 Class-Path 指向外部 lib 目录。我最推荐的方式是用 IDEA 的 Artifacts 配置把 lib 目录作为输出目录的一部分操作路径是File - Project Structure - Artifacts - 点加号 - JAR - From modules with dependencies在 Create JAR from Modules 弹窗里选中主类 MainFrame下方列表直接勾选 Include in project build构建完成后JAR 和 lib 会在同一个输出目录运行时不要分开保持相对路径。打包完双击能弹出登录窗口就算成功了。5. 常见问题与排查技巧实录5.1 中文乱码登录界面和数据库内容全是问号这个问题在课设里出现频率极高基本可以排第一。表面现象是三种界面按钮中文正常但数据库接出来的中文是问号反过来数据库里有中文界面显示乱码还有从控制台输出中文乱码。这三类的解决思路完全不同。数据库中文乱码先查建库语句是否指定了 utf8mb4再用SHOW CREATE TABLE fruit;查看表级字符集。如果表不是 utf8mb4执行ALTER TABLE fruit CONVERT TO CHARACTER SET utf8mb4;。JDBC URL 里也要带 characterEncodingutf8。界面乱码则多数是 Swing 默认字体不支持中文可以在启动类中设置全局字体Font font new Font(微软雅黑, Font.PLAIN, 14); EnumerationObject keys UIManager.getDefaults().keys(); while (keys.hasMoreElements()) { Object key keys.nextElement(); Object value UIManager.get(key); if (value instanceof Font) { UIManager.put(key, font); } }控制台乱码通常是IDEA控制台编码问题在 Help - Edit Custom VM Options 里加一行-Dfile.encodingUTF-8重启IDEA即可。网上说设置 IDE 文件编码和模块编码也顺手一起做设置完不要只看当前页面SQL 文件里如果有中文也必须确认是 UTF-8 编码保存。5.2 数据库连接报错驱动找不到、时区问题、连接被拒连接报错是最劝退新手的坑。我把常见情况整理成一张速查表报错信息原因分析处理方案ClassNotFoundException: com.mysql.cj.jdbc.Drivermysql-connector-java 的 jar 没有引入检查lib目录是否存在jar包IDEA中确认已加入LibrariesFailed to determine a suitable driver class驱动类名写错或版本匹配不对MySQL 8.x 用 com.mysql.cj.jdbc.DriverMySQL 5.x 用 com.mysql.jdbc.DriverThe server time zone value is unrecognizedURL 缺少 serverTimezone 参数URL追加 serverTimezoneAsia/ShanghaiAccess denied for user rootlocalhost用户名密码错误或账号无远程权限检查数据库账号密码本地连接建议直接用localhost不要用127.0.0.1以外的地址Communications link failureMySQL服务没有启动或端口不是3306启动MySQL服务或执行 netstat -anoPublic Key Retrieval is not allowedMySQL 8.0 的认证插件问题URL追加 allowPublicKeyRetrievaltrue 并设置 useSSLfalse排查这列问题的基本思路就一句话先确认 MySQL 服务进程活着再确认账号密码正确再确认驱动 jar 在 classpath 中最后确认 URL 参数完整。很多人第一反应是代码问题其实八成是MySQL服务没启动或者密码写错。5.3 编译版本不匹配和内存溢出“java: 警告: 源发行版 17 需要目标发行版 17”这个报错我在很多同学的电脑上见过。本质是项目语言级别和JDK版本不一致。IDEA里打开 File - Project Structure - Modules把 Language level 和 SDK 改成一致然后在 Settings - Build Tools - Compiler - Java Compiler把 target bytecode version 也改成对应版本三处全部对齐问题就解决。OutOfMemoryError 在课设项目里一般出现在大量数据导出或报表查询时。比如你一次性把几万条销售记录加载到内存里做统计或者往Excel导出时把全部数据堆在List里就很容易触发。稳妥做法有三种查询时分页或者限制条数比如 LIMIT 1000统计尽量交给SQL完成如果确实需要处理大数据在VM options里调大内存-Xms128m -Xmx512m。我建议优先优化代码调大内存只是应急方案而且面试时你不愿意说自己靠加内存解决OOM吧。5.4 资源泄漏与SQL注入隐患面试官或者答辩老师经常会问一个问题你的 JDBC 代码里 Connection、Statement、ResultSet 有没有正确关闭很多同学的代码在 try 块里执行SQL在 finally 里只关了 ConnectionStatement 和 ResultSet 一直敞着短时间没问题长时间运行就会把数据库连接池或者MySQL的最大连接数耗尽。我建议封装一个关闭工具方法用可变参数统一处理DBUtil.close(rs, stmt, conn);放在 finally 块里调用不管前面的代码报不报错资源都会释放。这就是前面 DBUtil 代码里那个 close 方法的用途。关于 SQL 注入不管任何地方拼接SQL只要用户输入可能进SQL语句一律用 PreparedStatement 的 ? 占位符不要用字符串拼接。这个习惯比任何安全框架都重要。水果名称查询功能最容易被拿来拼接写成下面这样就非常危险String sql SELECT * FROM fruit WHERE variety LIKE % keyword %;用户输入一个 OR 11就能把整张表查出来。要改成String sql SELECT * FROM fruit WHERE variety LIKE ?; preparedStatement.setString(1, % keyword %);这个问题在答辩时被问到的概率很高因为它是Java Web安全面试的高频考题。写进去你就能在答不上其他技术问题的时候靠着这个细节扳回一城。6. 源码扩展思路从课设项目到简历亮点如果你只想交作业上面内容已经够用。但如果你希望这个项目在简历上或考研复试里能拿得出手我再给几个明确的优化方向这些都是基于现有源码的增量改造。第一加一个简单的图形化库存趋势图。Swing 自带的 JFreeChart 库可以生成柱状图和折线图用销售流水按周聚合的数据展示销量趋势整个系统的观感会立刻上一个档次。JFreeChart 的使用方式网上资料很多核心就三步创建数据集、创建图表、放入面板。第二把配置文件从Java代码里抽离。目前 DBUtil 里账号密码写死在常量里你可以改成读取 db.properties 文件的模式用一个静态代码块加载配置文件。这个改动很小但能体现“配置与代码分离”的思想答辩老师会认为你懂工程实践。第三如果进阶方向是 Java Web就把Swing界面替换成 Servlet JSP 或者 Spring Boot Vue 的版本。底层 DAO、Service 那套代码几乎可以复用只需要把 UI 层换掉再加一层 Controller。这样下来你等于拥有了同一个业务逻辑的两个端简历上写“完成桌面端与Web端双端系统开发”素材就更足了。第四做一下简单的低库存短信或邮件提醒。可以用JavaMail发提醒邮件或者用第三方的短信接口不需要真的发把接口打好模拟触发即可。这种“主动提醒”功能在小项目里非常亮眼属于典型的增值功能。我个人帮学弟学妹看课设源码这几年最深的感受是很多项目跑不起来不是代码多难而是环境配置和版本匹配的问题占了八成跑起来之后真正拉开差距的往往是数据库表设计和事务处理这些小细节。你把这个项目从头到尾亲手敲一遍把每张表、每个事务、每个资源的开关都搞清楚收获远比网上下载一份能运行的源码大得多。照着上面的思路和代码搭建起来之后把品种数据换成你自己熟悉的柑橘类再去调整一下查询条件很快就能变成属于你自己的完整项目。本文还有配套的精品资源点击获取
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表