尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
基于Java Socket与GUI的银行排号系统:多客户端并发与Oracle持久化实现
简介本资源为基于Java Socket与Java GUI实现的银行排号系统完整项目包面向计算机相关专业学生、Java初学者及需要完成课程设计或毕业设计的人群帮助解决排队叫号业务场景下的系统建模与网络通信实现问题。包内包含全套项目源码与完整文档源码经过测试校正可稳定运行适合作为项目设计参考或二次开发基础。压缩包为zip格式整体约292.61MB涵盖源码文件、说明文档等主要类型源码用于直接运行与调试文档则辅助理解系统架构与功能模块。目前已有475人学习下载具备一定参考热度。读者可获得一套可运行的银行排号系统实现方案涵盖Socket通信、GUI界面设计、叫号逻辑与数据管理等核心知识点同时配套文档有助于梳理项目结构、理解关键代码与排错思路适合用于课程实践、技能提升或项目答辩准备。1. 从一次银行网点取号说起这套 Java Socket 排号系统到底能跑通什么上个月帮一个做课程设计的朋友看他的银行排号系统打开工程一看客户端和服务端全塞在一个 main 方法里取号逻辑靠一个静态 List 硬扛两个窗口同时点“取号”就撞号。这不是个例很多同学做 Java Socket 网络编程 Java GUI 的课设时卡的不是界面画不出来而是“多客户端并发连上来之后号码怎么保证不重、队列怎么同步、窗口怎么实时刷新”这三件事。这份《基于 javaSocketJava GUI 的银行排号系统设计与实现源码文档》就是冲着这个场景来的服务端用 Socket 监听多个客户端连接客户端用 Java GUISwing/AWT 那一套做取号、叫号、窗口状态展示后台用 Oracle 存业务数据。它适合正在做 Java 课程设计、想找一个能跑通的 CS 架构网络编程范例、或者需要一份带完整文档的排号系统参考实现的人。下面我按“先看懂结构、再动手跑、最后避坑”的顺序把它拆开讲清楚。2. 拆开压缩包先看骨架Socket 通信层、GUI 层、Oracle 持久层怎么分工拿到源码别急着点运行先把工程目录和类职责理一遍。这套系统的核心不是界面多漂亮而是三层职责有没有分开Socket 负责网络传输GUI 负责交互展示Oracle 负责数据落地。分不清这三层后面改一个叫号逻辑就会牵一发动全身。2.1 服务端 ServerSocket 的监听与多线程接入模型服务端是整个系统的中枢。常见做法是主线程持有一个ServerSocket绑定固定端口然后在一个while(true)循环里accept()阻塞等待客户端连接每来一个客户端就丢给一个独立线程去处理这样多个取号机、多个窗口终端才能同时在线。// 服务端主监听一个端口多线程接入 public class BankServer { private static final int PORT 8888; // 在线客户端集合注意用线程安全容器 private static final ListClientHandler CLIENTS Collections.synchronizedList(new ArrayList()); public static void main(String[] args) throws IOException { ServerSocket serverSocket new ServerSocket(PORT); System.out.println(银行排号服务端已启动监听端口 PORT); while (true) { // 阻塞等待客户端接入每接入一个就开一条线程 Socket socket serverSocket.accept(); ClientHandler handler new ClientHandler(socket); CLIENTS.add(handler); new Thread(handler).start(); } } }这段代码里有两个参数值得盯住PORT是服务端对外暴露的端口客户端必须填一样的值否则连不上CLIENTS用Collections.synchronizedList包了一层是因为多个线程会同时往里加、删、遍历普通ArrayList在并发下会抛ConcurrentModificationException这是新手最容易翻车的地方。accept()本身是阻塞的所以主线程会一直停在这里等连接这是正常现象不是卡死。2.2 客户端 GUI 与 Socket 的绑定取号按钮背后发生了什么客户端这边Java GUI 负责把“取号”“叫号”“窗口状态”这些操作变成按钮和列表但按钮点下去真正干活的是 Socket 输出流。典型结构是界面初始化时先建立一条到服务端的Socket连接拿到输入输出流用户点“取号”时把请求按约定协议比如TAKE加业务类型写出去同时开一个后台线程专门readLine()监听服务端推回来的消息收到就刷新界面。// 客户端连接服务端并发送取号请求 public class BankClient { private Socket socket; private BufferedReader in; private PrintWriter out; public void connect(String host, int port) throws IOException { socket new Socket(host, port); in new BufferedReader(new InputStreamReader(socket.getInputStream())); out new PrintWriter(socket.getOutputStream(), true); // 后台线程持续接收服务端推送避免阻塞 GUI 事件线程 new Thread(this::listenServer).start(); } private void listenServer() { try { String msg; while ((msg in.readLine()) ! null) { // 收到消息后交给 GUI 刷新Swing 里要用 SwingUtilities final String text msg; SwingUtilities.invokeLater(() - updateUI(text)); } } catch (IOException e) { e.printStackTrace(); } } public void takeNumber(String bizType) { out.println(TAKE: bizType); // 协议动作 业务类型 } }这里的关键点是listenServer必须跑在独立线程里。如果你把readLine()直接写在按钮事件里界面会整个卡住因为 Swing 的事件分发线程被阻塞了。另外刷新界面时用SwingUtilities.invokeLater是 Swing 的规矩跨线程改组件必须回到事件线程不然会出现界面偶发不刷新甚至抛异常的玄学问题。协议用TAKE:业务类型这种简单字符串好处是调试时用 telnet 就能模拟坏处是没有长度校验后面避坑章节会讲。2.3 Oracle 侧的表结构与号码生成策略号码不能只存在内存里否则服务端一重启当天排的号全丢。常见做法是在 Oracle 里建两张核心表一张排队记录表一张窗口/业务类型配置表。号码生成有两种思路一种是靠数据库序列SEQUENCE一种是按业务类型当天最大号加一。前者简单但号码全局连续、不区分业务后者更贴近真实银行“每个业务单独排队”的体验但要注意并发下的锁。-- 排队记录表一条记录就是一张号票 CREATE TABLE QUEUE_TICKET ( TICKET_ID NUMBER PRIMARY KEY, BIZ_TYPE VARCHAR2(20), -- 业务类型个人/对公/理财 TICKET_NO NUMBER, -- 当天该业务下的排队号 STATUS VARCHAR2(10), -- WAITING / CALLING / DONE CREATE_TIME DATE DEFAULT SYSDATE, WINDOW_NO NUMBER -- 被哪个窗口叫走 ); -- 按业务类型取当天最大号用于生成下一个号 SELECT NVL(MAX(TICKET_NO), 0) 1 AS NEXT_NO FROM QUEUE_TICKET WHERE BIZ_TYPE ? AND TRUNC(CREATE_TIME) TRUNC(SYSDATE);TRUNC(CREATE_TIME) TRUNC(SYSDATE)这个条件是把时间截断到“天”保证号码每天从 1 重新开始这是银行排号的常规体验。NVL(MAX(...), 0) 1处理了当天第一个号的情况没有它第一张票会取到 null。要注意这个“查最大值再加一”的写法在并发下不是原子的两个窗口同时取号可能拿到同一个号正确做法是配合行级锁或直接用序列具体在避坑章节展开。3. 把工程跑起来JDK、Oracle 连接与客户端服务端启动顺序看懂结构之后就是动手。这套系统跑不起来八成不是代码问题而是环境和启动顺序没弄对。下面按我实际复现的顺序走一遍。3.1 JDK 与依赖环境确认先确认 JDK 版本。这类课设工程大多基于 JDK 8 编写用高版本 JDK比如 17编译时Swing 本身没问题但 Oracle 的 JDBC 驱动和某些旧写法可能报模块访问警告甚至错误。稳妥做法是先用 JDK 8 跑通再考虑升级。# 确认当前 JDK 版本 java -version javac -version # 如果机器上有多个 JDK临时切到 8 export JAVA_HOME/path/to/jdk1.8.0_xxx export PATH$JAVA_HOME/bin:$PATHjava -version输出里如果看到1.8.0_xxx就是 JDK 8。JAVA_HOME指向 JDK 根目录而不是 bin 目录这是很多人配环境时踩的坑指错了javac就找不到。Oracle 的 JDBC 驱动 jar常见是ojdbc8.jar或对应版本要放进工程的 classpathEclipse/IDEA 里就是加到 Build Path 或 lib 目录。3.2 Oracle 连接配置与监听服务排查Oracle 这边最容易出问题的是连接串和监听服务。连接串典型格式是jdbc:oracle:thin:主机:端口:服务名端口默认 1521服务名要和你本地建库时的一致。// 数据库连接工具类片段 public class DBUtil { private static final String URL jdbc:oracle:thin:127.0.0.1:1521:ORCL; private static final String USER bank; private static final String PWD bank123; public static Connection getConnection() throws SQLException { // 加载驱动老版本 Oracle 驱动类名是 oracle.jdbc.driver.OracleDriver return DriverManager.getConnection(URL, USER, PWD); } }URL里的ORCL是服务名SID必须和你tnsnames.ora或建库时设置的一致写错了会报ORA-12505。USER和PWD是你在 Oracle 里为这个系统单独建的用户别直接用 sys/system 跑业务。如果连不上先在命令行用lsnrctl status看监听服务起没起监听没起的话任何 Java 代码都连不上这跟代码无关。3.3 启动顺序与首次运行验证启动顺序不能乱先起 Oracle 监听和数据库再起服务端最后起客户端。服务端没起就开客户端客户端new Socket()会直接抛ConnectException。# 1. 确认 Oracle 监听已启动 lsnrctl status # 2. 编译服务端与客户端假设源码在 src 下 javac -encoding UTF-8 -d out -cp lib/ojdbc8.jar src/server/*.java src/client/*.java # 3. 先启动服务端 java -cp out;lib/ojdbc8.jar server.BankServer # 4. 再启动客户端可开多个窗口模拟多台取号机 java -cp out;lib/ojdbc8.jar client.BankClientWindows 下 classpath 分隔符是分号;Linux/Mac 下是冒号:这是跨平台跑时最常见的翻车点。验证是否跑通就看客户端点“取号”后服务端控制台有没有打印接入日志、Oracle 的QUEUE_TICKET表里有没有新增记录、界面上的排队列表有没有实时刷新。三个都对上说明整条链路通了。4. 避坑与排查并发取号、界面卡死、连接串写错这些坑我都踩过这套系统能跑通不代表能扛住真实使用下面几条是我复现和帮人排查时反复遇到的按“现象 → 原因 → 解决”记下来。4.1 两个窗口同时取号拿到同一个号码现象开两个客户端几乎同时点取号Oracle 里出现两条TICKET_NO相同的记录。原因SELECT MAX(TICKET_NO)1和INSERT是两步操作中间没有锁两个线程都读到了同一个最大值。解决要么在查询时加FOR UPDATE锁住相关行要么把号码生成收敛到服务端单线程里做客户端只发请求不自己算号。我一般倾向后者服务端用一个专门的取号方法串行处理简单可靠。4.2 界面点一下卡半天按钮像失灵现象客户端点“取号”后界面无响应过几秒才恢复。原因把readLine()或数据库查询写在了 Swing 事件线程里阻塞了界面刷新。解决所有可能阻塞的操作网络读写、数据库访问都放到独立线程界面更新统一用SwingUtilities.invokeLater回到事件线程。记住一条Swing 事件线程里只做轻量操作。4.3 报 ORA-12505 或连接直接被拒现象服务端一启动就抛数据库连接异常提示监听程序无法识别服务名。原因连接串里的 SID/服务名写错或者 Oracle 监听服务根本没起。解决先用lsnrctl status确认监听状态再核对连接串里的服务名与tnsnames.ora是否一致。这一步跟 Java 代码无关别在代码里反复改。4.4 端口被占用导致服务端起不来现象服务端启动报Address already in use或者 Windows 下提示“通常每个套接字地址只允许使用一次”。原因8888 端口被别的程序占了或者上一次的服务端进程没退干净。解决换一个端口或者用netstat -ano | findstr 8888找到占用进程结束掉。开发阶段端口冲突很常见养成启动前先查一下的习惯。4.5 中文乱码界面和数据库里都是问号现象客户端显示的中文变成乱码Oracle 里存进去的也是乱码。原因Socket 流和数据库字符集编码不一致InputStreamReader没指定编码。解决InputStreamReader和PrintWriter显式指定UTF-8同时确认 Oracle 数据库字符集支持中文。编码问题不统一后面查起来非常痛苦一开始就定死 UTF-8。5. 进阶用法把排号系统从“能跑”推到“像样”的几个具体技巧跑通只是起点这套源码真正有价值的地方在于它是个可以继续改的骨架。下面几个技巧是我在实际改这个系统时会用的能让它从课设水平往实用靠一靠。第一个是协议升级。现在用TAKE:业务类型这种裸字符串字段一多就难维护也容易因为消息里带冒号而解析错。可以换成简单的 JSON或者至少用固定分隔符加字段校验。改的时候注意服务端和客户端要同步改不然一边发一边收对不上排查起来就是黑匣子。// 用 JSON 组织请求字段清晰、易扩展 // 依赖一个轻量 JSON 库比如 fastjson 或 gson JSONObject req new JSONObject(); req.put(action, TAKE); req.put(bizType, PERSONAL); req.put(clientId, clientId); out.println(req.toJSONString());第二个是号码状态机。现在STATUS只有 WAITING/CALLING/DONE实际用起来还需要“过号”“重呼”。加状态时一定要在服务端统一校验流转合法性比如 DONE 的号不能再被叫否则界面会显示错乱。状态流转集中在一处判断比散落在各个按钮事件里可靠得多。第三个是断线重连。客户端网络抖一下 Socket 就断了界面还停在旧状态。可以在listenServer捕获异常后隔几秒尝试重连并把当前排队状态重新拉一遍。重连逻辑要防止无限快速重试加个退避间隔。改造点现状建议做法注意通信协议裸字符串JSON 或带校验的分隔格式两端同步改号码生成查最大值加一服务端串行生成或加锁并发下必须原子状态管理三状态增加过号/重呼流转集中校验网络容错断线即失效退避重连 状态重拉防止快速重试第四个是日志。服务端把每个客户端的接入、请求、断开都打上时间戳记下来出问题时不用靠猜。我一般会在ClientHandler里统一记日志而不是散在各处System.out.println。日志级别分一下正常请求用 info异常用 error排查时按级别过滤。最后说个验证方法改完任何一处别只看界面一定去 Oracle 里SELECT一下对应记录确认数据真的落对了。界面会骗人数据库不会。从那以后我每次改完排号逻辑都强制走一遍“两个客户端同时取号 查库核对号码唯一性”的流程这个习惯帮我挡掉了好几次并发问题。希望帮到你。本文还有配套的精品资源点击获取
RELATED

