拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Java+SQL Server 2005仓库管理系统课程设计:从建库到跑通

Java+SQL Server 2005仓库管理系统课程设计:从建库到跑通

简介:这份数据库课程设计仓库管理系统文档,面向本科阶段计算机相关专业学生及需要完成数据库课程设计的学习者,围绕小型仓库管理场景,提供一套基于JAVA与SQL SERVER 2005的完整业务系统实现方案。资源包内共1个docx文件,大小约1.44MB,内容涵盖课程设计报告、程序结构图、数据表设计、类功能说明及关键代码片段,便于读者理解系统从需求分析到编码落地的整体流程。系统划分为基础信息管理、出入库管理、查询统计和系统管理四大模块,涉及商品、客户、供应商、库存及操作员信息表,并通过Dao类完成数据库连接与数据操作,Login类实现权限验证,JXCFrame作为主程序窗口串联各功能界面。目前已有3609人学习,适合希望掌握JAVA与SQL结合开发、强化数据库设计与软件工程流程理解的学生参考,也可作为课程设计选题与实现思路的借鉴材料。

1. 从一份 2014 年的课程设计说起:JAVA + SQL SERVER 2005 的小型仓库管理系统到底能跑出什么

翻到这份《数据库课程设计仓库管理系统》的时候,我第一反应是——这玩意儿还能跑吗?2014 年 6 月,MyEclipse 加 SQL SERVER 2005,Swing 手写界面,Class.forName加载驱动,sa空密码连库。放在今天看,技术栈确实老得掉渣,但如果你正在做数据库课程设计、或者需要一套能交差、能演示、能讲清楚“增删改查 + 权限 + 事务”的最小闭环系统,这份资源反而比那些花里胡哨的 Spring Boot 脚手架更值得拆。它一共四个模块:基础信息管理、出入库管理、查询统计、系统管理,覆盖了供应商、商品、客户、库存、操作员五张核心表,代码里连JDesktopPane多内部窗体、JTabbedPane导航、登录鉴权、数据库连接池雏形都给你写好了。适合谁?本科数据库课设、JAVA 桌面端入门、想理解“表设计如何映射到 Swing 面板”的从业者。下面我按“能复现”的标准,把这份仓库管理系统从建库到跑通拆一遍。

2. 建库与表结构:五张核心表怎么撑起进销存

2.1 从 BCNF 说起:为什么这五张表冗余度低

原文里有一句“系统数据库中的表满足 BCNF,冗余度低,效率高”,这不是随便写的。BCNF 意味着每个决定因素都包含候选键,翻译成人话就是:供应商、商品、客户、库存、操作员这五类实体各自独立成表,彼此之间只靠外键关联,不把供应商电话塞进商品表,也不把客户地址塞进出库单。我一般会先把实体关系画清楚再动手建表,否则后面 Swing 面板里一个JComboBox要同时显示商品名和供应商名,你就得在 SQL 里反复 JOIN,代码越写越乱。

常见做法是:tb_gysinfo存供应商,tb_spinfo存商品,tb_khinfo存客户,tb_stock存库存,tb_userlist存操作员。出库和入库不单独建“流水表”而是直接更新库存表加操作记录,这是课设级别的简化,生产环境别这么干。

2.2 建库脚本与字段说明

SQL SERVER 2005 的语法和现在差别不大,但要注意nvarchar和varchar的选择,中文商品名必须用nvarchar,否则乱码。下面是我根据原文表名和用途还原的建库脚本,字段类型按课设常见规格补全:

