news 2026/9/12 5:01:09

Java SE轻量收银系统:Swing+JDBC实现桌面端收银闭环

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java SE轻量收银系统:Swing+JDBC实现桌面端收银闭环

简介:这是一份基于Java开发的轻量级超市收银系统实战项目资源,面向Java初学者与课程设计学习者,解决零售场景下商品管理、用户登录、收银台操作及会员注册等核心业务逻辑实现问题。压缩包共27个文件,含9个.java源码文件(如DengLu.java登录模块、Shouyintai.java收银台主界面、Goods.java商品类)、14个编译后.class字节码文件、2个manifest.mf清单文件、以及.project和.classpath工程配置文件,完整呈现从编码、编译到运行的全流程结构,包体仅25KB,便于快速导入IDE学习调试。已有264人下载学习,读者可直接获取可运行的GUI收银系统源码,掌握Swing界面开发、JDBC数据库连接(预设DBUtil工具类)、MVC分层思想及基础事务处理逻辑,特别适合JavaSE阶段项目实训与期末课程设计参考。

1. 这不是演示项目,而是一套能跑通完整收银闭环的 Java 桌面系统

你解压chaoshi.rar后看到的不是空壳 Demo,也不是只有登录界面的“教学玩具”——它包含从商品录入、会员注册、收银台结算到库存扣减的全链路逻辑,且所有类文件(.class)已编译就绪,src/下对应.java源码完整可读。这意味着:无需重写业务逻辑,只要配好 JDBC 驱动、建好数据库表、启动主类Shouyintai.class,就能在 Windows 或 Linux 桌面环境直接扫码结账。它不依赖 Spring Boot、不嵌入 Tomcat、不走 HTTP 接口,而是用 AWT/Swing 构建本地 GUI,用DBUtil.class封装 JDBC 连接池(虽简但有效),用Goods.classMember.class承载核心领域模型。适合两类人:一是 Java 初学者想拿真实业务练手(比“学生管理系统”更贴近商业场景),二是中小超市技术员需快速部署轻量收银终端(无云服务依赖,单机即可运行)。它不解决高并发或分布式事务,但把“一笔交易如何从扫码→查价→扣库存→打小票”这个最小闭环,用纯 Java SE + JDBC + Swing 拆解得足够清晰。


2. 从反编译源码到数据库建模:还原系统数据结构与交互流程

2.1 解包后关键类职责解析:不是命名堆砌,而是分层明确的 MVC 实践

chaoshi.rar解压后呈现典型的 Java SE 桌面应用结构:bin/存放编译产物,src/存放源码,.project.classpath表明原工程基于 Eclipse 开发。我们先聚焦核心类的协作关系:

  • Shouyintai.java(收银台):主窗口类,继承Frame,含JTable显示购物车、JLabel实时总价、JButton触发结算。其内部匿名类Shouyintai$1.classActionListener,监听“结算”按钮点击事件。
  • Goods.javaMember.java:实体类,字段直白映射数据库列(如Goodsid,name,price,stockMembercardNo,name,discount),无 Lombok 注解,靠手动 getter/setter 维护。
  • DBUtil.java:关键基础设施类。静态块加载com.mysql.jdbc.Driver(注意:这是 MySQL Connector/J 5.x 旧版驱动类名),getConnection()方法返回Connectionclose()方法显式释放资源。未使用连接池,但通过static变量缓存Connection对象,避免每次操作都新建连接——这是单机桌面应用的典型取舍
  • DengLu.java(登录)与Shouyinyuanzhuce.java(收银员注册):验证逻辑在客户端完成(JPasswordField.getText().equals("123")类似硬编码密码),安全性非重点,但流程完整:登录 → 进入收银台 → 商品扫码/搜索 → 加入购物车 → 结算 → 更新库存。

提示:Shangpingtianjia$close.classShangpingtianjia.java(商品添加)中内部类,用于监听窗口关闭事件并执行dispose()。这种细粒度事件拆分,是 Swing 编程的惯用手法,而非冗余代码。