相关推荐

Gemma 4与BOTANIC-1协同实现植物DNA解析自动化

Gemma 4与BOTANIC-1协同实现植物DNA解析自动化

1. 这不是又一个“AI生物”的概念炒作:Gemma 4 与 BOTANIC-1 的真实协同逻辑你可能已经刷到过类似标题:“AI大模型进军农业”“植物基因组迎来革命性突破”。但这次不一样。我上个月在加州一个小型植物表型实验室里,亲眼看着一台配置普通的工…

📅 2026/10/9 6:47:29
智慧养老系统设计与实现:健康告警、求助与工单闭环实战复盘

智慧养老系统设计与实现:健康告警、求助与工单闭环实战复盘

说实话,毕设选题那会儿我纠结了很久。身边同学不是做商城就是做图书管理,看起来一套套的,但答辩时撞车概率极高,而且很难讲出真正的业务价值。导师给我指了个方向——智慧养老系统设计与实现,起初我心里也犯嘀咕&#…

📅 2026/10/9 6:42:28
Java List集合深度解析:从ArrayList到LinkedList的性能取舍与实战避坑

Java List集合深度解析:从ArrayList到LinkedList的性能取舍与实战避坑

前两天帮一个同事排查线上问题,现象是接口偶尔报超时,重启之后又正常。翻完代码,发现问题出在一个ArrayList上:他为了保持数据的某种顺序,在列表的中间位置循环执行insert操作,几万条数据叠下来&#xff0c…

