ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

设备维修管理系统JavaWeb课设:Servlet+JDBC实现与避坑指南

设备维修管理系统JavaWeb课设:Servlet+JDBC实现与避坑指南 简介设备维修管理系统是基于JavaWeb技术栈、采用原生Servlet与JDBC开发的完整课程设计/毕业设计项目适合计算机、数学、电子信息等专业学生用于期末作业或毕设参考。压缩包内共有248个文件以Java源码与class文件为核心含54个java和54个class同时包含50个js、17个css、13个png等前端页面资源以及sql数据库脚本和db数据库文件便于快速部署调试。整个资源包约2.84MB结构紧凑涵盖设备报修、维修记录、零件管理、客户管理等模块并提供项目说明文档。目前已有346人学习下载。资源提供了可直接运行的全部源码读者可借此理解JavaWeb请求处理、JDBC数据持久化与分层开发思路还能基于现有代码扩展功能适合有一定基础并希望深入钻研的开发者作为实战参考资料。1. 设备维修管理系统原生 Servlet JDBC 的 JavaWeb 课设长什么样设备维修管理系统这套 JavaWeb 源码是我见过的课设型项目里结构最“透明”的一类请求处理全部用原生 Servlet数据库访问全部走 JDBC没有 Spring、没有 MyBatis所有逻辑都平铺在 src 目录下。反直觉的地方在于越是框架用得熟练的人越容易在这个项目上栽跟头——因为报修单要更新状态、配件要扣库存、维修记录要落库这条链路一旦打通很多在 Spring Boot 里被隐藏的底层问题反而会暴露出来。对正在做课程设计、期末大作业或者拿毕设起步的人来说这类源码的价值就是用最少的环境依赖把 JavaWeb 的完整请求链路看明白。下文从源码结构、部署流程、常见报错和改造方向依次拆解帮你从“能跑通”走到“能答辩”。2. 把源码拆开看从 class 文件反推包结构与报修主流程2.1 先看这几个类Dao 层对应哪些业务表资源里给出了一串 class 文件名单把它按命名规律整理一遍整个项目的数据库设计基本就浮出来了。ReportEquipmentDao、RepairRecordDao、PartDao、CustomerDao、ReportRecordDao、PartDetailDao 这六个 Dao 类分别对应报修设备、维修记录、配件、客户、报修单、配件明细这几张核心表。Dao 类名推断表名在系统里承担的角色CustomerDaocustomer客户信息维护报修单要关联客户ReportEquipmentDaoreport_equipment报修设备登记记录设备编号、故障描述ReportRecordDaoreport_record报修单流转记录报修时间、处理状态RepairRecordDaorepair_record维修过程记录包括维修人、维修结果PartDaopart配件库存表维修时扣减库存PartDetailDaopart_detail配件出入库明细追溯每个维修单用了哪些件这个命名规律在 JavaWeb 课设里非常典型一个表对应一个 DaoDao 内部就是 JDBC 老三样——从 DbUtil 里拿 Connection用 PreparedStatement 拼参数用 ResultSet 把行数据映射成对象。为什么强调用 PreparedStatement 而不是 Statement因为原生 JDBC 里最常见的漏洞就是字符串拼 SQL参数里带个单引号就能把整条 SQL 拆了。PreparedStatement 先把 SQL 骨架发给数据库预编译参数单独传既避免注入问题也是在答辩时能说清楚的一个安全知识点。2.2 Servlet 层两个关键类的请求处理路径GenerateCheckServlet 和 QueryCompletedTasksServlet 是单看名字就能懂业务的类。前者负责根据报修单生成检查单后者负责查已完成任务。原生 Servlet 的套路高度统一doGet 做查询展示doPost 做表单提交以报修登记为例标准的写法长这样WebServlet(/reportEquipment) public class ReportEquipmentServlet extends HttpServlet { private ReportEquipmentDao reportEquipmentDao new ReportEquipmentDao(); Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 报修列表查询把数据放进 request转发到 JSP 展示 ListReportEquipment list reportEquipmentDao.findAll(); request.setAttribute(list, list); request.getRequestDispatcher(/reportEquipment/list.jsp).forward(request, response); } Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 提交报修单读表单字段、写库、重定向回列表避免重复提交 request.setCharacterEncoding(UTF-8); ReportEquipment equipment new ReportEquipment(); equipment.setEquipmentId(Integer.parseInt(request.getParameter(equipmentId))); equipment.setCustomerId(Integer.parseInt(request.getParameter(customerId))); equipment.setReportDesc(request.getParameter(reportDesc)); reportEquipmentDao.insert(equipment); response.sendRedirect(request.getContextPath() /reportEquipment); } }逐行说明WebServlet(/reportEquipment)是 Servlet 3.0 引入的注解式映射Tomcat 8.5 起原生支持完全不用在 web.xml 里每个 Servlet 写一段配置。doGet 里把查询结果塞进 request 的 attribute 里再 forwardJSP 就能用 EL 表达式直接取doPost 里request.setCharacterEncoding(UTF-8)必须放在读取参数之前否则中文参数进来到第一步就乱码了。提交之后用response.sendRedirect让浏览器重新 GET 一次列表而不是继续 forward这一步是避免表单重复提交的关键。如果看完这两个类还想追更大的查询链路可以重点看 GenerateCheckServlet。它做的事情一般是查报修单详情、查客户信息、查设备信息然后把三个数据拼到一张检查单页面。这里你会发现原生 Servlet 的一个特征——一个请求往往要串多个 Dao代码里会依次调用 reportRecordDao.findById、customerDao.findById、equipmentDao.findById这种“手工拼装”在框架里被 Service 层取代了但逻辑本质是完全一样的。2.3 维修链路里的关键片段一个跨表更新的事务处理这个项目里最有含金量的代码不在增删改查的单表操作里而在“完工确认”这种跨表更新。维修完成后要做两件事把 repair_record 的状态改成已完成同时扣减 part 表的配件库存。两条 SQL 必须同时成功或者同时失败原生 JDBC 里这就是setAutoCommit(false)的典型场景Connection conn null; try { conn DbUtil.getConnection(); conn.setAutoCommit(false); // 开启手动事务两条 SQL 要么都成要么都回滚 // 1. 更新维修单状态为“已完成” String sql1 UPDATE repair_record SET status 已完成, finish_time NOW() WHERE id ?; PreparedStatement ps1 conn.prepareStatement(sql1); ps1.setInt(1, repairId); ps1.executeUpdate(); // 2. 扣减配件库存 String sql2 UPDATE part SET stock stock - ? WHERE id ?; PreparedStatement ps2 conn.prepareStatement(sql2); ps2.setInt(1, partCount); ps2.setInt(2, partId); ps2.executeUpdate(); conn.commit(); // 两条都成功才提交 } catch (Exception e) { conn.rollback(); // 任意一条失败都回滚 e.printStackTrace(); } finally { conn.setAutoCommit(true); // 恢复默认自动提交避免后续连接复用出问题 DbUtil.close(conn); // 只关 connectionps/rs 在各自的 try 块里关闭 }参数说明与踩坑点setAutoCommit(false)之后后续 SQL 全部进入同一事务直到调commit()才真正落库rollback()可以把前面所有未提交操作全部撤销。有一个非常隐蔽的坑是 finally 里没有把 autoCommit 恢复成 true项目如果用了连接池这个连接被归还之后还是手动提交状态下一个人拿到这个连接怎么执行都不落库排查起来极其痛苦。这类问题在 JDBC 项目里被叫“玄学 BUG”其实就是资源状态没复原。3. 把项目跑起来JDK、Tomcat、MySQL 环境配置与部署全流程3.1 版本搭配为什么说 JDK 8 Tomcat 8.5 MySQL 5.7/8.0 最省心原生 Servlet 项目对环境要求很低但版本组合直接决定你会不会开局就翻车。我一般建议课设环境按 JDK 8、Tomcat 8.5、MySQL 5.7 来搭这套组合是网上大部分教程和笔记的默认环境遇到问题搜起来最容易命中。如果你机器上已经装了 JDK 17 和 Tomcat 10也不是不行但要注意 Tomcat 10 把包名从javax.servlet改成了jakarta.servlet项目里所有import javax.servlet.*全部要改课设阶段没必要给自己加这个工作量。MySQL 8.0 也可以用只是 JDBC 驱动配置要比 5.7 多处理两个参数下文 3.2 会专门说明。这里顺带回答一个经常被搜到的问题用 VSCode 写 Servlet 怎么配置环境。写代码本身没问题装 Java Extension Pack 就能编辑和编译但要在 VSCode 里跑 Tomcat 调试要装 Tomcat for Java 插件还要手动处理部署目录比 IDEA 繁琐得多。JavaWeb 课设场景我更推荐直接用 IDEA Community 版免费且内置了 Tomcat 集成省下的时间够你把报修流程多测两遍。3.2 建库与数据库连接配置usessl 和 sslmode 到底听谁的拿到源码第一件事是找到 sql 目录或 doc 目录下的建表脚本先执行它。如果资源里没有单独的建表 SQL也可以根据 2.1 的表推断手动建但优先找原脚本因为字段名对不上会影响后续所有 Dao 的查询。建库命令很简单CREATE DATABASE IF NOT EXISTS equipment_repair DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci; USE equipment_repair;库建好之后打开项目里的数据库配置文件一般是 src 目录下的 db.properties 或 jdbc.properties把连接信息改成自己本机的drivercom.mysql.cj.jdbc.Driver urljdbc:mysql://localhost:3306/equipment_repair?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8 usernameroot password123456这里每个参数单独解释一下因为网上关于mysql jdbc usessl 与 sslmode 使用的讨论特别多实际以你本机的 MySQL 版本为准注意这三个点配置项说明driverMySQL 8.x 必须写com.mysql.cj.jdbc.DriverMySQL 5.x 是com.mysql.jdbc.Driver混用会报 ClassNotFoundExceptionuseSSLfalse本地开发没有 SSL 证书关掉避免告警。如果你确实要开 SSL连接串要和服务端的 ssl-mode 保持一致否则 MySQL 8 直接拒绝连接serverTimezoneMySQL 8 强制要求显式指定时区不写就会报The server time zone value is unrecognized国内统一写 Asia/ShanghaicharacterEncoding连接层字符集配合库表的 utf8mb4 才能保证中文不乱码驱动 jar 包的放置位置也是个高频问题。mysql-connector-java 的 jar 必须放在 web/WEB-INF/lib 目录下如果项目是 Maven 结构就放在 pom.xml 里管理。放在 src 目录下不会被 Tomcat 加载运行时报 ClassNotFoundException 时第一反应先检查 jar 位置。3.3 用 IDEA 配置 Tomcatwar exploded 和热部署这一步是很多人第一次接触 JavaWeb 项目时卡住的地方。在 IDEA 里跑 Servlet 项目关键不是写代码而是把构建产物正确部署到 Tomcat。常见做法是走完这几个步骤第一步用 IDEA 打开解压后的项目目录确认它是普通 Java 项目而不是 Maven 项目。第二步进入 Project Structure快捷键 CtrlAltShiftS在 Modules 里把 src 标记为 Sources把 web 目录标记为 Web Resources指定 web.xml 位置和 Web 根目录。第三步在 Artifacts 里新增一个 Web Application ExplodedIDEA 会自动识别项目里所有依赖。第四步打开 Run 配置新增 Tomcat Server Local在 Deployment 标签页把刚才的 Artifact 加进去Application context 默认填/项目名_war_exploded建议直接改成/这样访问路径短一些。启动之后 IDEA 会自动打开浏览器默认地址是 http://localhost:8080/项目名/首页 。用 war exploded 的优势是支持热部署改了 JSP 不用重启 Tomcat刷新页面就能看到变化改了 Java 代码点一下 Build 菜单的 RecompileIDEA 会自动重新加载。Eclipse 用户对应的操作是Project Facets 里勾选 Dynamic Web Module 3.1Target runtime 选择本机 Tomcat然后 Run As → Run on Server流程等价只是叫法不同。部署完成先别急着点功能打开浏览器手动访问一次报修列表页能正常展示数据再继续操作。“能启动”和“能访问”是两回事Tomcat 启动了但页面 404问题往往在上下文路径或 Servlet 注解映射上这在下一章专门展开。4. 避坑从部署到运行最常见的 5 个翻车现场4.1 启动期三连坑驱动类找不到、时区报错、URL 404第一个坑是java.lang.ClassNotFoundException: com.mysql.jdbc.Driver。现象Tomcat 一启动页面白屏控制台第一行就是这个异常。原因你用的 mysql-connector-java 是 8.x但 db.properties 里 driver 还是 5.x 时代的com.mysql.jdbc.Driver或者 jar 根本没放到 WEB-INF/lib。解决MySQL 8 一律改成com.mysql.cj.jdbc.Driverjar 位置对照 3.2 检查。这个坑在网上的 javaweb 教学案例贴里出现频率极高基本属于必踩项。第二个坑是数据库连接时报The server time zone value ???ú±ê×??±?? is unrecognized。现象连接建立失败但 driver 和密码都确认无误。原因这是 MySQL 8 的新要求连接串必须显式指定时区不写它就返回一个本地化乱码时区。解决在 JDBC URL 后面追加serverTimezoneAsia/Shanghai。注意如果你的 MySQL 服务器部署在别的时区要按实际时区改不能无脑复制。第三个坑是页面 404 或者样式全部丢失。现象Tomcat 能启动但访问 http://localhost:8080/reportEquipment 报 404列表页能打开页面上的 CSS 和图片全是破的。原因分两半Servlet 映射路径在注解里忘了写开头的斜杠或者上下文路径变了导致绝对路径的静态资源找不到。解决Servlet 注解统一以/开头JSP 里的静态资源不要写死/css/style.css改成${pageContext.request.contextPath}/css/style.css让上下文路径自动拼接。后者是原生 Servlet 项目里最容易忽略的细节。4.2 运行期两连坑中文乱码和重复提交第四个坑是中文乱码而且是看上去很怪的乱码列表页中文正常新建报修单之后页面里刚提交的中文变成问号但旧数据没变。这个现象基本能锁定是写入环节乱了。原因JSP 页面没设请求编码或者 JDBC URL 没加 characterEncoding或者数据库表排序规则不是 utf8mb4。三处但凡有一处没对齐新写入的中文就是乱码。解决请求入口加request.setCharacterEncoding(UTF-8)响应加response.setContentType(text/html;charsetUTF-8)JDBC URL 加characterEncodingutf8建表语句统一utf8mb4。三个地方对齐之后项目里基本不会再出现中文问题。第五个坑是表单重复提交。现象提交报修单之后点浏览器刷新同一条数据新增了两条或三条日志里出现连续多次 insert。原因doPost 里最后用的是request.getRequestDispatcher(list.jsp).forward()forward 是服务端内部转发浏览器地址栏还是提交路径F5 一刷就重新执行了一次 POST。解决写完数据库之后强制用response.sendRedirect(request.getContextPath() /reportEquipment)让浏览器发起新的 GET 请求这个模式叫 Post/Redirect/Get是 Web 开发的基础常识也是答辩时老师爱问的点。4.3 排查这类问题看哪里三个日志入口的优先级刚才这些坑在排查时不用乱猜按顺序看三个地方就够了。第一是 IDEA 控制台异常堆栈的第一行就指明了是驱动、SQL 还是连接问题ClassNotFoundException 之类的一定第一时间出现在这里。第二是 Tomcat 的 logs 目录catalina.out 里记录了容器自身的信息特别是访问日志能告诉你浏览器实际请求的 URL 是什么404 是不是路径本身就不对。第三是 MySQL 端直接打开命令行执行查询确认数据到底有没有写进去很多“页面报错”其实是数据已经落了但查询条件不对白找了半天代码。这三层按顺序捋极少数情况会解决不了多数组装问题都能在十分钟内定位。这套排查思路在原生 JDBC 项目里特别管用因为没有框架帮你打日志一切都得看这三处原始输出。5. 改造一步用 Filter 把登录鉴权补上答辩直接加分课设项目交上去老师最爱问的一个问题就是“你这个系统有没有登录功能”。原生 Servlet 项目很多为了图省事把所有页面裸奔连登录页都没有这在一对一答辩时很吃亏。其实加一个登录校验并不难用 Filter 统一拦截所有请求就行代码量不到 30 行。以/login.jsp为登录页为例WebFilter(/*) public class LoginFilter implements Filter { Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request (HttpServletRequest) req; HttpServletResponse response (HttpServletResponse) resp; // 放行登录页、登录接口和静态资源其他页面一律检查 session String uri request.getRequestURI(); if (uri.endsWith(login.jsp) || uri.endsWith(loginServlet) || uri.contains(/css/) || uri.contains(/js/)) { chain.doFilter(request, response); return; } // 核心校验session 里没有 user 就踢回登录页 Object user request.getSession().getAttribute(user); if (user null) { response.sendRedirect(request.getContextPath() /login.jsp); return; } chain.doFilter(request, response); } }这段代码里最容易被忽略的是放行条件。WebFilter(/*)拦的是所有请求如果你不放行 login.jsp用户还没登录就被重定向而重定向目标又是 login.jsp就变成死循环。静态资源也必须放行否则登录页引用的 CSS 加载不出来页面会变得很难看。session 校验本身很简单就是判断 attribute 是不是 null。更进一步如果想区分管理员和普通维修工在登录时往 session 里放一个角色字段Filter 里再判断一下角色再放行这一句话就能在答辩时多讲半分钟比把项目吹得天花乱坠都管用。以前我交过一次没有做任何登录校验的课设演示时一切正常老师顺着 URL 一个一个翻突然问“你这个查询接口不校验身份是不是意味着任何人拿到地址就能改维修记录”那次我确实没答好。从那以后我每次接手一个 JavaWeb 项目强制自己先走一遍权限和登录的核查把 session 校验、静态资源放行、角色判断这三件事理清再谈业务功能。这套源码拿回去之后建议你也先做这一步。希望帮到你。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进