Java课程设计实战:超市管理系统源码架构、JDBC与SQL Server数据库改造指南

发布时间:2026/10/5 6:20:01
Java课程设计实战:超市管理系统源码架构、JDBC与SQL Server数据库改造指南 简介针对Java初学者打造的超市管理系统源码包完整覆盖超市日常管理六大核心模块基本档案管理供货商、销售商、货品档案、仓库、采购订货管理、仓库入库、仓库出库、人员管理、部门管理各模块均实现添加、删除、修改等完整功能。项目基于选择结构、循环结构、数组等Java基础知识构建并配套SQL Server数据库相关文件适合作为课程设计或入门练手项目。压缩包共340个文件以78个java源文件与190个class编译文件为主同时包含58张png界面截图、sql数据库脚本、mdf/ldf数据文件、jar依赖及doc说明文档整体仅2.43MB文件构成清晰便于按模块查阅。已有4290人学习下载。该版本历经8个月学习与6稿改进业务逻辑完整从界面窗体、控制面板到数据访问对象均能一一对应。读者可结合源码与截图对照学习各管理面板的实际效果理解Java与SQL Server整合开发的典型思路是一份贴近实战的学习参考资料。1. 拿到源码先看包结构这个超市管理系统写到了哪一步解压这份超市管理系统源码包里面全是 RemoveButtomFrame.class、PersonnelDao.class 这类编译后的字节码文件。对照说明文档才知道这是学员练了8个月Java、在导师指点下改了6稿才定型的实战项目。系统不大但功能面铺得完整基本档案、采购订货、仓库入库、仓库出库、人员管理、部门管理全都有每个模块都带增删改查。对刚学完Java基础的人它把“类怎么分、界面怎么搭、SQL Server怎么连”串成了一条可模仿的线对做课程设计的人来说模块划分可以直接抄。使用方式不同打开姿势差别很大要参考看类名和DAO层就能看出七成逻辑要改功能得先反编译class再动手。2. 从.class文件名反推架构DAO层和窗体层是怎么协同的2.1 类名就是地图一份职责表与javap验证解压后第一件事不是找代码而是把全部类名列出来。文件不多但命名规整我按职责做了一份推测表类名文件类型职责判断PersonnelDao数据访问类人员表的增删改查JoinDepotDao数据访问类入库单表的增删改查OutDepotDao数据访问类出库单表的增删改查FeelDao数据访问类供货商/销售商档案表的数据库操作PersonnelPanel面板类人员管理界面的展示与录入区域InsertPersonnelFrame窗体类新增人员时弹出的录入窗口UpdatePersonnelFrame窗体类修改人员时弹出的录入窗口UpdateJoinDepotFrame窗体类修改入库单的窗口UpdateOutDepotFrame窗体类修改出库单的窗口RemoveButtomFrame窗体类底部按钮导航相关窗体这里有个很典型的分层思维DAO类只负责数据库读写Panel负责界面布局Frame负责弹窗交互。数据访问和界面展示分开是 Java 课程练手项目里最常见的分层方式。虽然它没有严格的Service层但至少做到了DAO和UI解耦这对刚学完 Java 基础的人已经是一个合格的结构。要验证这些判断不一定要先反编译成源码。JDK 自带的 javap 工具可以直接查看 class 文件的方法签名比如javap -p -classpath . PersonnelDao.class-p参数会显示私有成员-classpath指定当前目录。执行后能看到类里面有没有 Connection 字段、有没有 insertPersonnel 这类业务方法基本上就能确认这个类到底干了什么事。我一般会先对所有 DAO 类执行一遍 javap把方法名汇总起来再对照业务说明去理解系统全貌。提示如果你拿到的是 class 文件而不是 java 文件javap 是最快的信息提取方式它不需要额外安装任何反编译工具。2.2 六大模块的业务闭环采购、入库、出库的数据流从类名能看出结构但要把业务串起来得按超市实际操作流程走一遍。基本档案管理是地基包括供货商管理、销售商管理、货品档案管理、仓库管理四块然后是采购订货相当于采购员向供货商下单单子关联货品编号、数量、进价采购单确认后做仓库入库入库单让库存数量增加销售出货时走仓库出库库存数量减少人员管理和部门管理是后台基础配置负责操作员和部门归属。所以数据流是这样一个闭环供货商档案 - 采购订货 - 仓库入库 - 库存增加 销售商档案 - 销售出库 - 仓库出库 - 库存减少 人员/部门 - 记录操作人及所属部门在代码层面JoinDepotDao 和 OutDepotDao 分别处理入库单和出库单的写库操作入库单、出库单里都少不了货品编号、仓库编号、数量、单价、操作人、日期这几个字段。这个环节最容易出错的地方是“入库加库存、出库减库存”这两个动作没有放在同一个事务里。如果库存更新失败单子却已经插入成功对账就会对不上。这份资源是练手项目事务边界做得不算严密所以我在第 3 章建表时会特意把库存字段落到业务表里方便你读代码时对照跟踪。2.3 典型JDBC写法连接生命周期和它的代价看这种课程练手项目的 DAO 层基本能猜出作者的写法套路。先用Class.forName加载驱动再用DriverManager.getConnection拿连接每条 SQL 先拼字符串再执行最后在 finally 里关闭资源。我看过大量类似项目基本上是一个模板复制出来的。下面这段代码就是这个套路的标准形态public int insertPersonnel(Personnel p) { Connection conn null; PreparedStatement ps null; int result 0; try { Class.forName(com.microsoft.sqlserver.jdbc.SQLServerDriver); conn DriverManager.getConnection( jdbc:sqlserver://localhost:1433;DatabaseNameSupermarketDB, sa, 123456); String sql INSERT INTO person_info (person_name, dept_id, login_name) VALUES (?, ?, ?); ps conn.prepareStatement(sql); ps.setString(1, p.getPersonName()); ps.setInt(2, p.getDeptId()); ps.setString(3, p.getLoginName()); result ps.executeUpdate(); } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); } finally { try { if (ps ! null) ps.close(); } catch (SQLException ignored) {} try { if (conn ! null) conn.close(); } catch (SQLException ignored) {} } return result; }这段代码其实暴露了三层信息。第一Class.forName的作用是加载 SQL Server 的 JDBC 驱动类驱动版本不匹配时就在这里抛ClassNotFoundException。第二DriverManager.getConnection的三个参数里URL 写成jdbc:sqlserver://localhost:1433;DatabaseNameSupermarketDB实际部署时机器名、端口和数据库名都要按你的环境改。第三PreparedStatement 配合占位符比 Statement 拼字符串安全得多但注意它每次执行都要新建连接这是典型的“能用但不好维护”的写法。这个连接生命周期有个隐藏代价每个 DAO 方法调用时都要经历“加载驱动、建立 TCP 连接、鉴权、执行 SQL、关闭连接”这一整套流程。桌面上几次点击还好数据量稍微大一点SQL Server 的user connections计数器就会飙得很高。这个问题留到第 5 章进阶改造时解决。3. SQL Server 数据库落地建库、建表、连接串配置3.1 建库建表六张表覆盖六个模块这份资源标注“含 sql server 数据库”建表部分值得认真看。按六大功能模块至少需要货品档案表、供货商表、销售商表、仓库表、采购订货表、采购明细表、入库单表、出库单表、人员表、部门表。为了不让表结构散落各章我按最常规的字段设计拆成了一份可执行的 SQLCREATE DATABASE SupermarketDB; GO USE SupermarketDB; GO CREATE TABLE goods_info ( goods_id INT IDENTITY(1,1) PRIMARY KEY, -- 货品编号自增主键 goods_name NVARCHAR(50) NOT NULL, -- 货品名称 spec NVARCHAR(30) NULL, -- 规格型号 unit NVARCHAR(10) NULL, -- 计量单位 stock_qty INT DEFAULT 0, -- 当前库存数量 warn_qty INT DEFAULT 10, -- 库存预警阈值 supplier_id INT NULL, -- 供货商编号 in_price DECIMAL(10,2) NULL, -- 进价 out_price DECIMAL(10,2) NULL -- 售价 ); CREATE TABLE supplier_info ( supplier_id INT IDENTITY(1,1) PRIMARY KEY, supplier_name NVARCHAR(50) NOT NULL, contact_name NVARCHAR(20) NULL, phone VARCHAR(20) NULL, address NVARCHAR(100) NULL ); CREATE TABLE seller_info ( seller_id INT IDENTITY(1,1) PRIMARY KEY, seller_name NVARCHAR(50) NOT NULL, contact NVARCHAR(20) NULL, phone VARCHAR(20) NULL ); CREATE TABLE warehouse_info ( warehouse_id INT IDENTITY(1,1) PRIMARY KEY, warehouse_name NVARCHAR(50) NOT NULL, address NVARCHAR(100) NULL ); CREATE TABLE join_depot ( join_id INT IDENTITY(1,1) PRIMARY KEY, goods_id INT NOT NULL, -- 关联 goods_info warehouse_id INT NOT NULL, -- 关联 warehouse_info join_qty INT NOT NULL, -- 入库数量 unit_price DECIMAL(10,2) NULL, -- 入库单价 join_date DATETIME DEFAULT GETDATE(), -- 入库时间 operator VARCHAR(20) NULL, -- 操作人 remark NVARCHAR(200) NULL ); CREATE TABLE out_depot ( out_id INT IDENTITY(1,1) PRIMARY KEY, goods_id INT NOT NULL, warehouse_id INT NOT NULL, out_qty INT NOT NULL, unit_price DECIMAL(10,2) NULL, out_date DATETIME DEFAULT GETDATE(), operator VARCHAR(20) NULL, remark NVARCHAR(200) NULL ); CREATE TABLE dept_info ( dept_id INT IDENTITY(1,1) PRIMARY KEY, dept_name NVARCHAR(50) NOT NULL ); CREATE TABLE person_info ( person_id INT IDENTITY(1,1) PRIMARY KEY, person_name NVARCHAR(30) NOT NULL, dept_id INT NULL, -- 关联 dept_info login_name VARCHAR(20) NULL, login_pwd VARCHAR(50) NULL, role_name NVARCHAR(20) NULL );这份建表脚本有四个设计要点。第一goods_id用 IDENTITY 自增插入时不需手工指定主键第二join_depot和out_depot里的goods_id、warehouse_id分别关联货品档案和仓库表这是后续写 JoinDepotDao、OutDepotDao 时最重要的两个外键第三库存字段stock_qty默认值是 0入库加库存、出库减库存的逻辑分别对应两张业务表第四凡是存放中文的列统一用NVARCHAR不用VARCHAR(50)因为 VARCHAR 在 SQL Server 简体中文实例下对某些字符集处理容易产生乱码。人员表和部门表是权限控制的基础。dept_id 关联 dept_infologin_name 和 login_pwd 为将来做登录功能留了扩展位。很多课程设计的表结构是“一表打天下”所有字段塞进一张大表这个项目虽然没拆到非常细但按业务域建表的习惯到工作里也适用。3.2 JDBC连接串驱动、端口、实例名这些参数的含义SQL Server 的 JDBC URL 和 MySQL 差别很大新手常在这里翻车。SQL Server 的连接串标准格式是jdbc:sqlserver://主机名:端口;DatabaseName数据库名;encryptfalse;trustServerCertificatetrue各参数含义如下参数示例值说明hostlocalhost数据库所在主机远程部署写 IP 或机器名port1433SQL Server 默认实例端口DatabaseNameSupermarketDB要连接的数据库名encryptfalse高版本驱动默认加密老项目要显式关掉trustServerCertificatetrue和 encryptfalse 配合跳过证书校验connectTimeout3000建议加上连接失败时快速报错而不是卡住从微软 JDBC 驱动 12.x 开始默认encrypttrue很多老代码在连接时报“The driver could not establish a secure connection”。解决办法就是在 URL 里显式加上encryptfalse;trustServerCertificatetrue。课程项目基本都跑在局域网里不需要走 TLS关掉加密是最省事的方案。还要注意命名实例的问题。如果 SQL Server 安装时用的是 SQLEXPRESS 这类命名实例连接串要加反斜杠实例名jdbc:sqlserver://localhost\\SQLEXPRESS:1433;DatabaseNameSupermarketDB端口 1433 是默认实例的监听端口命名实例的监听端口可能是动态分配的需要用 SQL Server Browser 服务解析。这条规则是第 4 章第 2 个坑的核心原因。3.3 数据库工具类连接管理集中到一处不管反编译出来的源码用了什么连接管理方式我建议你把连接参数统一收敛到一个工具类里。这样改库名、改密码只动一处不用全局替换。下面这段是能直接跑通的断点调试版本import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; public class DbUtil { private static final String DRIVER com.microsoft.sqlserver.jdbc.SQLServerDriver; private static final String URL jdbc:sqlserver://localhost:1433;DatabaseNameSupermarketDB;encryptfalse;trustServerCertificatetrue; private static final String USER sa; private static final String PASSWORD 123456; static { try { Class.forName(DRIVER); } catch (ClassNotFoundException e) { throw new ExceptionInInitializerError(e); } } public static Connection getConnection() throws Exception { return DriverManager.getConnection(URL, USER, PASSWORD); } public static void close(Connection conn, Statement st, ResultSet rs) { try { if (rs ! null) rs.close(); } catch (Exception ignored) {} try { if (st ! null) st.close(); } catch (Exception ignored) {} try { if (conn ! null) conn.close(); } catch (Exception ignored) {} } }这个工具类的关键点有三处static 代码块在类加载时执行一次驱动注册避免每次 getConnection 都重复加载getConnection 统一从三个常量取参数close 方法把三个资源的关闭逻辑收敛在一起。我在实际调试时还会加一个 main 方法做连接自检public static void main(String[] args) { try (Connection conn DbUtil.getConnection()) { System.out.println(连接成功 conn.getCatalog()); } catch (Exception e) { e.printStackTrace(); } }这样连不连得上、驱动是否存在一分钟就能验证完不用把整个系统跑起来之后再慢慢排查。4. 避坑指南编译版本、端口、乱码、反编译四道坎这套系统在很多机器上都能直接跑起来但我指导别人实操过程中反复出现几类问题。按出现的频次从高到低排列每条都按“现象、原因、解决”来写基本都是可以直接照做的。4.1 ClassNotFoundException驱动没进Build Path或版本不对现象程序启动后控制台报java.lang.ClassNotFoundException: com.microsoft.sqlserver.jdbc.SQLServerDriver界面根本调不到数据库。原因项目里没有引入合适的 JDBC 驱动 jar 包。常见两种情况一是只下载了老旧的 sqljdbc4.jar版本和当前 SQL Server 不匹配二是 jar 文件放在 lib 目录下但 IDE 没有把它加入 Build Path运行时完全找不到驱动类。解决从微软官方获取对应版本的 mssql-jdbc 驱动然后在 IDE 里执行一次 Build Path 导入。如果用 Maven 管理直接在 pom.xml 里引入依赖dependency groupIdcom.microsoft.sqlserver/groupId artifactIdmssql-jdbc/artifactId version12.4.2.jre8/version /dependency引入后先在 DbUtil 的 main 方法里跑一次连接自检确认驱动加载成功再启动主窗体。4.2 端口1433连不上命名实例和TCP/IP协议是元凶现象报通过端口 1433 连接到主机 localhost 失败但本地 SQL Server Management Studio 可以正常登录。原因SQL Server 默认实例监听 1433 端口但很多机器安装时选的是命名实例比如 SQLEXPRESS。命名实例的端口可能是动态分配的且 SQL Server Browser 服务默认没启动外部程序拿不到正确的端口。另外SQL Server 网络配置里的 TCP/IP 协议可能处于禁用状态只开放了 Named Pipes。解决打开 SQL Server 配置管理器在“SQL Server 网络配置”里确认实例名找到 TCP/IP 协议右键启用。然后在“IP 地址”选项卡里把 IP 端口改成 1433。修改后重启 SQL Server 服务。连接串里如果是命名实例就要写成jdbc:sqlserver://localhost\\SQLEXPRESS:1433;DatabaseNameSupermarketDB最后检查 Windows 防火墙是否放行了 1433 端口。本机调试时建议先关防火墙或添加允许规则免得端口又被拦一道。4.3 中文乱码编码、NVARCHAR、IDE项目编码三层排查现象窗体标题、按钮文字、表格数据显示成问号或乱码数据库里查到的中文也变成???。原因这是三层问题的叠加。第一层Java 源文件保存时用的编码和编译器读取时用的编码不一致导致字符串在编译阶段就已经损坏第二层建表时字段用了 VARCHARSQL Server 在简体中文排序规则下对部分字符集不友好第三层数据库连接没有指定客户端编码驱动和数据库之间的字符转换出错。解决如果是反编译后重新编译把 IDE 的项目编码统一设为 UTF-8。然后在 SQL Server 端把所有中文相关字段改成 NVARCHAR 类型比如ALTER TABLE person_info ALTER COLUMN person_name NVARCHAR(30)。最后在 JDBC URL 里加上characterEncodingUTF-8相关参数。三层都对齐之后乱码基本消失。注意SQL Server 没有 MySQL 里那种SET NAMES utf8的命令最稳妥的办法就是建表时规范用N前缀类型连接参数里显式指定编码。4.4 只有.class没有.java反编译工具怎么选现象解压后全是.class文件找不到.java源码想改按钮文字或者加一个功能不知道从哪下手。原因这类资源分发时只导出了编译后的 class 文件属于常见情况不是你的解压软件有问题。解决用 JD-GUI 工具直接把 class 文件拖进去可以看到还原后的 Java 代码也可以导出成 java 文件。IntelliJ IDEA 自带反编译能力直接把 class 文件打开就能浏览。注意两点一是反编译后的代码一般变量名错乱建议只用来理解逻辑不要直接复制粘贴回去二是某些内部类会生成PersonnelPanel$1.class这类文件要随主类一起放回原包路径否则运行时会报类找不到。4.5 数据库连不上验证模式、库名、SA密码三处核对现象SQL Server Management Studio 能连程序运行时报“用户登录失败”或者“无法打开数据库”提示信息语义很模糊。原因SQL Server 安装时选的认证模式是“Windows 身份验证模式”程序用 sa 账号登录自然被拒绝。另外连接 URL 里的 DatabaseName 和实际库名不一致也会报类似错误。解决在 SQL Server Management Studio 里右键服务器属性选择“安全性”把服务器身份验证改成“SQL Server 和 Windows 身份验证模式”。然后确认 sa 账号已启用密码没有过期。课程项目的常见密码是sa / 123456如果你的环境改了密码记得同步修改 DbUtil 里的 PASSWORD 常量。最后核对连接串里的 DatabaseName 大小写都正确和实际库名完全一致。这五条如果按顺序排查完大部分环境问题都能解决。第 4.1 和 4.2 是出现频率最高的先处理掉这两条系统基本就能启动。5. 进阶改造把 DAO 层从能用改成好维护5.1 连接池和参数化查询一起换原 DAO 每次数据库操作都新建连接课设场景下没问题数据量稍微上来就会拖垮 SQL Server。最简单的方案是引入 HikariCP 连接池替换成本很低HikariConfig config new HikariConfig(); config.setJdbcUrl(jdbc:sqlserver://localhost:1433;DatabaseNameSupermarketDB;encryptfalse;trustServerCertificatetrue); config.setUsername(sa); config.setPassword(123456); config.setMaximumPoolSize(10); config.setMinimumIdle(2); config.setConnectionTimeout(3000); HikariDataSource ds new HikariDataSource(config);把原 DAO 里的DriverManager.getConnection统一替换成ds.getConnection()其余 SQL 代码不需要改动。同时把字符串拼接的 SQL 全部改成 PreparedStatement 占位符写法输入值里带单引号也不会破坏 SQL 语义这是最直接的两个升级点。5.2 用循环业务测试验证改造结果改完 DAO 之后不能只靠肉眼检查我一般会写一个循环脚本连续执行 100 次入库出库最后验证库存余额。这个测试能一次性暴露连接泄露、SQL 拼接错误、事务边界问题三类隐患。for (int i 1; i 100; i) { joinDao.addJoinDepot(goodsId, 10, 5.0); // 入库10件 outDao.addOutDepot(goodsId, 3, 8.0); // 出库3件 } Goods g goodsDao.findById(goodsId); int expectedStock 100 * (10 - 3); if (g.getStockQty() ! expectedStock) { throw new AssertionError(库存对不上 g.getStockQty()); }循环跑到一半如果连接池耗尽、连接被关闭这个脚本就会立刻报错不用等到真正上线才发现。我从那次改造起养成一个习惯每次动 DAO 层代码都会强制走一遍这种全流程验证再收工。希望帮到你。本文还有配套的精品资源点击获取