📅 2026/10/9 6:42:28
MORE NEWS

更多资讯

📰

向量数据库工程实践:从选型、分层架构到线上调优

1. 这不是一篇“论文模板”,而是一份系统架构师的实战手记向量数据库——这个词在2024年之后已经从AI工程师的私密工具箱,变成了系统架构师方案评审会上被反复点名的关键词。我参与过三个不同规模的智能检索系统重构项目,其中两个在立项阶段就…

📰

MCGS6.2仿真程序负责人登录密码清除与重置实操指南

咱们搞自控这块儿的,谁手里没几个昆仑通泰的工程。前阵子接了个燃气锅炉热力系统的仿真维护项目,全是老活儿,用的还是MCGS6.2这个老版本。甲方拿过来的电脑上装好了仿真程序,运行环境一启动就弹出“负责人登录”的密码框&#xff…

📰

实时性即竞争力:物联网数据处理的五次代际跃迁

👨‍🎓博主简介 🏅CSDN博客专家   🏅云计算领域优质创作者   🏅华为云开发者社区专家博主   🏅阿里云开发者社区专家博主 💊交流社区:运维交流社区 欢迎大家的加入&#xff01…

📰

Python PDF处理实战:四大主流库选型与文本表格提取指南

1. PDF处理这个领域,Python工具箱里到底该选谁处理PDF这件事,很多人第一次接触时都以为很简单,打开文档复制粘贴就行。等到真上手跑一个批量脚本,才发现问题全冒出来了:文本抽出来是乱的、表格对不上、加密文档打不开、…

📰

从CPU超线程到线程池:队列与反压机制的底层逻辑

开篇聊个我踩过的坑。去年调一个线上接口,监控显示线程池活跃线程数打满,阻塞队列里堆了两万多条任务,接口响应从50ms涨到2s。我第一反应就是加线程数,从8个加到16个,结果更慢了,CPU直接红了,任…

📰

C# WebSocketServer 源码实战:从跑通到扛住并发

简介:这份C# WebSocketServer服务器源代码压缩包,面向具备一定.NET基础、希望深入理解实时双向通信原理的开发者,尤其适合正在学习网络编程或需要搭建聊天类实时应用的技术人员。包内共18个文件,以10个cs源码文件为核心&#xff0…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