简介:这份资源是面向高校计算机专业学生与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.x,8.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,连接串要加serverTimezone=Asia/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.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/baoxiu?useUnicode=true&characterEncoding=utf8mb4&serverTimezone=Asia/Shanghai&useSSL=false jdbc.username=root jdbc.password=你的密码第一处是驱动类,MySQL 8.0 必须用com.mysql.cj.jdbc.Driver。第二处是连接串里的serverTimezone,不配会报The server time zone value is unrecognized。第三处是useSSL=false,本地开发不需要 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 Map<String, Object> login(String username, String password, String role) { Map<String, 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 Map<String, Object> submitBaoxiu(Zaixianbaoxiu baoxiu) { Map<String, 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,一张手机拍的照片转完能有几 MB,longtext 最大能存 4GB,够用但查询时会拖慢速度。常见做法是图片存文件服务器,数据库只存路径,源码里如果直接存 Base64,建议改成存路径。3.3 维修指派:管理员如何把单子派给对的人管理员登录后,在在线报修列表里看到所有"待指派"的单子,选择一条,指定一个维修人员,系统在 weixiuzhipai 表创建指派记录。// 维修指派(Service 层) public Map<String, Object> assignWeixiu(Weixiuzhipai zhipai) { Map<String, 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 Map<String, Object> submitPingjia(Weixiupingjia pingjia) { Map<String, 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 启动报 404,Tomcat 起来了但访问不到页面现象: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 'root'@'localhost'或者Communications link failure。原因:jdbc.properties 里的用户名密码不对,或者 MySQL 服务没启动,或者端口不是默认的 3306。解决:先用命令行验证mysql -u root -p能不能登进去。能登进去说明密码对,检查 jdbc.properties 里有没有多余空格。连不上说明 MySQL 服务没起,Windows 下net start mysql,Linux 下systemctl start mysqld。如果 MySQL 端口改过,连接串里的 3306 要同步改。4.3 中文乱码,页面显示问号或方块现象:页面上的中文变成???或者乱码方块。原因:字符集不统一,可能是数据库、连接串、JSP 页面、Tomcat 四个环节里有一个没用 UTF-8。解决:按顺序排查。数据库层面SHOW VARIABLES LIKE 'character%';确认 character_set_server 是 utf8mb4。连接串里加characterEncoding=utf8mb4。JSP 页面头部加<%@ page contentType="text/html;charset=UTF-8" %>。Tomcat 的 server.xml 里 Connector 标签加URIEncoding="UTF-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 四张表各多一条记录,状态字段依次变化,就说明链路是通的。从那以后我每次改完这类管理系统的代码,都会强制走一遍这条四角色链路,不管改的是哪个模块。因为报修系统的价值就在于链路完整,任何一个环节断了,整套系统就是摆设。希望帮到你。本文还有配套的精品资源,点击获取
简介:这份资源是面向高校计算机专业学生与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.x,8.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,连接串要加serverTimezone=Asia/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.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/baoxiu?useUnicode=true&characterEncoding=utf8mb4&serverTimezone=Asia/Shanghai&useSSL=false jdbc.username=root jdbc.password=你的密码第一处是驱动类,MySQL 8.0 必须用com.mysql.cj.jdbc.Driver。第二处是连接串里的serverTimezone,不配会报The server time zone value is unrecognized。第三处是useSSL=false,本地开发不需要 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 Map<String, Object> login(String username, String password, String role) { Map<String, 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 Map<String, Object> submitBaoxiu(Zaixianbaoxiu baoxiu) { Map<String, 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,一张手机拍的照片转完能有几 MB,longtext 最大能存 4GB,够用但查询时会拖慢速度。常见做法是图片存文件服务器,数据库只存路径,源码里如果直接存 Base64,建议改成存路径。3.3 维修指派:管理员如何把单子派给对的人管理员登录后,在在线报修列表里看到所有"待指派"的单子,选择一条,指定一个维修人员,系统在 weixiuzhipai 表创建指派记录。// 维修指派(Service 层) public Map<String, Object> assignWeixiu(Weixiuzhipai zhipai) { Map<String, 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 Map<String, Object> submitPingjia(Weixiupingjia pingjia) { Map<String, 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 启动报 404,Tomcat 起来了但访问不到页面现象: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 'root'@'localhost'或者Communications link failure。原因:jdbc.properties 里的用户名密码不对,或者 MySQL 服务没启动,或者端口不是默认的 3306。解决:先用命令行验证mysql -u root -p能不能登进去。能登进去说明密码对,检查 jdbc.properties 里有没有多余空格。连不上说明 MySQL 服务没起,Windows 下net start mysql,Linux 下systemctl start mysqld。如果 MySQL 端口改过,连接串里的 3306 要同步改。4.3 中文乱码,页面显示问号或方块现象:页面上的中文变成???或者乱码方块。原因:字符集不统一,可能是数据库、连接串、JSP 页面、Tomcat 四个环节里有一个没用 UTF-8。解决:按顺序排查。数据库层面SHOW VARIABLES LIKE 'character%';确认 character_set_server 是 utf8mb4。连接串里加characterEncoding=utf8mb4。JSP 页面头部加<%@ page contentType="text/html;charset=UTF-8" %>。Tomcat 的 server.xml 里 Connector 标签加URIEncoding="UTF-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 四张表各多一条记录,状态字段依次变化,就说明链路是通的。从那以后我每次改完这类管理系统的代码,都会强制走一遍这条四角色链路,不管改的是哪个模块。因为报修系统的价值就在于链路完整,任何一个环节断了,整套系统就是摆设。希望帮到你。本文还有配套的精品资源,点击获取