news 2026/10/8 2:59:50

Java毕业设计电费管理系统:从技术选型到并发抄表与答辩避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java毕业设计电费管理系统:从技术选型到并发抄表与答辩避坑指南

简介:这是一份面向高校计算机专业毕业设计场景的Java电费管理系统完整源码包,适合正在准备毕设或需要Java全栈实战练习的学生参考。系统围绕居民小区与企业电费管理展开,涵盖用户管理、电费计算、在线缴费、数据统计与缴费提醒等核心模块,采用Spring Boot结合MyBatis构建后端,MySQL存储数据,前端使用HTML5、CSS3与JavaScript,并集成Spring Security与JWT保障安全,整体遵循MVC分层设计。压缩包共158个文件,约1.78MB,其中52个java文件承载业务逻辑与接口实现,24个js、19个html与14个css构成前端页面与交互样式,另有xml配置、字体图标及少量properties、json等资源文件,结构完整便于二次开发。目前已有115人学习下载,可作为毕设选题参考、课程设计模板或Java Web综合练习素材,帮助读者理解电费计费算法、权限控制与报表生成等实现思路。

1. 电费管理系统毕业设计:从能跑起来到能讲清楚

很多同学拿到「毕业设计电费管理系统(java).zip」这类压缩包时,第一反应是解压、找 main 方法、点运行,然后发现数据库连不上、依赖下载失败、页面 404,最后只能硬着头皮改到能跑,答辩时被问「你这个系统怎么保证多用户同时抄表不重复计费」就卡住了。这个标题背后其实是一套典型的 Java Web 业务系统:用户管理、电表台账、抄表记录、阶梯电价计算、缴费流水、统计报表。它适合计算机、软件工程、电子信息工程等专业的本科毕业生,也适合刚学完 Java 基础、想找一个完整项目练手的初级开发者。真正要解决的不是「怎么把压缩包跑起来」,而是「怎么在有限时间里把业务逻辑讲清楚、把数据一致性守住、把答辩问题接住」。下面按落地顺序拆开讲。

2. 先定技术栈再动手:Spring Boot + MyBatis-Plus 的最小可运行骨架

2.1 为什么这套组合是毕业设计的稳妥选择

毕业设计的时间通常只有 8 到 12 周,其中还要写论文、做答辩 PPT。技术选型的第一原则不是「先进」,而是「资料多、报错能搜到、导师看得懂」。Spring Boot 把 Tomcat 内嵌、自动配置、起步依赖都封装好了,MyBatis-Plus 在 MyBatis 基础上提供了单表 CRUD 的默认实现,省掉大量 XML 映射文件。常见做法是:Spring Boot 2.7.x 或 3.x 搭配 MyBatis-Plus 3.5.x,MySQL 8.0,前端用 Thymeleaf 或 Vue 加 Element UI。如果导师明确要求用 JSP,那就用 JSP,不要为了「技术新」去赌答辩风险。

这里有一个容易被忽略的点:热词里出现「mybatisplus根据java实体类生成创建表的sql语句」,说明很多人希望减少手写建表语句的工作量。MyBatis-Plus 本身不直接生成 DDL,但可以通过读取实体类的@TableName、@TableField注解,配合自定义代码生成器或简单的反射工具输出建表 SQL。毕业设计里可以写一个TableSqlGenerator工具类,在测试阶段跑一次,把生成的 SQL 贴进schema.sql,既省时间又能在论文里写「基于元数据的建表脚本自动生成」。

2.2 从零搭建可运行骨架的四个步骤

第一步,创建 Spring Boot 项目。用 IDEA 的 Spring Initializr,勾选 Spring Web、MyBatis-Plus、MySQL Driver、Lombok。如果网络环境导致依赖下载慢,在settings.xml里配置国内镜像,这是环境配置阶段最常见的卡点。

第二步,配置数据源。在application.yml里写清楚 JDBC URL、用户名、密码,并开启 MyBatis-Plus 的 SQL 日志,方便调试。

spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/electric_bill?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 123456 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: id-type: auto logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0

这段配置里,serverTimezone必须写,否则 MySQL 8 会报时区错误;logic-delete-field是逻辑删除,电费系统里用户和电表都不建议物理删除,保留历史数据对统计报表很重要。

第三步,写实体类和 Mapper。以电表为例:

@Data @TableName("t_meter") public class Meter { @TableId(type = IdType.AUTO) private Long id; private String meterNo; private Long userId; private BigDecimal initialReading; private Integer status; @TableLogic private Integer deleted; }

@TableLogic配合全局配置,查询时自动追加deleted = 0,删除时变成update set deleted = 1。这个细节在答辩时如果被问到「删除用户后历史缴费记录怎么办」,可以回答「逻辑删除保留关联数据,报表统计不受影响」。

第四步,写一个 Controller 验证链路:

@RestController @RequestMapping("/meter") public class MeterController { @Autowired private MeterMapper meterMapper; @GetMapping("/list") public List<Meter> list() { return meterMapper.selectList(null); } }

启动后访问http://localhost:8080/meter/list,能看到 JSON 数据,说明 Spring Boot、MyBatis-Plus、MySQL 三层已经打通。这一步跑通之前,不要急着写业务逻辑,否则报错时很难定位是配置问题还是代码问题。

3. 电费计算与抄表业务:阶梯电价、并发抄表和账单生成

3.1 阶梯电价的计算模型怎么落到代码里

电费管理系统的核心是计费。居民阶梯电价通常按月分档:第一档 0 到 180 度,单价 0.5 元;第二档 181 到 280 度,单价 0.55 元;第三档 280 度以上,单价 0.8 元。注意第二档和第三档的单价通常是对超出部分加价,不是全量加价。常见做法是把计费规则配置在数据库表t_price_rule里,而不是硬编码在 Java 中,这样答辩时可以说「规则可配置,适应不同地区政策调整」。

public BigDecimal calculateFee(BigDecimal usage, List<PriceRule> rules) { BigDecimal total = BigDecimal.ZERO; BigDecimal remaining = usage; for (PriceRule rule : rules) { if (remaining.compareTo(BigDecimal.ZERO) <= 0) break; BigDecimal upper = rule.getUpperLimit(); BigDecimal inThisTier = remaining.min(upper.subtract(rule.getLowerLimit())); total = total.add(inThisTier.multiply(rule.getUnitPrice())); remaining = remaining.subtract(inThisTier); } return total.setScale(2, RoundingMode.HALF_UP); }

参数说明:usage是本月用电量,由本次抄表读数减去上次抄表读数得到;rules按档位顺序排列;setScale(2)保留两位小数,金额计算必须用BigDecimal,用double会出现 0.1 + 0.2 不等于 0.3 的经典问题,答辩时被问到就是送分题。

3.2 抄表记录的并发安全与账单生成

抄表员在移动端提交读数时,可能同时有多个人操作同一块电表,或者网络重试导致重复提交。如果直接insert抄表记录再更新电表读数,会出现重复计费。血泪经验是:在t_meter表上加一个version字段做乐观锁,或者用update t_meter set last_reading = #{newReading}, version = version + 1 where id = #{id} and version = #{oldVersion},根据影响行数判断是否成功。

@Transactional(rollbackFor = Exception.class) public void submitReading(Long meterId, BigDecimal newReading, Integer oldVersion) { Meter meter = meterMapper.selectById(meterId); if (meter == null) throw new BizException("电表不存在"); if (newReading.compareTo(meter.getLastReading()) < 0) { throw new BizException("本次读数不能小于上次读数"); } int rows = meterMapper.updateReadingWithVersion(meterId, newReading, oldVersion); if (rows == 0) throw new BizException("数据已被他人修改,请刷新后重试"); Reading reading = new Reading(); reading.setMeterId(meterId); reading.setReadingValue(newReading); reading.setReadingTime(LocalDateTime.now()); readingMapper.insert(reading); billService.generateBill(meterId, newReading.subtract(meter.getLastReading())); }

逻辑说明:先校验读数不能回退,再用乐观锁更新电表当前读数,更新成功后插入抄表记录,最后生成账单。@Transactional保证三步要么全成功要么全回滚。如果并发冲突,前端提示用户刷新,而不是静默失败。这个设计在答辩时能直接回应「怎么保证数据一致性」的问题。

账单生成时要注意:同一个抄表周期内不能重复生成账单。可以在t_bill表上加唯一索引(meter_id, period),插入冲突时捕获异常并提示「本期账单已生成」。这比先查后插更可靠,因为查和插之间仍有并发窗口。