-- 创建数据库 CREATE DATABASE db_JXC; GO USE db_JXC; GO -- 供应商信息表 CREATE TABLE tb_gysinfo ( id INT IDENTITY(1,1) PRIMARY KEY, -- 自增主键 gysname NVARCHAR(50) NOT NULL, -- 供应商名称 jc NVARCHAR(20), -- 简称 address NVARCHAR(100), -- 地址 tel NVARCHAR(20), -- 电话 fax NVARCHAR(20), -- 传真 email NVARCHAR(50), -- 邮箱 memo NVARCHAR(200) -- 备注 ); -- 商品信息表 CREATE TABLE tb_spinfo ( id INT IDENTITY(1,1) PRIMARY KEY, spname NVARCHAR(50) NOT NULL, -- 商品名称 jc NVARCHAR(20), -- 简称 cd NVARCHAR(20), -- 产地 gg NVARCHAR(20), -- 规格 dw NVARCHAR(10), -- 单位 gysname NVARCHAR(50), -- 供应商名称(冗余字段,课设简化) memo NVARCHAR(200) ); -- 客户信息表 CREATE TABLE tb_khinfo ( id INT IDENTITY(1,1) PRIMARY KEY, khname NVARCHAR(50) NOT NULL, -- 客户名称 jc NVARCHAR(20), address NVARCHAR(100), tel NVARCHAR(20), email NVARCHAR(50), memo NVARCHAR(200) ); -- 库存信息表 CREATE TABLE tb_stock ( id INT IDENTITY(1,1) PRIMARY KEY, spname NVARCHAR(50) NOT NULL, -- 商品名称 kcsl INT DEFAULT 0, -- 库存数量 dj DECIMAL(10,2) DEFAULT 0 -- 单价 ); -- 操作员信息表 CREATE TABLE tb_userlist ( id INT IDENTITY(1,1) PRIMARY KEY, username NVARCHAR(20) NOT NULL UNIQUE, -- 登录名 name NVARCHAR(20), -- 真实姓名 pass NVARCHAR(20), -- 密码(课设明文,生产必须哈希) quan NVARCHAR(10) -- 权限级别 );

逻辑说明:IDENTITY(1,1)是 SQL SERVER 的自增写法,等价于 MySQL 的AUTO_INCREMENT。tb_spinfo里我保留了gysname这个冗余字段,因为原文的 Swing 面板里商品管理直接显示供应商名,如果严格 BCNF 应该只存gysid,但课设为了减少 JOIN 复杂度,通常允许这种反范式。参数上,NVARCHAR长度按业务字段合理估算,商品名 50 够用,备注 200 足够。

提示:SQL SERVER 2005 默认不开启sa账户,需要在“安全性-登录名”里启用并设置密码。原文里dbPwd = ""是空密码,本地跑可以,交作业前建议改成非空,否则答辩时老师一问就露馅。

2.3 插入测试数据

建完表不插数据,Swing 界面打开就是一片空白,连登录都过不去。操作员表至少插一条管理员记录:

INSERT INTO tb_userlist (username, name, pass, quan) VALUES ('admin', '管理员', '123', '管理员'); INSERT INTO tb_gysinfo (gysname, jc, tel) VALUES ('华东电子', 'HD', '021-12345678'); INSERT INTO tb_spinfo (spname, jc, gg, dw, gysname) VALUES ('电阻10K', 'DZ10K', '0805', '个', '华东电子'); INSERT INTO tb_stock (spname, kcsl, dj) VALUES ('电阻10K', 1000, 0.05);

这几条数据是后面登录和查询演示的最小集。quan字段决定登录后能看到哪些按钮,原文里“一般用户有查询、插入、更新、删除的权力,而管理员还有添加删除用户、密码维护”,所以quan至少要有“管理员”和“一般用户”两个值。

3. 数据库连接与 Dao 层:Class.forName那套写法还能不能用

3.1 驱动加载与连接字符串拆解

原文Dao.java里这段代码是整份资源的命门:

static String dbClassName = "com.microsoft.jdbc.sqlserver.SQLServerDriver"; static String dbUrl = "jdbc:microsoft:sqlserver://localhost:1433;" + "DatabaseName=db_JXC;SelectMethod=Cursor"; protected static String dbUser = "sa"; protected static String dbPwd = ""; public static Connection conn = null; static { try { if (conn == null) { Class.forName(dbClassName).newInstance(); conn = DriverManager.getConnection(dbUrl, dbUser, dbPwd); } } catch (Exception e) { e.printStackTrace(); } }

逻辑说明:Class.forName加载驱动类,newInstance()实例化,这是 JDBC 4.0 之前的标配写法。dbUrl里的SelectMethod=Cursor是 SQL SERVER 2005 驱动特有的参数,作用是让结果集以游标方式返回,避免一次性把所有数据拉进内存——课设数据量小感觉不到,但如果你插了几万条库存记录,不加这个参数可能直接 OOM。DatabaseName=db_JXC必须和建库名一致,大小写不敏感但建议统一。

参数怎么改:如果你本机装的是 SQL SERVER 2008 或更高版本,驱动类名要换成com.microsoft.sqlserver.jdbc.SQLServerDriver,URL 前缀换成jdbc:sqlserver://,端口默认 1433。原文用的com.microsoft.jdbc.sqlserver.SQLServerDriver是 2005 专用驱动,现在很难找到,常见做法是换成mssql-jdbc的 jar 包。