2.2 数据库表结构逆向推导:从 DAO 层 SQL 拼接还原 DDL

DBUtil.java中无建表语句,但Goods.javainsert()方法暴露了插入逻辑:

public int insert(Goods goods) { String sql = "INSERT INTO goods (name, price, stock, barcode) VALUES (?, ?, ?, ?)"; // ... PreparedStatement 设置参数 ... }

同理,Member.javainsert()方法含"INSERT INTO member (cardNo, name, phone, discount) VALUES (?, ?, ?, ?)"。结合DengLu.java登录查询"SELECT * FROM user WHERE username = ? AND password = ?",可确定三张核心表:

表名字段(类型)说明
goodsid INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(50),price DECIMAL(10,2),stock INT,barcode VARCHAR(20)商品主表,barcode为扫码依据
memberid INT PRIMARY KEY AUTO_INCREMENT,cardNo VARCHAR(20) UNIQUE,name VARCHAR(30),phone VARCHAR(15),discount DECIMAL(3,2)会员表,discount存储折扣率(如 0.95 表示 95 折)
userid INT PRIMARY KEY AUTO_INCREMENT,username VARCHAR(20),password VARCHAR(50)收银员账号表,密码明文存储(仅作功能验证,非生产标准)

建表 SQL 必须执行(以 MySQL 8.0 为例):

CREATE DATABASE IF NOT EXISTS chaoshi DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci; USE chaoshi; CREATE TABLE goods ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL, price DECIMAL(10,2) NOT NULL, stock INT NOT NULL DEFAULT 0, barcode VARCHAR(20) UNIQUE ); CREATE TABLE member ( id INT PRIMARY KEY AUTO_INCREMENT, cardNo VARCHAR(20) UNIQUE NOT NULL, name VARCHAR(30), phone VARCHAR(15), discount DECIMAL(3,2) DEFAULT 1.00 ); CREATE TABLE user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(20) NOT NULL, password VARCHAR(50) NOT NULL ); -- 插入默认收银员(用户名 admin,密码 123) INSERT INTO user (username, password) VALUES ('admin', '123');

注意:DBUtil.javagetConnection()使用DriverManager.getConnection("jdbc:mysql://localhost:3306/chaoshi?useSSL=false&serverTimezone=GMT%2B8", "root", "123456")必须确保 MySQL 服务运行,且 root 用户密码为123456,否则启动Shouyintai会抛出SQLException: Access denied。若修改密码,需同步更新DBUtil.java中的密码字符串并重新编译。

2.3 启动流程与类加载路径:绕过 IDE 直接运行的关键步骤