4. 避坑与排查:毕业设计电费系统最常见的五个翻车点

4.1 数据库连不上,报 Public Key Retrieval is not allowed

现象:启动时抛com.mysql.cj.jdbc.exceptions.CommunicationsException,提示Public Key Retrieval is not allowed。原因:MySQL 8 默认使用caching_sha2_password认证插件,JDBC 连接串没有允许公钥检索。解决:在 URL 后加allowPublicKeyRetrieval=true&useSSL=false,仅限本地开发环境,生产环境应配置 SSL 证书。

4.2 前端页面 404,静态资源加载失败

现象:Controller 能返回 JSON,但访问index.html报 404,或者 CSS、JS 加载不出来。原因:Spring Boot 默认静态资源放在src/main/resources/static下,如果用了 Thymeleaf,模板要放在templates下;如果用了 Vue 打包,dist目录要放到static下并配置好路由。解决:先确认文件位置,再检查application.yml里有没有配spring.mvc.static-path-pattern和spring.web.resources.static-locations。常见误用是把 JSP 放在templates下,JSP 需要额外配prefix和suffix。

4.3 金额计算出现 0.30000000000000004

现象:电费合计和手工算的对不上,差几分钱。原因:用了double或float做金额运算。解决:所有金额字段用BigDecimal,数据库用decimal(10,2),Java 里用new BigDecimal("0.5")而不是new BigDecimal(0.5)。除法必须指定精度和舍入模式,否则BigDecimal也会抛ArithmeticException。

4.4 逻辑删除后唯一索引冲突

现象:删除了一个电表,再新增相同表号的电表,报唯一索引冲突。原因:逻辑删除只是把deleted置为 1,数据库里那条记录还在,唯一索引仍然生效。解决:把唯一索引改成(meter_no, deleted)联合唯一,或者删除时把meter_no改写成meter_no + '_del_' + id。前者更干净,但要注意deleted只有 0 和 1,同一表号最多只能有一条删除记录,如果反复删除同一表号仍会冲突,所以更稳妥的是后者。

4.5 答辩时被问「你的系统并发能力怎么样」

现象:演示时一切正常,答辩老师问「1000 个用户同时缴费会不会超卖」。原因:没有准备并发相关的回答。解决:不要吹牛说支持高并发,而是诚实回答「当前是单机部署,缴费接口用了数据库行锁和唯一索引防止重复扣款,如果要做高并发需要引入消息队列削峰和分布式锁」。然后可以补充「我在抄表模块用了乐观锁,这是我在这个项目里实际处理的并发场景」。诚实且有细节,比背八股文得分高。

5. 让系统经得起追问:用接口测试和 SQL 审计验证核心链路

5.1 用 Postman 或 curl 跑通缴费全流程

答辩前一定要自己把「新增用户 → 新增电表 → 抄表 → 生成账单 → 缴费 → 查询余额」这条链路完整跑一遍,并且用接口测试工具留下记录。下面是一组 curl 命令,可以直接复制到终端执行:

# 新增用户 curl -X POST http://localhost:8080/user/add \ -H "Content-Type: application/json" \ -d '{"name":"张三","phone":"13800000000","address":"1号楼101"}' # 新增电表,假设用户 id 返回为 1 curl -X POST http://localhost:8080/meter/add \ -H "Content-Type: application/json" \ -d '{"meterNo":"M2026001","userId":1,"initialReading":1000}' # 抄表,假设电表 id 为 1,上次读数 1000,本次 1200 curl -X POST http://localhost:8080/reading/submit \ -H "Content-Type: application/json" \ -d '{"meterId":1,"newReading":1200,"oldVersion":0}' # 查询账单 curl http://localhost:8080/bill/list?meterId=1 # 缴费 curl -X POST http://localhost:8080/payment/pay \ -H "Content-Type: application/json" \ -d '{"billId":1,"amount":110.00}'

跑完后去数据库里核对:t_reading有没有多出一条,t_bill的金额是不是 200 度电按阶梯算出来的 110 元(180×0.5 + 20×0.55 = 90 + 11 = 101,这里只是示例,实际按你的规则算),t_meter的last_reading有没有更新成 1200。如果对不上,优先查事务有没有生效、@Transactional是不是加在 public 方法上、异常是不是被 catch 后没抛出。

5.2 用 SQL 审计确认没有全表扫描和重复数据

