简介这份资源是面向高校计算机专业学生与Java初学者的一份课程设计/毕业设计参考文档主题为基于Java的学校智能网上报修管理系统用于解决传统人工或电话报修方式效率低、流程混乱的问题。系统按管理员、维修人员、学生三种角色划分权限涵盖学生管理、维修人员管理、报修类型管理、在线报修、维修指派、维修信息、维修评价及公告信息等模块采用Java语言与MySQL数据库实现结构清晰、功能完整。资源包内共1个doc文档约2.14MB内容包含摘要、绪论、系统分析与功能设计等章节可作为需求梳理、模块划分与论文撰写的直接参考。目前已有86人学习浏览适合需要快速搭建报修类管理系统思路、撰写相关设计文档的读者借鉴使用。1. 从一张手写报修单说起这套 Java 报修系统到底能接住什么活宿舍楼三楼的水管爆了学生在群里喊了一嗓子宿管阿姨拿本子记下打电话找维修师傅师傅说没收到单子三天后水还在流。这个场景在学校里太常见了问题不在人懒在于报修这件事从头到尾没有一条可追踪的链路。我拆的这套基于 Java 的学校智能网上报修管理系统核心就是把这根链路补上学生在线提交报修单管理员指派维修人员维修人员回填维修信息学生做维修评价每一步都有状态、有记录、有责任人。系统用 Java 语言开发数据库选的是 MySQL角色分管理员、维修人员、学生三类功能覆盖在线报修、维修指派、维修信息、维修评价、公告信息等模块。它适合正在做课程设计或毕业设计的同学拿来跑通一套完整的三层架构业务流也适合想看看 SSM 怎么落地到真实管理场景的开发者。下面我按拆包、跑通、踩坑、进阶的顺序把这份资源讲透。2. 拆开这套 SSM 报修系统三层架构与 11 张表的真实分工2.1 为什么是 SSM 而不是 Spring Boot拿到源码先看技术栈这套系统用的是 SSM也就是 Spring SpringMVC MyBatis 的组合不是现在更流行的 Spring Boot。很多人第一反应是怎么不用 Boot但对于课程设计和教学场景来说SSM 反而更合适。Spring 负责业务层的 Bean 管理和依赖注入Service 层通过接口定义业务方法实现类里写具体逻辑SpringMVC 负责请求路由Controller 接收前端请求后调用 Service再把结果返回给 JSP 页面MyBatis 负责持久层DAO 接口定义增删改查方法XML 映射文件里写 SQL。三层各管一摊目录结构清晰出了问题能快速定位是哪一层的事。Spring Boot 把配置都自动化了新手跑起来确实快但为什么能跑这件事被藏起来了。SSM 需要手动配 web.xml、spring-mvc.xml、applicationContext.xml、mybatis-config.xml配一遍下来你对一个 Java Web 请求从进来到出去经过了哪些环节会有实打实的体感。这套系统的价值不在于技术多新而在于它把一条完整的业务链路摊开给你看。2.2 11 张表怎么撑起一条报修链路数据库设计是这套系统的骨架一共 11 张表每张表对应一个业务实体。我把核心几张表的关系理一下你就能看懂数据是怎么流转的。表名中文名核心字段在链路中的角色zaixianbaoxiu在线报修baoxiubianhao, baoxiubiaoti, baoxiuleixing, xueshengzhanghao学生提交的报修单链路起点weixiuzhipai维修指派zhipaibianhao, zhipaizhuangtai, weixiuzhanghao管理员把报修单指派给维修人员weixiuxinxi维修信息weixiubianhao, weixiujindu, weixiuxiangqing维修人员回填的处理结果weixiupingjia维修评价pingjiabianhao, pingjia, pingyu学生对维修结果打分和留言xuesheng学生xueshengzhanghao, mimav, xueshengxingming学生身份信息weixiu维修员weixiuzhanghao, mimav, weixiuxingming维修人员身份信息users用户表username, password, role统一登录入口按 role 区分身份token令牌表userid, token, expiratedtime登录态管理baoxiuleixing报修类型baoxiuleixing报修分类字典gonggaoxinxi公告信息gonggaobiaoti, gonggaoneirong系统公告config配置文件name, value系统参数配置链路是这样的学生在 zaixianbaoxiu 表插入一条报修记录管理员在后台看到后通过 weixiuzhipai 表创建一条指派记录把报修单和某个维修人员关联起来。维修人员登录后看到指派给自己的单子处理完在 weixiuxinxi 表写入维修详情和进度。学生看到维修完成后在 weixiupingjia 表提交评价。四张表通过 xueshengzhanghao 和 weixiuzhanghao 这两个业务字段串联而不是靠复杂的外键约束这是这类管理系统的常见做法查询灵活但需要业务层保证一致性。注意看 weixiupingjia 表里有两个字段 crossuserid 和 crossrefid这是跨表关联用的。评价记录需要同时关联到学生和维修人员用这两个字段做多态关联避免为每种组合建一张中间表。这种设计在中小型系统里很实用但查询时要多写一层 join。2.3 环境搭建从 JDK 到 Tomcat 的版本对齐跑这套系统之前版本对齐是第一道坎。我一般会按下面的清单把环境锁死避免出现代码没问题但就是跑不起来的玄学。# 1. 确认 JDK 版本SSM 项目通常用 JDK 8 java -version # 输出应为 java version 1.8.0_xxx # 2. 确认 Maven 版本 mvn -version # 建议 3.6.x 以上 # 3. 确认 MySQL 版本 mysql --version # 建议 5.7.x8.0 需要改驱动类和连接串 # 4. 确认 Tomcat 版本 # 在 Tomcat 的 bin 目录下执行 ./version.sh # Linux/Mac version.bat # Windows # 建议 Tomcat 8.5.x 或 9.xJDK 选 8 是因为 SSM 的很多依赖包在 JDK 8 上最稳定JDK 11 以上会有模块化相关的兼容问题。MySQL 如果装的是 8.0驱动类要从com.mysql.jdbc.Driver改成com.mysql.cj.jdbc.Driver连接串要加serverTimezoneAsia/Shanghai否则会报时区错误。Tomcat 8.5 和 9 的区别主要在 Servlet 规范版本这套系统用 8.5 就够了。数据库导入是下一步。源码包里一般会有一个.sql文件用命令行导入比用图形化工具更可控# 创建数据库并导入 mysql -u root -p -e CREATE DATABASE baoxiu DEFAULT CHARACTER SET utf8mb4; mysql -u root -p baoxiu baoxiu.sql # 验证表是否导入成功 mysql -u root -p -e USE baoxiu; SHOW TABLES; # 应该看到 11 张表字符集一定要用 utf8mb4不要用 utf8。MySQL 的 utf8 是残缺的存不了 emoji 和部分生僻字报修描述里如果学生打了特殊符号就会插入失败。这个坑我踩过不止一次。2.4 配置文件里三个必须改的地方源码里的配置文件通常带着原作者的本地环境信息直接跑大概率连不上数据库。打开applicationContext.xml或者jdbc.properties重点改三处# jdbc.properties 示例 jdbc.drivercom.mysql.cj.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/baoxiu?useUnicodetruecharacterEncodingutf8mb4serverTimezoneAsia/ShanghaiuseSSLfalse jdbc.usernameroot jdbc.password你的密码第一处是驱动类MySQL 8.0 必须用com.mysql.cj.jdbc.Driver。第二处是连接串里的serverTimezone不配会报The server time zone value is unrecognized。第三处是useSSLfalse本地开发不需要 SSL 连接开着反而会出警告。改完这三处启动 Tomcat访问http://localhost:8080/项目名/能看到登录页就说明环境通了。3. 跑通第一条报修链路从学生提交到管理员指派3.1 登录模块的 token 机制这套系统的登录不是简单的 Session 存用户信息而是用了 token 表来管理登录态。流程是这样的用户提交用户名和密码后端校验 users 表通过后生成一个 token 字符串连同 userid、username、role、过期时间一起写入 token 表同时把 token 返回给前端。后续请求带着 token后端查 token 表验证有效性。// 登录核心逻辑示意Controller 层 RequestMapping(/login) ResponseBody public MapString, Object login(String username, String password, String role) { MapString, Object result new HashMap(); // 根据角色查对应的表 // 管理员查 users 表学生查 xuesheng 表维修员查 weixiu 表 Object user userService.findByUsernameAndRole(username, role); if (user null) { result.put(code, 500); result.put(msg, 用户名不存在); return result; } // 校验密码实际项目中应加密存储这里源码可能是明文 if (!password.equals(getPassword(user))) { result.put(code, 500); result.put(msg, 密码错误); return result; } // 生成 token 并写入 token 表 String token UUID.randomUUID().toString().replace(-, ); tokenService.saveToken(userId, username, role, token); result.put(code, 200); result.put(token, token); return result; }这里有个设计上的取舍值得说token 存在数据库里而不是用 JWT 无状态方案好处是服务端可以主动让 token 失效比如管理员禁用某个账号后删掉 token 记录就登不上了。坏处是每次请求都要查一次数据库并发高了 token 表会成为瓶颈。对于学校这种量级几千人的并发完全扛得住不用过度设计。3.2 在线报修学生端提交表单的字段校验学生提交报修是链路的起点。前端表单一般包含报修标题、报修类型、报修照片、报修地址、报修详情这几个字段。后端接收后写入 zaixianbaoxiu 表。// 在线报修提交Service 层 public MapString, Object submitBaoxiu(Zaixianbaoxiu baoxiu) { MapString, Object result new HashMap(); // 1. 校验必填字段 if (StringUtils.isBlank(baoxiu.getBaoxiubiaoti())) { result.put(code, 500); result.put(msg, 报修标题不能为空); return result; } if (StringUtils.isBlank(baoxiu.getBaoxiuleixing())) { result.put(code, 500); result.put(msg, 请选择报修类型); return result; } // 2. 生成报修编号格式BX 时间戳 baoxiu.setBaoxiubianhao(BX System.currentTimeMillis()); // 3. 设置初始状态为待指派 baoxiu.setZhuangtai(待指派); baoxiu.setAddtime(new Date()); // 4. 写入数据库 zaixianbaoxiuMapper.insert(baoxiu); result.put(code, 200); result.put(msg, 报修提交成功); return result; }报修编号用时间戳生成简单但有个隐患如果同一毫秒有两个人提交编号会重复。更稳妥的做法是时间戳加随机数或者用数据库自增 ID 拼前缀。源码里用的是时间戳方案小规模用没问题但如果要做压力测试这里会先崩。报修照片字段是 longtext 类型存的是图片的 Base64 编码或者文件路径。如果是 Base64一张手机拍的照片转完能有几 MBlongtext 最大能存 4GB够用但查询时会拖慢速度。常见做法是图片存文件服务器数据库只存路径源码里如果直接存 Base64建议改成存路径。3.3 维修指派管理员如何把单子派给对的人管理员登录后在在线报修列表里看到所有待指派的单子选择一条指定一个维修人员系统在 weixiuzhipai 表创建指派记录。// 维修指派Service 层 public MapString, Object assignWeixiu(Weixiuzhipai zhipai) { MapString, Object result new HashMap(); // 1. 校验报修单是否存在且未被指派 Zaixianbaoxiu baoxiu zaixianbaoxiuMapper.selectById(zhipai.getBaoxiuId()); if (baoxiu null) { result.put(code, 500); result.put(msg, 报修单不存在); return result; } if (!待指派.equals(baoxiu.getZhuangtai())) { result.put(code, 500); result.put(msg, 该报修单已被指派); return result; } // 2. 生成指派编号 zhipai.setZhipaibianhao(ZP System.currentTimeMillis()); zhipai.setZhipaizhuangtai(已指派); zhipai.setZhipaishijian(new Date()); // 3. 写入指派表 weixiuzhipaiMapper.insert(zhipai); // 4. 更新报修单状态 baoxiu.setZhuangtai(已指派); zaixianbaoxiuMapper.updateById(baoxiu); result.put(code, 200); result.put(msg, 指派成功); return result; }这里有个状态流转的设计报修单从待指派变成已指派指派记录从无到有。两个操作应该在一个事务里否则可能出现指派记录写入了但报修单状态没更新或者反过来。源码里如果没加Transactional注解这是一个需要自己补上的点。维修人员登录后在维修指派管理里看到指派给自己的单子点进去可以回填维修信息。维修信息表 weixiuxinxi 里的 weixiujindu 字段记录进度常见取值是维修中和已完成。学生看到进度变成已完成后就可以提交评价了。3.4 维修评价链路闭环的最后一环评价模块的逻辑比较直接学生在维修评价管理里选择一条已完成的维修记录打分float 类型一般是 1 到 5 分写评语提交后写入 weixiupingjia 表。// 提交评价Service 层 public MapString, Object submitPingjia(Weixiupingjia pingjia) { MapString, Object result new HashMap(); // 1. 校验评分范围 if (pingjia.getPingjia() 1 || pingjia.getPingjia() 5) { result.put(code, 500); result.put(msg, 评分必须在 1 到 5 之间); return result; } // 2. 校验该维修记录是否已被评价 int count weixiupingjiaMapper.countByWeixiuId(pingjia.getWeixiuId()); if (count 0) { result.put(code, 500); result.put(msg, 该维修记录已评价不能重复评价); return result; } // 3. 生成评价编号 pingjia.setPingjiabianhao(PJ System.currentTimeMillis()); pingjia.setAddtime(new Date()); weixiupingjiaMapper.insert(pingjia); result.put(code, 200); result.put(msg, 评价提交成功); return result; }防重复评价这个校验很重要。如果不加学生可以反复提交评价维修人员的评分就会被刷。源码里如果只靠前端按钮置灰来防重复后端没做校验这是一个安全漏洞需要补上。4. 避坑排查这套系统跑不起来时先看这五条4.1 启动报 404Tomcat 起来了但访问不到页面现象Tomcat 控制台没有报错访问http://localhost:8080/显示 404。原因项目部署路径不对或者 web.xml 里配置的欢迎页路径和实际文件不匹配。解决先看 Tomcat 的 webapps 目录下有没有你的项目文件夹。如果没有检查 IDEA 的 Artifacts 配置确认 war 包或 exploded 包输出路径正确。如果有文件夹但访问 404打开 web.xml 看welcome-file-list里配的是什么通常是login.jsp或index.jsp确认这个文件在 webapp 根目录下存在。4.2 数据库连不上报 Access denied 或 Communications link failure现象启动时抛异常提示Access denied for user rootlocalhost或者Communications link failure。原因jdbc.properties 里的用户名密码不对或者 MySQL 服务没启动或者端口不是默认的 3306。解决先用命令行验证mysql -u root -p能不能登进去。能登进去说明密码对检查 jdbc.properties 里有没有多余空格。连不上说明 MySQL 服务没起Windows 下net start mysqlLinux 下systemctl start mysqld。如果 MySQL 端口改过连接串里的 3306 要同步改。4.3 中文乱码页面显示问号或方块现象页面上的中文变成???或者乱码方块。原因字符集不统一可能是数据库、连接串、JSP 页面、Tomcat 四个环节里有一个没用 UTF-8。解决按顺序排查。数据库层面SHOW VARIABLES LIKE character%;确认 character_set_server 是 utf8mb4。连接串里加characterEncodingutf8mb4。JSP 页面头部加% page contentTypetext/html;charsetUTF-8 %。Tomcat 的 server.xml 里 Connector 标签加URIEncodingUTF-8。四个地方都对齐了乱码就消失了。4.4 登录后操作报 500提示 token 无效现象能登录成功但点任何功能都报错后端日志显示 token 校验失败。原因前端请求没有带上 token或者 token 过期了或者 token 表里的记录被清了。解决打开浏览器 F12 看 Network 里每个请求的 header确认有没有 token 字段。如果没有检查前端 ajax 的拦截器有没有把登录时返回的 token 存到 localStorage 并附加到后续请求上。如果有 token 但还是报错查 token 表的 expiratedtime 字段看是不是过期了。开发阶段可以把过期时间设长一点比如 24 小时。4.5 图片上传后显示不出来现象报修时上传了照片提交成功但列表里图片位置是空白或者裂图。原因图片存的是 Base64 但前端渲染方式不对或者存的是文件路径但文件没保存成功。解决先看数据库里 baoxiuzhaopian 字段存的是什么。如果是data:image/png;base64,xxxxx这种格式前端img的 src 直接放这个字符串就能显示。如果存的是/upload/xxx.jpg这种路径检查 Tomcat 的 webapps 下有没有对应的物理文件以及路径前缀对不对。常见错误是存了绝对路径D:\upload\xxx.jpg前端访问不到要改成相对路径。5. 进阶用法把报修系统改成能扛住真实流量的版本5.1 用拦截器统一处理登录校验源码里如果每个 Controller 方法都手动查 token代码会非常啰嗦。更优雅的做法是写一个 SpringMVC 拦截器在preHandle里统一校验 token放行登录接口和静态资源。// 登录拦截器 public class LoginInterceptor implements HandlerInterceptor { Autowired private TokenService tokenService; Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 放行登录接口和静态资源 String uri request.getRequestURI(); if (uri.contains(/login) || uri.contains(/static/) || uri.contains(/css/) || uri.contains(/js/)) { return true; } // 从 header 里取 token String token request.getHeader(token); if (StringUtils.isBlank(token)) { response.setStatus(401); return false; } // 校验 token 是否有效 boolean valid tokenService.validateToken(token); if (!valid) { response.setStatus(401); return false; } return true; } }拦截器配好后在 spring-mvc.xml 里注册指定拦截路径和排除路径。这样业务代码里就不用再关心登录态了专注写业务逻辑。参数说明preHandle返回 true 表示放行返回 false 表示拦截。response.setStatus(401)让前端能识别出是未登录状态跳转到登录页。5.2 报修单状态机把流转规则收拢到一处现在报修单的状态散落在各个 Service 方法里学生提交时设待指派管理员指派时改已指派维修完成时改已完成。如果以后要加一个已取消状态得改好几个地方。更好的做法是定义一个状态枚举和状态流转规则。// 报修单状态枚举 public enum BaoxiuStatus { DAI_ZHIPAI(待指派), YI_ZHIPAI(已指派), WEI_XIU_ZHONG(维修中), YI_WAN_CHENG(已完成), YI_QU_XIAO(已取消); private String desc; BaoxiuStatus(String desc) { this.desc desc; } public String getDesc() { return desc; } // 定义允许的状态流转 public static boolean canTransfer(BaoxiuStatus from, BaoxiuStatus to) { switch (from) { case DAI_ZHIPAI: return to YI_ZHIPAI || to YI_QU_XIAO; case YI_ZHIPAI: return to WEI_XIU_ZHONG || to YI_QU_XIAO; case WEI_XIU_ZHONG: return to YI_WAN_CHENG; default: return false; } } }这样每次改状态前先调canTransfer判断非法流转直接拒绝。好处是规则集中在一处加状态或改规则只动这一个文件。这套系统目前的状态流转比较简单但如果要扩展成支持退回重派超时自动关闭等逻辑状态机就是必须的了。5.3 验证方法用一条完整链路自测改完代码后怎么确认没改坏我的习惯是走一遍完整链路用学生账号登录提交一条报修记下报修编号退出用管理员账号登录在在线报修列表里找到这条单子指派给某个维修人员退出用维修人员账号登录在维修指派里看到这条单子回填维修信息进度设为已完成退出再用学生账号登录在维修评价里对这条记录打分提交。四个角色走完数据库里 zaixianbaoxiu、weixiuzhipai、weixiuxinxi、weixiupingjia 四张表各多一条记录状态字段依次变化就说明链路是通的。从那以后我每次改完这类管理系统的代码都会强制走一遍这条四角色链路不管改的是哪个模块。因为报修系统的价值就在于链路完整任何一个环节断了整套系统就是摆设。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?