ARTICLE DETAIL

资讯详情

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

SSH架构Java Web用电管理系统实战解析

SSH架构Java Web用电管理系统实战解析 简介本资源是一份面向信息管理与信息系统专业本科生的毕业设计文档聚焦应县供电公司实际业务场景系统性完成小区用电管理系统的分析、设计与实现。论文覆盖需求分析含数据流图与模块划分、系统实现含逻辑/物理架构及核心功能模块详解用户管理、抄表管理、电费计算、统计查询与客户服务并附有界面截图与功能说明可为同类电力信息化项目提供完整参考范式。资源为单文件Word文档.doc格式大小1.92MB结构清晰含目录、引言、各章节详述及开发环境说明便于快速查阅与复用。目前已有57人学习下载适合高校相关专业学生开展课程设计、毕业设计选题参考或基层供电单位信息化建设人员了解小型用电管理系统的技术路径与落地要点。1. 应县供电公司小区用电管理系统毕业论文一份真实可复现的 Java Web 毕业级工程实践文档这不是一份“模板套用、截图拼凑”的空壳论文而是一份2012 年实打实跑在 Tomcat 6 Eclipse 3.3 Access 数据库上的 B/S 架构用电管理系统的完整设计与实现记录。它解决的是当时基层供电单位最痛的三个现实问题抄表员反复上门却常吃闭门羹、用户查历史电费要翻纸质台账、物业和供电所之间数据不同步导致分摊纠纷。系统用 Struts2 做控制器、Spring 管 IOC 和事务、Hibernate 封装 JDBC——这三者合称 SSH不是网络协议是当年 Java EE 主流分层架构不是概念堆砌而是真在WebRoot/WEB-INF/lib下放了struts2-core-2.1.6.jar、spring-core-2.5.6.jar、hibernate-core-3.3.1.GA.jar这些带时间戳的 jar 包。论文里每张数据库表结构Users、Electricity、UnitPrice、每个 Action 类LoginAction.java、CalElAction.java、甚至filters/LoginInterceptor.java的拦截逻辑都对应着真实可编译、可部署、可登录的代码。如果你正卡在毕业设计选题、Java Web 课程设计没头绪、或者想拆解一个“非 Spring Boot 时代”的经典三层架构项目——这份文档就是你缺的那块拼图它不讲云原生不谈微服务但把 MVC 怎么分、DAO 怎么写、事务怎么配、权限怎么拦全摊开在你眼前。新手能照着建库、配环境、跑起来老手能从中抠出 Hibernate 二级缓存配置缺失的隐患、Access 作为生产数据库的致命短板、以及 Struts2 标签库在 IE6 下的兼容玄学。2. SSH 架构落地为什么选 Struts2SpringHibernate 而不是直接上 Spring Boot2.1 2012 年的技术语境决定了选型不是“落后”而是“务实”现在回看Spring Boot 是 2014 年才发布的而这篇论文完成于 2012 年 5 月。当时主流 Java Web 开发的“黄金三角”就是 SSHStruts2 提供清晰的请求路由和表单绑定Spring 解决对象生命周期管理和声明式事务Hibernate 屏蔽 JDBC 细节。论文里明确写着“采用 SSH 系统架构模式……大大降低了系统模块间的依赖性”这不是套话——它直指当时痛点手工 new Service、手动 commit/rollback、SQL 字符串拼接满天飞。SSH 的价值在于把“谁创建对象”、“谁管数据库连接”、“谁决定事务边界”这三个问题从程序员手里交给了框架。比如UsersService.java里一个方法public void addUser(Users user) { usersDAO.save(user); // DAO 层只管 CRUD }这个usersDAO不是new UsersDAOImpl()得来的而是 Spring 在applicationContext.xml里配置好后注入进来的bean idusersService classservice.UsersService property nameusersDAO refusersDAOImpl/ /bean bean idusersDAOImpl classorm.UsersDAOImpl/提示这种 XML 配置方式现在看很重但在没有注解驱动的年代它是唯一能解耦的方式。refusersDAOImpl这行代码就是当年“控制反转IoC”最朴素的体现——Service 不再关心 DAO 怎么来只管用。2.2 分层职责必须划清WebRoot、controller、service、orm、common、filters 六大包的真实作用论文第 3.3 节提到“代码包结构如图 3.12 所示”这张图虽未附上但文字描述极其扎实。我们按实际开发逻辑还原其分工包名核心职责关键文件示例技术要点说明WebRoot纯视图层JSP 页面、CSS、JS、图片login.jsp,userList.jsp,calEl.jsp所有页面通过s:form、s:textfield等 Struts2 标签与 Action 绑定s:iterator遍历 Lists:if控制权限显示controllerMVC 的 CController接收请求、调用 Service、返回结果LoginAction.java,CalElAction.java,ExportExcelAction.java继承ActionSupport重写execute()Override public String execute()返回success或error字符串由struts.xml映射跳转路径service业务逻辑层组合 DAO、处理规则、管理事务UsersService.java,ElectricityService.java,UnitPriceService.java方法上加TransactionalSpring 注解或在 XML 中配置tx:advice电费计算逻辑梯度计费在此实现而非 DAO 层orm数据访问层实体类映射、SQL 封装、Session 管理Users.java,Electricity.java,UsersDAOImpl.java,PageDAO.javaUsers.java用Entity若用注解或Users.hbm.xml映射PageDAO.java手写 HQL 分页查询因 Hibernate 3.3 不支持setFirstResult()/setMaxResults()的链式调用common跨层工具类全局配置、通用功能HibernateSessionFactory.java,CreateLinechart.javaHibernateSessionFactory封装Configuration.buildSessionFactory()CreateLinechart.java调用 JFreeChart 生成统计图输出为 PNG 流filters安全拦截层登录校验、权限过滤LoginInterceptor.java实现Interceptor接口intercept()方法中检查ActionContext.getContext().getSession().get(user)是否存在不存在则跳转 login这种分层不是为了炫技而是为了解决协作问题。比如抄表员录入数据时MRAction.javaMeter Reading Action只负责接收表单参数、调用ElectricityService.addRecord()而电费计算规则0~50 度单价 X 元51~100 度单价 Y 元…全部封装在ElectricityService.calculateCost()里。如果电价政策调整改一个 service 方法即可不用动 JSP、不用改 DAO。2.3 梯度电费计算一个被论文轻描淡写、实则最易翻车的核心业务逻辑论文 3.2.3 节说“管理员按 0~50 度50~100 度150~200 度四个梯度进行定价”但没给出具体算法。我们从CalElAction.java和ElectricityService.java的上下文反推其实现这是毕业设计常见做法核心逻辑藏在代码里论文只写结论// ElectricityService.java 中的 calculateCost 方法伪代码 public double calculateCost(double amount, ListUnitPrice prices) { // prices 从数据库查出含 price0~price4 五个字段 UnitPrice currentPrice prices.get(0); // 取最新一条单价记录 double cost 0.0; if (amount 50) { cost amount * currentPrice.getPrice0(); } else if (amount 100) { cost 50 * currentPrice.getPrice0() (amount - 50) * currentPrice.getPrice1(); } else if (amount 150) { cost 50 * currentPrice.getPrice0() 50 * currentPrice.getPrice1() (amount - 100) * currentPrice.getPrice2(); } else if (amount 200) { cost 50 * currentPrice.getPrice0() 50 * currentPrice.getPrice1() 50 * currentPrice.getPrice2() (amount - 150) * currentPrice.getPrice3(); } else { // 超过 200 度部分论文未定义但代码必须处理——此处按 price4 计算 cost 50 * currentPrice.getPrice0() 50 * currentPrice.getPrice1() 50 * currentPrice.getPrice2() 50 * currentPrice.getPrice3() (amount - 200) * currentPrice.getPrice4(); } return Math.round(cost * 100.0) / 100.0; // 保留两位小数 }注意这个算法的关键在于prices必须是按时间倒序取的第一条ORDER BY stime DESC LIMIT 1否则会用错历史单价。而论文表 3.3 中Unitprice表的stime字段类型是varchar2(20)Oracle 风格但实际用的是 Access所以存储格式应为2012-05-01。如果存成01/05/2012排序就会错乱——这是当年 Access 字符串排序的典型坑。3. 数据库与物理部署Access 作为生产库的血泪经验与补救方案3.1 表结构设计从 E-R 图到 Access .mdb 文件的落地细节论文表 3.1–3.4 给出了四张核心表的字段定义但 Access 的实际建表需注意三点主键自增Access 中Uid、Eid、id字段类型应设为AutoNumber而非int。AutoNumber才能保证插入时不填值自动递增。文本长度限制varchar2(60)在 Access 中对应Text类型最大长度 255 字符但需在字段属性里手动设Field Size 60否则默认 255 会浪费空间。浮点精度float(10,2)在 Access 中用Currency类型替代Currency固定 4 位小数比Double更精确且避免0.10.20.30000000000000004的浮点误差——电费计算对精度零容忍。建库 SQLAccess 不支持标准 DDL需用 GUI 或 DAO 创建但逻辑等价-- Users 表Access 中实际名为 Users CREATE TABLE Users ( Uid AUTOINCREMENT PRIMARY KEY, Uname TEXT(60), Utel TEXT(50), Utime TEXT(20), -- 存 2012-03-15 08:30:00 Uaddress TEXT(100), Uauthority TEXT(20) ); -- Electricity 表关键Uaddress 是外键但 Access 不强制外键约束靠代码保证 CREATE TABLE Electricity ( Eid AUTOINCREMENT PRIMARY KEY, Uaddress TEXT(100), -- 关联 Users.Uaddress非 Uid论文此处设计有歧义 Etime TEXT(20), Ecost CURRENCY, Eamount DOUBLE );注意论文表 3.2 中Electricity表的外键是Uaddress住址而非Uid编号。这是为简化设计——避免 Join 查询直接用住址字符串关联。但隐患极大如果用户搬家Users.Uaddress改了Electricity.Uaddress不同步历史电费就查不到。真实项目必须用Uid作为外键Uaddress仅作冗余展示。3.2 开发与运行环境硬件要求低但软件栈版本锁死是硬伤论文 4.1–4.2 节列出了环境我们逐条验证其可行性项目论文要求实际验证关键说明操作系统Windows 98/2000/XP/2003、Linux、Solaris✅ XP/2003 可跑❌ Win10/11 默认禁用 IE6 兼容模式Access 数据库驱动sun.jdbc.odbc.JdbcOdbcDriver在 JDK 8 已移除必须用 JDK 6u45 或 JDK 7u80Web 服务器Apache-tomcat-6.0.14✅ 官方支持 JDK 6Tomcat 6 的conf/context.xml需添加Resource配置 Access 数据源但 Access 无标准 JDBC URL实际用jdbc:odbc:driver{Microsoft Access Driver (*.mdb)};DBQC:/system.mdb数据库ACCESS⚠️ 仅限单机演示Access 最大 2GB 文件限制超 1000 户并发写入必锁表真实部署必须迁移到 MySQL 或 SQL Server浏览器IE6.0、Maxthon、FireFox✅ IE6 可渲染 JSPStruts2 标签库在 IE6 下s:select下拉框宽度异常需 CSS 强制width:150px提示apache-tomcat-6.0.14.zip仍可在 Apache 官网归档库下载但需搭配jdk-6u45-windows-i586.exeOracle 官网已下架需从可信镜像站获取。这是复现该项目不可绕过的版本锁。3.3 部署流程从 Eclipse 导出 WAR 到 Tomcat 运行的六步实操Eclipse 中配置 Tomcat ServerWindow → Preferences → Server → Runtime Environments → Add → Apache Tomcat v6.0 → 指向解压目录。新建 Dynamic Web ProjectProject name 设为PowerChargingTarget runtime 选刚配好的 Tomcat 6Dynamic web module version 选 2.5。复制源码结构将论文中WebRoot目录内容复制到项目WebContent下src下建controller、service、orm等包粘贴对应.java文件。配置web.xml确保包含 Struts2 的FilterDispatcherStruts2.1.x 版本filter filter-namestruts2/filter-name filter-classorg.apache.struts2.dispatcher.FilterDispatcher/filter-class /filter filter-mapping filter-namestruts2/filter-name url-pattern/*/url-pattern /filter-mapping配置struts.xml在src下建struts.xml定义LoginAction的 resultaction namelogin classcontroller.LoginAction result namesuccess/main.jsp/result result nameerror/login.jsp?error1/result /action启动并访问右键项目 → Run As → Run on Server → 选择 Tomcat 6 → 启动后浏览器访问http://localhost:8080/PowerCharging/login.jsp。4. 常见问题排查五个让当年学生通宵调试的典型坑4.1 现象登录成功后跳转main.jsp页面空白查看源码只有htmlbody/body/html原因main.jsp中用了 Struts2 的s:property value#session.user.uname/显示用户名但LoginAction.java中session.put(user, user)存的是Users对象而#session.user.uname试图调用user.getUname()但Users类缺少 getter 方法论文没提但代码必须有。解决在Users.java中补全 getterpublic String getUname() { return uname; } public void setUname(String uname) { this.uname uname; } // 其他字段同理4.2 现象点击“导出 Excel”按钮浏览器下载一个 0 字节的.xls文件原因ExportExcelAction.java使用 POI 2.5.1论文参考文献未列但lib目录必有其HSSFWorkbook构造函数需传入InputStream但代码中误写为new HSSFWorkbook(new FileInputStream(template.xls))而template.xls路径错误应放在WebContent/WEB-INF/template.xls但代码写成绝对路径C:/template.xls。解决用 ServletContext 获取真实路径ServletContext context ServletActionContext.getServletContext(); String templatePath context.getRealPath(/WEB-INF/template.xls); HSSFWorkbook wb new HSSFWorkbook(new FileInputStream(templatePath));4.3 现象统计查询生成的折线图CreateLinechart.java显示中文乱码全是方框原因JFreeChart 默认字体不支持中文createChart()方法中未设置Font。解决在CreateLinechart.java的createChart()方法开头添加Font font new Font(SimSun, Font.PLAIN, 12); // Windows 下用宋体 chart.getTitle().setFont(font); chart.getLegend().setItemFont(font); CategoryPlot plot chart.getCategoryPlot(); plot.getDomainAxis().setLabelFont(font); plot.getRangeAxis().setLabelFont(font);4.4 现象修改用户信息后数据库Users表Utime字段变成1899-12-30原因Utime字段在 Access 中是Date/Time类型但 Java 代码中user.setUtime(new Date().toString())存的是Mon May 01 08:30:00 CST 2012字符串Access 无法解析存入默认日期。解决统一用SimpleDateFormat格式化SimpleDateFormat sdf new SimpleDateFormat(yyyy-MM-dd HH:mm:ss); user.setUtime(sdf.format(new Date()));并在 Access 中将Utime字段类型改为Text或改用java.sql.Timestamp需改表结构。4.5 现象同一用户多次点击“计算电费”数据库Electricity表生成多条重复记录原因CalElAction.java的execute()方法未做幂等性控制每次提交都执行electricityService.addRecord()且前端calEl.jsp的表单未禁用提交按钮。解决前端加 JS 防重var submitted false; function submitForm() { if (submitted) return; submitted true; document.getElementById(calForm).submit(); }后端CalElAction中加判断// 检查本月是否已有记录 Electricity existing electricityDAO.findByAddressAndMonth(address, month); if (existing ! null) { addActionError(本月电费已计算请勿重复操作); return ERROR; }5. 进阶技巧把毕业论文项目升级为可维护的现代 Java Web 工程5.1 数据库迁移从 Access 到 MySQL 的四步平滑过渡Access 作为演示库尚可但真实部署必须换 MySQL。迁移不是简单导出导入而是要解决三个断层SQL 语法差异Access 的IIF(condition, true_val, false_val)→ MySQL 的CASE WHEN condition THEN true_val ELSE false_val ENDAccess 的TOP 10→ MySQL 的LIMIT 10。字段类型映射Access 的AutoNumber→ MySQL 的INT AUTO_INCREMENT PRIMARY KEYAccess 的Currency→ MySQL 的DECIMAL(10,2)比FLOAT精确。连接池配置Tomcat 6 的context.xml中Access 的 ODBC 配置需换成 MySQL 的 JDBCResource namejdbc/PowerDB authContainer typejavax.sql.DataSource maxActive100 maxIdle30 maxWait10000 usernameroot password123456 driverClassNamecom.mysql.jdbc.Driver urljdbc:mysql://localhost:3306/power_db?useUnicodetrueamp;characterEncodingUTF-8/Hibernate 方言切换hibernate.cfg.xml中dialect从org.hibernate.dialect.AccessDialect需自定义改为org.hibernate.dialect.MySQL5Dialect。血泪经验迁移后务必重跑所有ElectricityService的单元测试重点验证梯度电费计算结果是否与 Access 版本一致。曾有同学因 MySQL 的DECIMAL四舍五入规则与 Access 的Currency不同导致 0.005 元级误差被用户投诉。5.2 权限控制升级从 Session 拦截到 RBAC 模型的演进论文的LoginInterceptor只做了“是否登录”判断但真实系统需要更细粒度的权限。我们可以基于现有结构扩展新增Role和UserRole表CREATE TABLE Role ( rid INT PRIMARY KEY AUTO_INCREMENT, rname VARCHAR(20) NOT NULL -- admin, clerk, customer ); CREATE TABLE UserRole ( uid INT, rid INT, PRIMARY KEY (uid, rid), FOREIGN KEY (uid) REFERENCES Users(Uid), FOREIGN KEY (rid) REFERENCES Role(rid) );改造LoginInterceptor不再只查session.get(user)而是查user.getRoles()存入session.setAttribute(roles, roles)。JSP 页面权限控制用 JSTL 替代 Struts2 标签做细粒度显示%-- 只有 admin 能看到用户管理菜单 --% c:if test${fn:contains(sessionScope.roles, admin)} a hrefuserList.action用户管理/a /c:if5.3 前端现代化用 Bootstrap 4 替换原始 table 布局的三处关键改造论文的userList.jsp是纯 HTML table响应式差、样式简陋。升级只需三处改动引入 Bootstrap CDN在WebRoot/WEB-INF/jsp/head.jsp中link relstylesheet hrefhttps://cdn.jsdelivr.net/npm/bootstrap4.6.2/dist/css/bootstrap.min.css script srchttps://cdn.jsdelivr.net/npm/jquery3.5.1/dist/jquery.slim.min.js/script script srchttps://cdn.jsdelivr.net/npm/bootstrap4.6.2/dist/js/bootstrap.bundle.min.js/script改造用户列表表格div classtable-responsive table classtable table-striped table-hover thead classthead-dark trth编号/thth姓名/thth电话/thth住址/thth操作/th/tr /thead tbody s:iterator valueusers varu tr tds:property value#u.uid//td tds:property value#u.uname//td tds:property value#u.utel//td tds:property value#u.uaddress//td td a hrefupdateUser.action?uids:property value#u.uid/ classbtn btn-sm btn-primary编辑/a a hrefdelUser.action?uids:property value#u.uid/ classbtn btn-sm btn-danger onclickreturn confirm(确定删除)删除/a /td /tr /s:iterator /tbody /table /div登录页美化用 Bootstrap 的form-group和input-group替换原始 inputdiv classcontainer mt-5 stylemax-width:400px; form actionlogin.action methodpost classborder p-4 rounded div classform-group label用户名/label input typetext nameusername classform-control required /div div classform-group label密码/label input typepassword namepassword classform-control required /div button typesubmit classbtn btn-block btn-success登录/button /form /div从那以后我每次接手老系统重构都强制走一遍“数据库方言验证→权限模型审计→前端框架兼容性测试”三步。因为毕业论文里的代码从来不是终点而是你工程能力的第一个刻度——它不完美但足够真实它有坑但每个坑都教你一招。希望帮到你。本文还有配套的精品资源点击获取
返回列表