3.2 查询方法封装与 Swing 表格绑定

原文里getKhInfos()方法只写了一行findForList("select id,khname from tb_khinfo"),我把它补全成一个可复用的查询封装:

public static List<Map<String, Object>> findForList(String sql) { List<Map<String, Object>> list = new ArrayList<>(); try { Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql); ResultSetMetaData md = rs.getMetaData(); int cols = md.getColumnCount(); while (rs.next()) { Map<String, Object> row = new HashMap<>(); for (int i = 1; i <= cols; i++) { row.put(md.getColumnName(i), rs.getObject(i)); } list.add(row); } rs.close(); stmt.close(); } catch (SQLException e) { e.printStackTrace(); } return list; }

逻辑说明:用ResultSetMetaData动态获取列名,把每一行塞进Map,这样 Swing 的JTable可以直接用DefaultTableModel渲染,不用为每张表写一个实体类。参数上,sql由调用方传入,比如客户查询面板传select id,khname,tel from tb_khinfo,库存盘点传select spname,kcsl,dj from tb_stock。注意conn是静态的,整个应用共用一个连接,课设够用,但并发操作会出问题——这也是后面避坑章节要讲的。

3.3 登录验证与权限分流

Login.java里Dao.getUser(userName.getText(), userPassword.getText())返回一个TbUserlist对象,然后判断user.getUsername() == null就清空输入框。这个逻辑有个隐患:如果数据库里查不到用户,getUser返回的是null还是空对象?原文没写清楚,我一般会这样补:

public static TbUserlist getUser(String username, String password) { TbUserlist user = new TbUserlist(); String sql = "select * from tb_userlist where username='" + username + "' and pass='" + password + "'"; List<Map<String, Object>> list = findForList(sql); if (list.size() > 0) { Map<String, Object> row = list.get(0); user.setUsername((String) row.get("username")); user.setName((String) row.get("name")); user.setQuan((String) row.get("quan")); } return user; }

逻辑说明:返回空对象而不是null,调用方只需判断getUsername() == null即可,避免NullPointerException。权限字段quan在JXCFrame创建导航面板时用来决定是否添加“系统管理”标签页。常见做法是在createNavigationPanel()里加一个判断:如果Login.getUser().getQuan().equals("管理员")才tabbedPane.addTab("系统管理", ...)。

注意:原文 SQL 是字符串拼接,存在注入风险。课设演示无所谓,但如果你要把它写进简历项目,建议改成PreparedStatement,否则面试官一眼看穿。

4. 避坑与排查:这份 2014 年老代码最容易翻车的五个地方

4.1 现象:登录后主窗口一片灰,按钮点了没反应

原因:JDesktopPane的背景图片welcome.jpg路径不对。原文updateBackImage()里用JXCFrame.this.getClass().getResource("welcome.jpg"),这要求图片和JXCFrame.class在同一目录下。MyEclipse 默认把src下的非 java 文件复制到bin,但如果你手动改了输出路径或者用 IDEA 打开,图片就找不到了。

解决:在项目根目录建res文件夹,把图片放进去,代码改成getClass().getResource("/res/welcome.jpg")。或者更粗暴——直接把图片转成 Base64 硬编码,课设演示绝对不丢。

4.2 现象:ClassNotFoundException: com.microsoft.jdbc.sqlserver.SQLServerDriver

原因:没导入 SQL SERVER 2005 的 JDBC 驱动 jar 包,或者 jar 包版本和 JDK 不匹配。原文用的是sqljdbc.jar,只支持 JDK 1.5 左右,你如果用 JDK 8 跑,大概率报这个错。

解决:换成sqljdbc4.jar或mssql-jdbc-7.4.1.jre8.jar,驱动类名改成com.microsoft.sqlserver.jdbc.SQLServerDriver,URL 改成jdbc:sqlserver://localhost:1433;databaseName=db_JXC。注意SelectMethod=Cursor在新驱动里已经废弃,去掉即可。

4.3 现象:中文商品名存进数据库变成问号

原因:建表时用了varchar而不是nvarchar,或者 JDBC URL 没指定字符集。SQL SERVER 2005 默认排序规则如果是SQL_Latin1_General_CP1_CI_AS,varchar存中文直接丢。

解决:建表统一用nvarchar,JDBC URL 加;sendStringParametersAsUnicode=true。如果已经建了表,用ALTER TABLE tb_spinfo ALTER COLUMN spname NVARCHAR(50)改字段类型。

4.4 现象:库存盘点数字对不上,出库后库存没减