系统未打包成 JAR,需手动指定 classpath 运行。步骤如下:

  1. 准备运行环境

    • 安装 JDK 8(java -version输出1.8.0_XXX),因DBUtil.java使用com.mysql.jdbc.Driver(MySQL 5.x 驱动),与 JDK 8 兼容性最佳;
    • mysql-connector-java-5.1.47.jar(下载地址:https://dev.mysql.com/downloads/connector/j/5.1.html)放入chaoshi/目录;
    • 确保chaoshi/bin/下存在所有.class文件(含manifest.mf,但此文件无Main-Class声明,故不能java -jar)。
  2. 命令行启动收银台

    cd chaoshi java -cp "bin:./mysql-connector-java-5.1.47.jar" Shouyintai
    • -cp参数将bin/(含所有 class)和 MySQL 驱动 JAR 合并为类路径;
    • Shouyintai是主类名(无.class后缀),JVM 自动查找bin/Shouyintai.class
    • 若报错Could not find or load main class Shouyintai,检查当前目录是否为chaoshi/,且bin/下确有Shouyintai.class
  3. 首次运行验证

    • 启动后弹出登录窗口,输入admin/123进入收银台;
    • 点击“商品管理” → “添加商品”,填入名称、价格、库存、条码(如123456),点击保存;
    • 返回收银台,在“商品条码”输入框输入123456,回车——商品自动加入购物车,总价实时计算;
    • 点击“结算”,弹出确认框,选择“现金支付”,系统扣减goods表中对应stock并生成交易记录(虽无独立 transaction 表,但库存更新已执行)。

3. 商品扫码与库存强一致性保障:事务控制与并发安全实操

3.1 默认无事务?用 try-catch + 手动 rollback 弥补 JDBC 原生缺陷

Shouyintai.java的结算逻辑位于actionPerformed()方法中,关键代码片段如下:

// 伪代码示意(实际在 Shouyintai$1.class 中) try { conn = DBUtil.getConnection(); conn.setAutoCommit(false); // 关键:开启事务 // 步骤1:扣减库存(UPDATE goods SET stock = stock - ? WHERE id = ?) PreparedStatement ps1 = conn.prepareStatement("UPDATE goods SET stock = stock - ? WHERE id = ?"); ps1.setInt(1, quantity); ps1.setInt(2, goodsId); ps1.executeUpdate(); // 步骤2:记录销售(此处无 sales 表,故省略) conn.commit(); // 提交事务 } catch (SQLException e) { try { conn.rollback(); // 回滚 } catch (SQLException ex) { ex.printStackTrace(); } JOptionPane.showMessageDialog(null, "库存不足或数据库错误"); }

但原始chaoshi.rar中的Shouyintai.java并未显式调用setAutoCommit(false)commit()。这意味着:默认autoCommit=true,每条 SQL 独立提交,无法保证“扣库存”与“记销售”的原子性。必须手动增强

修改Shouyintai.java的结算方法(以 Eclipse 为例):
  1. // 结算逻辑开始处添加:
    Connection conn = null; try { conn = DBUtil.getConnection(); conn.setAutoCommit(false); // 关闭自动提交
  2. // 扣库存 SQL 执行后添加:
    // 假设已有 PreparedStatement psUpdateStock 执行成功 psUpdateStock.executeUpdate(); // 此处可追加其他业务SQL,如插入 sales 记录 // PreparedStatement psInsertSale = conn.prepareStatement("INSERT INTO sales (...) VALUES (...)"); // psInsertSale.executeUpdate(); conn.commit(); // 显式提交 JOptionPane.showMessageDialog(this, "结算成功!"); } catch (SQLException e) { try { if (conn != null) conn.rollback(); // 发生异常则回滚 } catch (SQLException ex) { ex.printStackTrace(); } JOptionPane.showMessageDialog(this, "结算失败:" + e.getMessage()); } finally { try { if (conn != null) conn.close(); } catch (SQLException e) { e.printStackTrace(); } }

提示:DBUtil.javaclose()方法仅关闭StatementResultSet,未关闭Connection。因此在Shouyintai中必须显式conn.close(),否则连接泄漏。这是桌面应用常见疏漏,需补全。

3.2 库存超卖防护:乐观锁 vs 悲观锁的轻量级选型

当多台收银机同时操作同一商品时,UPDATE goods SET stock = stock - 1 WHERE id = 100可能导致超卖(如库存剩 1,两笔请求同时读到 1,均扣减为 0)。chaoshi原始代码无防护,需加固:

方案一:乐观锁(推荐,侵入小)
  • goods表新增version INT DEFAULT 0字段;
  • 查询商品时读取version
  • 更新时校验:UPDATE goods SET stock = stock - 1, version = version + 1 WHERE id = ? AND version = ?
  • executeUpdate()返回 0,说明版本不匹配(已被他人更新),提示“库存变动,请刷新重试”。
方案二:悲观锁(简单直接)
  • 在查询商品时加锁:SELECT * FROM goods WHERE id = ? FOR UPDATE
  • 此 SQL 会阻塞其他事务对同一行的UPDATE,直到当前事务结束;
  • 注意:必须在同一个Connection中执行SELECT ... FOR UPDATE和后续UPDATE,且事务未提交前锁不释放。

实操代码(悲观锁)

String sqlSelect = "SELECT * FROM goods WHERE id = ? FOR UPDATE"; PreparedStatement psSelect = conn.prepareStatement(sqlSelect); psSelect.setInt(1, goodsId); ResultSet rs = psSelect.executeQuery(); if (rs.next()) { int currentStock = rs.getInt("stock"); if (currentStock < quantity) { throw new SQLException("库存不足"); } // 继续执行 UPDATE }

4. 从 Swing 到现代化 UI:替换 AWT 组件与集成打印模块的实战改造

4.1 用 IntelliJ IDEA 重构 GUI:告别 AWT,拥抱现代 Swing 组件

chaoshi原始界面使用Frame+Panel+Button等 AWT 组件,布局僵硬(FlowLayout)、字体模糊、无高 DPI 支持。升级为JFrame+JPanel+JButton并启用系统外观:

  1. 修改主类继承关系
    Shouyintai.javapublic class Shouyintai extends Framepublic class Shouyintai extends JFrame
  2. 替换组件初始化
    // 原:Frame frame = new Frame("收银台"); // 改为: JFrame frame = new JFrame("超市收银系统"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new BorderLayout()); // 使用 BorderLayout 替代 FlowLayout
  3. 启用系统外观(Windows/macOS/Linux 自适应):
    main()方法开头添加:
    try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception e) { e.printStackTrace(); }

4.2 集成热敏小票打印:用 Java Print Service 输出标准 POS 小票

收银系统必须支持物理打印。chaoshi无打印模块,需自行添加。以下为兼容主流热敏打印机(如芯烨、佳博)的方案:

步骤 1:定义小票文本模板
public static String generateReceipt(List<CartItem> cart, double total) { StringBuilder sb = new StringBuilder(); sb.append("====== 超市收银系统 ======\n"); sb.append("时间:").append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())).append("\n"); sb.append("----------------------------\n"); for (CartItem item : cart) { sb.append(String.format("%-10s %4d×%6.2f=%6.2f\n", item.getName(), item.getQuantity(), item.getPrice(), item.getTotal())); } sb.append("----------------------------\n"); sb.append(String.format("总计:¥%8.2f\n", total)); sb.append("感谢惠顾!\n"); return sb.toString(); }
步骤 2:调用系统打印机(无需驱动,依赖 OS 打印服务)
public static void printReceipt(String receiptText) { try { DocFlavor flavor = DocFlavor.BYTE_ARRAY.AUTOSENSE; PrintService service = PrintServiceLookup.lookupDefaultPrintService(); if (service == null) { JOptionPane.showMessageDialog(null, "未找到默认打印机,请检查系统设置"); return; } Doc doc = new SimpleDoc(receiptText.getBytes(StandardCharsets.UTF_8), flavor, null); service.createPrintJob().print(doc, null); } catch (Exception e) { e.printStackTrace(); JOptionPane.showMessageDialog(null, "打印失败:" + e.getMessage()); } }