在 MySQL 里开慢查询日志,或者直接对核心表跑explain:

EXPLAIN SELECT * FROM t_bill WHERE meter_id = 1 AND period = '2026-03';

如果type是ALL,说明没走索引,数据量大了会慢。给t_bill加(meter_id, period)联合索引。再查重复账单:

SELECT meter_id, period, COUNT(*) FROM t_bill GROUP BY meter_id, period HAVING COUNT(*) > 1;

这条语句返回空,说明唯一约束或业务逻辑生效了。答辩时如果老师问「你怎么保证不重复计费」,可以直接把这个查询结果展示出来,比口头解释有说服力。

5.3 一个我踩过的坑:别在答辩前一天换技术栈

我见过也经历过,有人觉得 Thymeleaf 太老,答辩前三天换成 Vue 前后端分离,结果跨域、登录态、打包路径全出问题,最后演示时页面白屏。毕业设计的首要目标是顺利通过,不是技术炫技。如果时间充裕,可以在论文的「未来改进」里写「前端可升级为 Vue3 + Element Plus,后端提供 RESTful 接口」,但不要在交付前动主干。另一个习惯是:每完成一个模块就git commit一次,压缩包里的代码和数据库脚本分开存放,schema.sql和data.sql放在resources下,换一台电脑也能快速恢复环境。希望帮到你。

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

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

机器学习生产部署最佳实践:Snowflak全链路路径解析

做机器学习生产部署这件事&#xff0c;我踩过不少坑。Snowflak 这个项目&#xff0c;就是我把这几年在模型上线、服务化、监控治理里踩过的坑&#xff0c;重新整理成的一套可复用路径。它不是某个惊艳算法&#xff0c;也不是一座庞大平台&#xff0c;而是一个把生产链路变得透明…

作者头像 李华
网站建设 2026/10/8 2:58:46

华为语音交换机IAD配置手册:从开箱到放号的完整路径

简介&#xff1a;这份华为语音交换机IAD配置手册源自官方光盘资料&#xff0c;面向从事企业语音组网、VoIP部署与运维的工程师及技术学习者&#xff0c;用于解决IAD设备开局配置、业务调试与故障排查等实际问题。压缩包共114个文件&#xff0c;约19.89MB&#xff0c;以xml配置文…

作者头像 李华
网站建设 2026/10/8 2:58:22

本地AI会话数据清理:从SQLite到向量库的可控工程实践

上个月我打开本地部署的AI Web界面&#xff0c;想找回两周前调prompt时记下的一段系统提示词&#xff0c;结果会话列表已经滚了几百条&#xff0c;翻了三分钟才找到。顺手看了一眼数据目录&#xff0c;好家伙——5.8GB。也就是从那天起&#xff0c;我意识到“本地AI会话越积越多…

作者头像 李华
网站建设 2026/10/8 2:57:11

基于TPS259483与PIC24EP的电源路径保护系统设计

前阵子做一块工业控制器&#xff0c;24V供电&#xff0c;带了好几路外设模块&#xff0c;热插拔、容性负载、短路这些都躲不开。最开始只是用一个PMOS加限流电阻做防反和过流&#xff0c;结果调试时一个接口插错&#xff0c;直接把板上的DC-DC前端烧了&#xff0c;从那以后就对…

作者头像 李华
网站建设 2026/10/8 2:57:00

Axure多角色登录原型:全局变量+动态面板+条件判断实战

上周给一个后台产品做原型评审&#xff0c;老板指着登录后的首页问&#xff1a;“这个页面&#xff0c;管理员和运营看到的怎么一模一样&#xff1f;”我承认当时偷了懒&#xff0c;三个角色共用了一套页面。会议室的气氛一下就变了&#xff0c;从“看原型”变成了“讨论权限边…

作者头像 李华
网站建设 2026/10/8 2:56:48

Allegro Skill实战:从零教你快速抓取与写入PCB设计数据

干PCB设计这行的人&#xff0c;电脑里几乎都装着Cadence Allegro&#xff0c;但真正把Allegro用出效率差的&#xff0c;往往是那些会写Skill脚本的人。前阵子有朋友问我&#xff1a;“你整天说Allegro Skill能抓取数据、写回软件&#xff0c;到底是怎么个抓法、写法&#xff1f…

作者头像 李华