原因:原文的出库逻辑是“先查出库存,再更新”,但 Swing 面板里两个操作不在同一个事务里。如果更新时抛异常,库存没减但出库记录已经写了,数据就脏了。

解决:把出库操作包在conn.setAutoCommit(false)和conn.commit()之间,任何一步失败就rollback()。课设不要求事务,但答辩时老师问“怎么保证数据一致性”,你能答上来就是加分项。

4.5 现象:多个内部窗体同时打开,修改一个另一个不刷新

原因:JXCFrame用Map<String, JInternalFrame> ifs缓存窗体实例,getIFrame方法如果窗体已存在就直接返回旧实例,不会重新查数据库。所以你在商品管理里改了价格,库存盘点窗口还是旧数据。

解决:在openFrameAction的actionPerformed里,每次打开窗体前先调一下窗体的刷新方法,或者干脆不用缓存,每次new一个新实例。代价是内存占用高一点,但课设数据量小,无所谓。

5. 进阶技巧:把这份课设改成能写进简历的项目

5.1 用PreparedStatement替换所有字符串拼接

原文所有 SQL 都是"select * from tb_userlist where username='" + username + "'"这种写法,改起来不复杂,但收益很大。以登录为例:

public static TbUserlist getUser(String username, String password) { TbUserlist user = new TbUserlist(); String sql = "select * from tb_userlist where username=? and pass=?"; try { PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, username); ps.setString(2, password); ResultSet rs = ps.executeQuery(); if (rs.next()) { user.setUsername(rs.getString("username")); user.setName(rs.getString("name")); user.setQuan(rs.getString("quan")); } rs.close(); ps.close(); } catch (SQLException e) { e.printStackTrace(); } return user; }

逻辑说明:?是占位符,setString按位置绑定参数,驱动会自动处理转义,注入攻击直接失效。参数上,注意setString的索引从 1 开始,不是 0。这个改动花不了半小时,但面试时你说“我做了 SQL 注入防护”,比说“我写了个登录界面”有分量得多。

5.2 加一个简单的数据库连接池

原文Dao.conn是静态单连接,所有操作共用一个Connection。Swing 是单线程的,课设跑起来没问题,但如果你在查询统计里加了“导出 Excel”这种耗时操作,界面会卡死。常见做法是引入DBCP或HikariCP,但课设没必要上重武器,手写一个简易连接池就够:

public class SimplePool { private static final int MAX = 5; private static List<Connection> pool = new ArrayList<>(); static { try { for (int i = 0; i < MAX; i++) { pool.add(DriverManager.getConnection(dbUrl, dbUser, dbPwd)); } } catch (SQLException e) { e.printStackTrace(); } } public static synchronized Connection getConn() { if (pool.isEmpty()) return null; return pool.remove(0); } public static synchronized void release(Connection c) { if (c != null && pool.size() < MAX) pool.add(c); } }

逻辑说明:初始化时创建 5 个连接放进List,getConn取一个,release还一个。参数MAX按课设并发量设 5 足够,生产环境要配合validConnection检测连接是否失效。这个改动能让你的课设从“能跑”变成“有点工程味道”。

5.3 验证方法:用JUnit跑一遍 Dao 层

课设不要求单元测试,但如果你想确认findForList和getUser没写错,加一个测试类很快:

public class DaoTest { @Test public void testGetUser() { TbUserlist user = Dao.getUser("admin", "123"); assertNotNull(user.getUsername()); assertEquals("管理员", user.getQuan()); } @Test public void testFindForList() { List<Map<String, Object>> list = Dao.findForList("select * from tb_stock"); assertTrue(list.size() > 0); } }

逻辑说明:@Test注解标记测试方法,assertNotNull和assertEquals验证结果。跑之前确保数据库已启动、测试数据已插入。这个测试类不用交,但你自己跑一遍,能提前发现“驱动没加载”“表名写错”这类低级问题。

5.4 一个我踩过的坑

当年我第一次跑这份代码,登录界面能出来,但点“登录”没反应。查了半天发现Login.java里login.doClick()绑在userPassword的KeyAdapter上,回车触发,但鼠标点击没绑。原文代码里login.addActionListener是有的,但我复制的时候漏了一段。从那以后我每次拿到这种 Swing 老代码,都强制走一遍“界面能显示 → 按钮能点 → 数据能查 → 数据能改”四步验证,少一步都不往下写。希望帮到你。

本文还有配套的精品资源,点击获取

返回列表