调用时机:在Shouyintai结算成功后,JOptionPane.showMessageDialog(...)之后插入printReceipt(receiptText)

注意:Windows 系统需在“设置 > 蓝牙和其他设备 > 打印机和扫描仪”中添加热敏打印机,并设为默认。Linux 用户需安装 CUPS 服务并配置打印机。


5. 生产环境加固:密码加密、日志追踪与离线模式下的本地缓存策略

5.1 密码明文存储风险与 BCrypt 加密迁移路径

user表中password字段明文存储(如123),严重违反安全规范。迁移方案需兼顾兼容性与平滑升级:

  1. 新增password_hash字段(VARCHAR(100)):
    ALTER TABLE user ADD COLUMN password_hash VARCHAR(100) AFTER password;
  2. 修改登录验证逻辑DengLu.java):
    // 查询时同时获取 password 和 password_hash String sql = "SELECT id, username, password, password_hash FROM user WHERE username = ?"; // 若 password_hash 为空(老用户),用明文比对并生成 hash 写回数据库 // 若 password_hash 不为空,用 BCrypt.checkpw(inputPassword, storedHash) 验证
  3. 引入 BCrypt 依赖
    下载bcprov-jdk15on-168.jar(Bouncy Castle)或更轻量的jbcrypt-0.4.jar(https://github.com/jeremyh/jBCrypt),添加至 classpath;
    // 生成 hash 示例 String hash = BCrypt.hashpw("123", BCrypt.gensalt());

5.2 用 Log4j2 实现操作审计日志:定位每一笔交易源头

chaoshi无日志,故障排查困难。添加log4j2.xml配置(放在src/下):

<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN"> <Appenders> <File name="FileAppender" fileName="logs/chaoshi.log"> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> </File> </Appenders> <Loggers> <Root level="info"> <AppenderRef ref="FileAppender"/> </Root> </Loggers> </Configuration>

Shouyintai.java结算方法中插入日志:

Logger logger = LogManager.getLogger(Shouyintai.class); logger.info("收银员[{}]结算订单:{}件商品,总金额¥{},支付方式[现金]", currentUser.getUsername(), cart.size(), total);

效果logs/chaoshi.log自动生成,记录每次结算时间、操作员、商品数、金额,便于事后审计。

5.3 离线模式兜底:H2 数据库嵌入式切换与同步机制

当网络中断时,MySQL 不可用。chaoshi需支持降级到本地 H2 数据库存储临时交易,待网络恢复后同步至 MySQL:

  1. 添加 H2 依赖h2-2.1.214.jar
  2. 修改DBUtil.javagetConnection()
    public static Connection getConnection() { String url = isOnline() ? "jdbc:mysql://localhost:3306/chaoshi?..." : "jdbc:h2:./data/chaoshi_offline;DB_CLOSE_DELAY=-1"; return DriverManager.getConnection(url, "sa", ""); }
  3. 设计同步任务
    启动时检查h2中是否存在未同步的offline_sales表记录,若有,则批量 INSERT 到 MySQL 的sales表,并清空h2表。

提示:H2 的jdbc:h2:./data/chaoshi_offline会在当前目录创建data/文件夹存储数据库文件,无需额外服务进程,真正实现“开箱即用”的离线能力。

最后一行不要总结。

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 5:01:00

基于SpringBoot+Vue的学生选课系统设计与实现——毕业设计完整解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 5:00:48

WeChatMsg 教程:4步导出微信聊天记录为HTML、Word、CSV并生成年度报告

WeChatMsg 教程&#xff1a;4步导出微信聊天记录为HTML、Word、CSV并生成年度报告 【免费下载链接】WeChatMsg 提取微信聊天记录&#xff0c;将其导出成HTML、Word、CSV文档永久保存&#xff0c;对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/GitHub_Tr…

作者头像 李华
网站建设 2026/9/12 5:00:29

Runway与小云雀选型指南:网文短剧AI生产范式决策

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 5:00:23

QT事件分发与过滤机制深度解析

1. QT事件分发与事件过滤机制解析在QT框架开发中&#xff0c;事件处理系统是整个GUI应用程序运行的核心机制。作为一套成熟完善的跨平台C框架&#xff0c;QT通过事件驱动模型实现用户交互响应&#xff0c;其事件处理流程主要包含事件生成、事件分发和事件过滤三个关键环节。理解…

作者头像 李华
网站建设 2026/9/12 4:57:14

西门子PLC在电镀生产线自动化改造中的应用

1. 项目背景与需求分析 电镀生产线作为表面处理行业的核心设备&#xff0c;其控制系统的稳定性直接决定了产品质量和生产效率。传统继电器控制方式存在线路复杂、故障率高、灵活性差等痛点&#xff0c;而采用西门子PLC进行自动化改造已成为行业主流方案。 这个项目要解决三个核…

作者头像 李华