
简介Java城市垃圾分类回收管理系统源码与数据库打包资源面向计算机专业毕业生及在校生适用毕业设计、期末大作业、课程设计等场景解决缺少完整可运行项目、不知如何实现垃圾分类业务的问题。压缩包共218个文件、大小约2.43MB其中52个Java源码负责后端业务逻辑17个HTML页面配合CSS与JS实现前端界面6个XML及YML等配置文件用于环境搭建1个SQL脚本提供数据库表结构与初始数据75个GIF录屏则直观演示系统操作流程便于快速上手。目前已有210人学习下载。系统覆盖居民垃圾分类信息管理、投放记录、回收处理等常见模块代码结构清晰、注释较完整部署时导入数据库并按说明调整配置即可运行可作为毕业设计答辩或期末大作业的完整参考也可借鉴其前后端交互逻辑与数据库设计思路。1. 拿到这套城市垃圾分类回收管理系统源码先别急着解压你手里这个Java城市垃圾分类回收管理系统源码数据库毕业设计.zip大概率是流传很广的那类课设模板Spring Boot 或 SSM 打底MySQL 里放十来张表前端用 Bootstrap 搭个后台界面压缩包里塞着完整工程、SQL 脚本、效果截图和一份写好的设计文档。它能解决的问题很具体——毕业设计需要一个有业务闭环的管理系统而垃圾分类、回收下单、积分结算正好把增删改查、权限、订单状态、统计报表串在一起工作量适中答辩也好讲。适合的人群是拿这套源码做参考想二次开发的学生、想快速搞懂 Java Web 完整链路的新手以及需要验证 Spring Boot MyBatis MySQL 集成写法的开发者。但这类压缩包普遍埋着坑数据库版本不匹配、Maven 拉不下来依赖、配置里的账号密码和本地不一致直接双击打开基本会劝退一批人。后面几章我会把导入、跑库、改配置、拆模块和答辩前必须做的事拆开讲。2. 拆包前先看技术栈三分钟判断这套 Java 源码能不能跑2.1 看 pom.xmlSpring Boot 还是 SSM依赖版本决定了 JDK 和数据库选型解压后不要急着打开 IDEA先用文本编辑器看根目录有没有pom.xml。有pom.xml就说明是 Maven 工程没有pom.xml但有一大堆lib/下的 jar 包那是经典的 SSM 手工导包工程处理起来更麻烦后面需要手动把库加进 IDEA。常见的做法是先把pom.xml里parent和几个核心依赖的版本号记下来因为 Spring Boot 2.x 和 3.x 对 JDK 有硬性要求MySQL 驱动版本也决定了你本机能不能连上 8.x 的库。!-- pom.xml 关键片段先看这三处再动手 -- parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.5.4/version !-- 2.x 配 JDK 83.x 必须 JDK 17 -- relativePath/ /parent dependencies !-- 用这个判断持久层是 MyBatis 还是 JPA -- dependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter/artifactId version2.2.0/version /dependency !-- 很多毕业设计会配 Druid 连接池版本和 MySQL 8 有兼容问题 -- dependency groupIdcom.alibaba/groupId artifactIddruid-spring-boot-starter/artifactId version1.2.6/version /dependency /dependencies判断逻辑很简单Spring Boot 2.x 系列基本绑定 JDK 8Spring Boot 3.x 必须 JDK 17 往上而你本机装的如果还是 JDK 8直接跑 3.x 会被版本卡住。另一个判断点是 MyBatis 的 mapper 接口有没有对应 XML——有 XML 的项目SQL 都在resources/mapper下改动起来比注解 SQL 直观只有注解的项目SQL 全散在Select、Update里答辩时被问“这条 SQL 在哪”容易找不到。参数说明spring-boot-starter-parent 的版本号不要乱升特别是 druid 和 mybatis 这两个升了往往会带来驱动类名不匹配、加密配置失效之类的新问题我一般只降不升。2.2 从包名和表名读功能先确认这套系统覆盖了什么业务接着看src/main/java下的包结构。典型的包名是com.xxx.recycle或者com.xxx.garbage下面一定会分controller、service、mapper、entity、config五层。实体类的名字可以直接当需求清单读User、Address、GarbageCategory、RecycleOrder、PointsRecord、StatisticsReport一张表对应一个实体一个实体对应一段增删改查。这里有个经验如果一个实体类同时存在xxxMapper.java和xxxMapper.xml说明作者是走的标准 XML 映射如果实体类很少而 controller 里堆了一大段 SQL 拼接说明代码质量比较差答辩时容易被问住。# 在项目根目录用 tree 快速看包结构速度比 IDEA 快 tree src/main/java -L 4输出的层级基本就是答案。controller里每个RequestMapping前缀代表一个模块/admin、/user、/recycle、/points、/category。你会看到这个系统实际上就是围绕分类标准、回收预约、订单结算、积分明细四件事做数据库增删改查。这一步花不了几分钟但对后面的修改很有帮助——答辩或者二次开发时面试官和老师最常问的第一句不是“你这个系统性能怎么样”而是“项目分为哪几个模块表是怎么设计的”。能不看文档直接讲出这几层比背设计图要可信得多。2.3 数据库脚本先行用 source 命令先跑通 .sql再谈其他绝大多数这类压缩包里都会有一个sql/或db/目录里面放着db.sql、garbage.sql或干脆叫init.sql。正确顺序是先手动执行这份脚本建库建表再回去改连接配置最后启动项目。反过来的话Spring Boot 一启动就连不上库报Access denied或Unknown database你根本分不清是脚本没跑对还是配置没改对。执行脚本我建议用 mysql 命令行source比图形客户端更直接因为报错时能精确到行号。# 假设数据库账号 root先建库再导入注意要带 --default-character-set mysql -u root -p --default-character-setutf8mb4 # 进入 mysql 交互端后执行 CREATE DATABASE IF NOT EXISTS garbage_recycle DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE garbage_recycle; SOURCE /your/unzip/path/sql/db.sql; SHOW TABLES;参数说明--default-character-setutf8mb4是必须的很多老脚本用utf8在 MySQL 8 上插入 emoji 符号会报Incorrect string valueSOURCE后面跟绝对路径不要用相对路径否则会因为当前目录不对找不到文件。SHOW TABLES能看到多少张表取决于脚本内容一般不少于十张就说明数据模型完整。我见过不少脚本开头带了DROP DATABASE执行前先看一眼开头如果是DROP开头确认库里没有自己的数据再放行这就是很多人反复初始化最后把配置表清空的真实原因。2.4 配置文件四件套端口、数据源、日志路径、上传目录数据库跑通之后再看src/main/resources/application.yml或application.properties。这是整个压缩包里改错率最高的文件。常见做法是把配置集中到四件事上服务端口、数据源、日志输出、文件上传路径其余保持默认即可。下面是典型的application.yml内容代码里我把这种课设项目里最容易翻车的参数都标出来了。server: port: 8080 # 端口冲突时改这里建议先 netstat 查占用 servlet: context-path: / # 如果这里写了 /gc访问路径就是 http://localhost:8080/gc spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver # MySQL 8 必须用 cj别改回 com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/garbage_recycle?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8mb4allowPublicKeyRetrievaltrue username: root password: 你自己的密码 # 不要保留压缩包里的默认密码多半和本地不一致 thymeleaf: prefix: classpath:/templates/ # 视图前缀404 时优先查这里 suffix: .html mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.xxx.recycle.entity logging: file: name: logs/recycle.log # 建议先本地看看能否创建目录四个参数的注意点driver-class-name在 MySQL 8 下必须是com.mysql.cj.jdbc.Driver老项目里的com.mysql.jdbc.Driver会直接报ClassNotFoundExceptionserverTimezoneAsia/Shanghai是时间字段差 8 小时的头号原因不加它每次查到的都是 UTC 时间context-path如果配的不是/登录页跳转、静态资源引用全部要带前缀我配过context-path: /gc结果网页所有src路径都得手动补/gc血泪经验没有特殊要求就保持/logging.file.name指向的目录如果是相对路径从不同目录启动项目会生成两套日志排错时容易看错文件。改完配置文件先静态检查一遍再执行下一步启动。3. 把压缩包变成可运行系统从 IDEA 导入到首次访问的完整步骤3.1 导入前准备JDK、Maven 与 IDEA 三项对齐导入之前先用命令行检查本机环境避免 IDEA 里一堆红才回来查版本。Spring Boot 2.x 的课设项目都该用 JDK 8本地如果装了 11、17、21 多个版本IDEA 编译时会按项目结构配置走经常出现“代码编译过但启动报java.lang.UnsupportedClassVersionError”的情况。我一般会在项目根目录打开终端跑一次mvn -v确认 Maven 用的是哪个 JDK、配置的是哪个settings.xml。mvn -v # 期望看到 Java version: 1.8 或 8.xMaven home 指向你自己的安装目录如果显示 Java 版本是 17后面启动八成会挂在IllegalArgumentException: Unsupported class file major version上。处理方式不是卸掉本机高版本 JDK而是给项目指定 JDKFile → Project Structure → Project → SDK 选 1.8同时 Settings → Build Tools → Maven → Runner → JRE 也选 1.8。注意这一步经常被漏掉Maven Runner 的 JRE 和 Project SDK 是两个不同的设置只改后者不够这就是为什么很多人“明明 JDK 对编译还是报错”。IDEA 版本方面2020 到 2023 都兼容 Spring Boot 2.x 课设不要因为图新就上 2024 最新版然后顺手把 JDK 拉到 21这套源码大概率扛不住新版 Lombok 插件的差异。导入方式也简单File → Open选中解压目录里的pom.xmlIDEA 弹出 “Open as Project” 选择信任该 Maven 工程即可不需要新建空工程再复制源码。如果你拿到的是没有pom.xml的 SSM 老工程那就先新建一个空工程再把源码目录拷贝进src/main/java把 lib 下的 jar 用 Project Structure → Libraries 手动导入过程繁琐但可跑只是我不建议为了一个毕业设计去维护一个手工导包的工程改依赖太痛苦。3.2 让 Maven 先把依赖拉下来刷新、打包和三个失败信号导入之后第一步不是点启动类而是让 Maven 把依赖下载到本地仓库。右侧 Maven 面板点一下刷新按钮然后看 IDEA 底部进度条。常见的失败信号有三个Cannot resolve symbol SpringBootApplication、Could not find artifact org.springframework.boot:spring-boot-starter-parent、长时间停留在Downloading...不往前走。这三个信号基本都指向同一个原因——本地settings.xml里的镜像仓库不可用。# 第一次导入后建议直接打包试试能避开 IDEA 缓存导致的假报错 mvn clean package -DskipTests -U参数说明-DskipTests跳过测试代码编译和运行省时间-U强制刷新远程快照对作业模板这种依赖写死版本的场景帮助不大但第一次下载建议带上。如果命令行能打包成功IDEA 里还是红说明是 IDEA 缓存的锅用 File → Invalidate Caches / Restart 清缓存即可。如果连命令行都失败十有八九是镜像源的问题这个在避坑章节我会把那套settings.xml内容直接贴出来。另外一个很多人忽略的点检查本机 Maven 的settings.xml是不是被改坏了localRepository指向了一个不存在的目录比远程仓库失效更容易排查出来。3.3 初始化数据库并连接账号、密码、字符集一次配齐环境没问题后回来把数据源参数和 2.3 节建的库对上。对于接线我习惯先用 Navicat 或 DataGrip 这类客户端连一次能连上了再回来跑项目这样能把“数据库问题”和“项目配置问题”隔离开。这里把关键参数整理成一张表照着检查比逐个翻配置快。配置项值作用和踩坑点host127.0.0.1不要写 localhost部分 Windows 环境解析慢port3306装过多个 MySQL 实例的机器确认端口一致username / passwordroot / 本地实际密码压缩包里的默认密码是别人机器的必须改数据库名garbage_recycle和 2.3 建的库名严格一致大小写敏感Linux连接串参数useSSLfalse 等8.x 不加 allowPublicKeyRetrieval 会报公钥检索错误改完配置后启动时如果出现Access denied for user rootlocalhost先在客户端里用相同密码手动登录一次往往能发现是密码里带了#这类需要转义的符号。另一个高频问题是 MySQL 8 的默认认证插件是caching_sha2_password老版本 DBCP 驱动不支持解决方案是驱动用com.mysql.cj.jdbc.Driver并保证 mysql-connector-java 在 8.0.11 以上。确认无误后再回来启动项目。3.4 启动服务并完成首次访问启动类、默认账号和静态资源找到src/main/java下带SpringBootApplication的启动类类名常见的是Application.java或GarbageRecycleApplication.java。右键 Run看到Started Application in 5.8 seconds这类日志就说明启动成功。浏览器访问http://localhost:8080/如果 2.4 节里context-path没动过这就是入口地址。如果页面能打开但样式全丢优先查静态资源目录路径如果直接 404 或跳到/login说明有 Spring Security 或登录拦截器拦截器规则写在config包下答辩前的坑大多在这里。-- 大多数这种课程项目的默认管理员账号写死在初始化 SQL 里直接查 SELECT * FROM sys_user WHERE role admin; -- 或者 SELECT * FROM user WHERE user_type 1 LIMIT 5;常见的默认账号是admin、密码123456但不要凭印象猜一定用上面这条 SQL 去库里查。注意有些模板会把密码用 MD5 存登录时还要过一遍new Md5PasswordEncoder()所以直接在数据库把密码改成明文不一定能登录成功。老练点的做法是在登录接口打断点看传入的密码字段被加密了几次这样比肉眼猜算法快得多。首次登录成功后别急着点功能先看一遍sys_user表和登录 controller 的代码把“用户从哪来、密码怎么存、权限怎么拦”三个问题弄明白这是答辩时最常见的开场问题也是后面改功能绕不开的入口。3.5 跑通三条核心链路管理员、回收员、居民的角色验证系统能登录只是开始真正能称为“跑通了”的标志是三条业务链路都能走通。第一管理员链路登录后台进入分类管理页面做一次新增分类、编辑名称、删除分类的操作验证sys_category表数据变化。第二居民链路注册一个普通用户维护收货地址提交一笔回收预约单填写垃圾分类和预约时间看recycle_order里是否多了一条待处理记录。第三回收员链路换回收员账号登录接单、上门回收、填写实际重量、点击结算最后在用户积分明细里看到积分入账记录。-- 一条链路走完后用这条 SQL 验证数据闭环 SELECT o.order_no, o.status, o.est_weight, o.real_weight, p.points_change FROM recycle_order o LEFT JOIN points_record p ON o.id p.order_id WHERE o.user_id 1 ORDER BY o.create_time DESC;这条 SQL 能把订单和积分明细一次对上如果points_change为空说明积分服务没触发如果状态还停在“待接单”说明接单操作没走到更新状态的后端接口。跑链路这件事不能省因为很多压缩包里的页面按钮是摆设点了只是前端跳转后端接口根本没实现。答辩或二次开发前把三条链路跑一遍才能知道这套源码是真完整还是缺胳膊少腿。具体的状态流转字段和积分记账逻辑在下一章拆模块时详细讲。4. 核心业务模块拆解分类标准、回收订单、积分账务的落库逻辑4.1 垃圾分类标准表父级与子级的编码设计垃圾分类管理系统最基础的表是分类表这场管理系统的“地基”。常见的表设计不是一张大平表而是带父级 ID 的树形结构一级分类是可回收物、有害垃圾、厨余垃圾、其他垃圾二级分类是具体的玻璃、金属、塑料、电池、灯管。用父级 ID 而不是把两级字段硬放在同一行的原因在于后续新增三级分类时不用改表结构只需要往表里插数据。CREATE TABLE garbage_category ( id INT NOT NULL AUTO_INCREMENT, parent_id INT DEFAULT 0 COMMENT 父级分类 id0 表示一级分类, category_code VARCHAR(20) NOT NULL COMMENT 业务编码如 R001, category_name VARCHAR(50) NOT NULL COMMENT 分类名称如可回收物, recycle_price DECIMAL(10,2) DEFAULT 0.00 COMMENT 每公斤回收单价, points_rate INT DEFAULT 1 COMMENT 每公斤默认积分, status TINYINT DEFAULT 1 COMMENT 1 启用 0 停用, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_category_code (category_code) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT垃圾分类标准表;这个表的parent_id是最核心的字段查询二级分类时用WHERE parent_id ?查询一级分类及其子类时用WHERE parent_id 0先取根节点再在 Java 里递归组装树。要注意category_code的编码规则必须唯一很多模板里直接用自增 ID 做业务编码导致分类被删除重建后 URL 里的 ID 对不上。recycle_price和points_rate两个字段是这个系统的计量关键回收订单计算积分时会引用这两个值答辩时如果被问“积分规则从哪里来”答案就是这两个字段而不是代码里的魔法数字。参数选择上价格用DECIMAL(10,2)而不是浮点数避免0.1 0.2这类精度问题这也是 Java 面试题里常被问到的 BigDecimal 的实际工程背景。4.2 回收预约与订单状态机从下单到结算的字段流转回收预约是这个系统业务链路的主动脉。居民用户提交预约单回收员接单上门后称重更新实际重量最后管理员确认完成并结算积分。这个过程不能用裸露的status字段一改了之因为只要一个页面误操作订单就可能从“已完成”跳回“待接单”把结算也带错。正确做法是定义订单的状态机再在代码里校验只有特定状态才能转换到下一个状态。// 订单状态的枚举把状态流转拉直避免任意跳转 public enum OrderStatus { PENDING(0, 待接单, 1, 2), // 可流转到 1已接单和 2取消 ACCEPTED(1, 已接单, 2), // 可流转到 2已完成 FINISHED(2, 已完成, 3), // 可流转到 3已结算 CANCELED(3, 已取消, -1), SETTLED(4, 已结算, -1); public final int code; public final String desc; public final int[] allowedTransitions; OrderStatus(int code, String desc, int... allowedTransitions) { this.code code; this.desc desc; this.allowedTransitions allowedTransitions; } /** * 校验状态是否可以流转 * param from 当前状态码 * param target 目标状态码 */ public static boolean canTransit(int from, int target) { for (OrderStatus status : values()) { if (status.code from) { for (int allowed : status.allowedTransitions) { if (allowed target) return true; } } } return false; } }这段代码把订单状态变成了人眼可读的表待接单可以流向已接单或取消已接单只能流向已完成已完成必须再走结算才到已结算。实际应用时在 Service 层更新状态之前先调canTransit()不通过直接抛业务异常避免状态被无线程安全地乱跳。回收订单表里除了id、order_no、user_id、category_id之外还需要address、appoint_time、est_weight、real_weight、amount这些业务字段。其中order_no建议用时间加随机数生成比如yyyyMMddHHmmss 四位随机数不要用数据库自增 ID 直接当订单号因为履历上别人看得出你的单量而且并发时自增 ID 排到库里也不好看。4.3 积分账务明细表和余额必须解耦很多课程项目把积分余额当作user表的一个字段每次扣积分直接UPDATE user SET points points - 10 WHERE id ?。这是最容易被评审老师挑刺的设计没有流水、没有对账依据、万一扣减失败会静默丢积分。正确做法是把“积分流水明细”和“积分余额”拆成两张表用户当前积分是快照积分明细是事实余额由明细汇总而来。/** * 回收订单完成后给用户加积分并写流水事务保证两边同时成功 */ Transactional(rollbackFor Exception.class) public void settlePoints(RecycleOrder order) { // 1. 计算本次应得积分 实际称重重量 * 分类的积分系数 GarbageCategory category categoryMapper.selectById(order.getCategoryId()); int points BigDecimal.valueOf(order.getRealWeight()) .multiply(BigDecimal.valueOf(category.getPointsRate())) .intValue(); // 2. 写积分流水每笔订单一行明细 PointsRecord record new PointsRecord(); record.setUserId(order.getUserId()); record.setOrderId(order.getId()); record.setPointsChange(points); record.setReason(RECYCLE_SETTLE); pointsRecordMapper.insert(record); // 3. 再更新用户余额快照可延迟但这里同步更新便于展示 userMapper.addPoints(order.getUserId(), points); }这个方法的本质是三步算出应得积分、写明细流水、更新余额快照Transactional保证这三步要么全成功要么全回滚。要注意product_id和settle的顺序不能反先写流水再更新余额这样即使更新失败流水还在对账时能查出差异。points_rate在garbage_category表里的单位如果是“每公斤”real_weight的单位就必须是公斤不然积分会差 1000 倍这类单位不一致的问题在数据集里经常出现。积分明细设计还有个隐藏好处答辩现场被问“用户积分异常怎么排查”时直接说“查points_record明细即可”比说“我重启一下”要专业得多。4.4 统计报表按分类、按时间段的汇总 SQL管理后台大概率有一个“数据统计”页面展示回收总量、分类占比、每日订单数。这类统计需求在代码里写循环逐条计算是新手最容易踩的坑正确做法是直接用 SQL 聚合把计算下推到数据库Java 侧只负责接收结果。下面给两条最常用的统计 SQL一条按分类汇总重量一条按周统计订单量。-- 按一级分类汇总回收重量bps 是业务字段 parent_id 的扩展 SELECT c.category_name, IFNULL(SUM(o.real_weight), 0) AS total_weight FROM garbage_category c LEFT JOIN recycle_order o ON o.category_id c.id AND o.status IN (2, 4) -- 已完成和已结算的订单才算 WHERE c.parent_id 0 GROUP BY c.id, c.category_name ORDER BY total_weight DESC;-- 按自然周统计订单数和总重量注意 WEEK() 参数的含义 SELECT YEAR(create_time) AS year_no, WEEK(create_time, 1) AS week_no, COUNT(*) AS order_count, IFNULL(SUM(real_weight), 0) AS week_weight FROM recycle_order WHERE status IN (2, 4) GROUP BY YEAR(create_time), WEEK(create_time, 1) ORDER BY year_no DESC, week_no DESC;第一条 SQL 用LEFT JOIN保证没有订单的分类也显示为 0而不是直接消失IFNULL(SUM(...),0)处理空值避免前端展示null。第二条 SQL 里WEEK(create_time, 1)的第二个参数1表示周一作为一周的第一天中国用户习惯周一开始而 MySQL 默认值是周日开始这个坑不显眼但统计结果对不上时很难想到。两条 SQL 都适合放进 Mapper XML 里作为select配合resultTypemap返回前端拿到 List 直接渲染表格或图表不需要在 Java 里再加工。这一章拆出来的三个模块——分类树、订单状态机、积分流水——正是这个系统的业务骨架理解和改清楚这三块整个源码就算吃透了一半。5. 避坑章毕业设计源码跑起来之前的六个高频事故5.1 MySQL 8 连接报错Public Key Retrieval 与驱动类名不符现象项目点击启动后控制台报Unable to load authentication plugin caching_sha2_password或者Public Key Retrieval is not allowed数据库客户端却能正常连接。原因压缩包里的项目大多是在 MySQL 5.7 时代写的驱动连接串没有适配 8.x 的认证插件。MySQL 8 默认用caching_sha2_password老驱动第一次连接时要求客户端先获取服务端公钥但连接串里没开这个开关连接就被掐断了。解决按 2.4 节把jdbc:mysql://的 url 补全参数核心是allowPublicKeyRetrievaltrue和useSSLfalse再确认驱动是com.mysql.cj.jdbc.Driver。如果项目被迫一定要用老驱动则登录 MySQL 执行ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 密码;把认证方式降级但我不建议这么干还是统一升级到mysql-connector-java8.x 更省心。5.2 Maven 依赖下载失败私服镜像失效导致全项目标红现象IDEA 打开工程后所有依赖 import 都是红色Maven 面板里一堆Cannot resolve等待很久也不见下载完成命令行执行mvn clean package直接报Unable to download或连接超时。原因本机 Maven 的settings.xml配置的镜像仓库地址失效或网络不通。很多压缩包附带的.mvn/目录里写死了仓库配置IDEA 优先读取了它与你本机的内网环境不兼容。解决改本机 Maven 的conf/settings.xml把mirrors替换为国内可用的镜像源然后重开 IDEA 让配置生效。mirrors mirror idaliyun-public/id mirrorOfcentral/mirrorOf urlhttps://maven.aliyun.com/repository/public/url /mirror /mirrors这里只替换central镜像不要把plugins和releases也强行镜像否则部分插件在阿里云没有又会卡在下载。换完后在 IDEA 终端执行mvn clean package -U看到下载进度往前走就说明通了。如果换了镜像还是没动静检查本机是否开了 IDE 内置 HTTP 代理这个值会导致即便镜像正确也连不上把它关掉用直连通常就能解决。5.3 Lombok 注解全部报红IDEA 没开注解处理现象User.java、GarbageCategory.java等实体类上的Data、Slf4j全部波浪线标红编译时提示找不到方法getUserId()或log。原因Lombok 是通过编译期注解处理器生成 getter/setter 的两个条件必须同时满足项目依赖里有lombok这个压缩包一般都有IDEA 安装了 Lombok 插件并开启 Annotation Processing。默认情况下新版 IDEA 对 Maven 项目会自动启用但如果导入的是手工导包工程插件和开关经常是关的。解决先确认本机 IDEA 插件市场里有 Lombok 插件并安装然后在 Settings → Build, Execution, Deployment → Compiler → Annotation Processors 勾选Enable annotation processing。如果还是红检查编译时是否报了package lombok does not exist那是 pom 中scopeprovided/scope配置导致的这种项目打包时会把 Lombok 排除编译环境如果没装 Lombok 就会翻车把scope去掉即可。这个坑的隐蔽之处在于启动类没红、只有实体类红第二次遇到时能直接按“注解处理没开”来查。5.4 登录页样式全丢或点按钮后 404视图与静态资源路径不对现象浏览器能打开登录页但页面是纯 HTML 无样式或者登录后跳转/index直接 404控制台只有ThymeleafError resolving template。原因三类情况。第一application.yml里spring.thymeleaf.prefix没配或配错模板路径找不到第二页面 controller 用了RestController返回字符串Spring 把返回值当 JSON 而不是视图名第三拦截器拦了/css/**、/js/**等静态资源导致样式加载被 403。解决打开发送登录请求的后端接口看返回类型Controller且方法返回字符串时Spring 才会找对应模板RestController下的 String 返回值会直接写入响应体。按 2.4 节检查prefix: classpath:/templates/是否和实际模板目录一致实体的 HTML 文件放在src/main/resources/templates下CSS 放在static下结构错了就移动目录而不是改代码。如果是拦截器问题在 WebMvc 配置里加上excludePathPatterns(/static/**, /css/**, /js/**)。这类问题肉眼难察觉最快排查方法是在浏览器按 F12 看 Network 面板404 的请求是什么类型直接定位是模板问题还是静态资源问题。5.5 端口被占用与上下文路径导致打不开现象控制台报Web server failed to start. Port 8080 was already in use或者换了一个端口后依然无法访问页面。原因8080 被本机其他程序占用的概率很高常见占用者是微信开发者工具内置服务器、团队协作软件或上次调试没关掉的 Spring Boot 进程。另外context-path若被设置成非根路径访问时没带前缀页面会一直 404。解决先确认占用进程Windows 用netstat -ano | findstr :8080看到 PID 后用任务管理器确认是不是残留的 Java 进程是就直接结束任务。改端口时注意同时改三处application.yml的server.port、前端页面里写死的跳转地址、浏览器访问的 URL。如果context-path设了/gc登录后重定向的/admin/index也要写成/gc/admin/index。这类模板里前端页面的跳转地址常写死为localhost:8080/xxx改端口时 CtrlShiftF 全局搜一遍 8080能少走很多弯路。5.6 答辩现场“这套源码不是你自己写的”包名、README 与配置痕迹现象老师或面试官打开工程一眼看到包名是com.jwc19xxx这类陌生域名数据库脚本里留着原作者学校的xjtu_student_info表评审直接问“这个项目和你有什么关系”。原因恕我直言这类压缩包是从学长老师那里拷贝或个人中转站下载的里面留着原作者的包名、类名、README、数据库表前缀。不改直接交在评审眼里就是“一眼假”。解决不要只改个别姓名要动四处。第一把src/main/java下的包名全部改掉建议改成你自己的域名反写用 IDEA 的 Refactor → Rename 而不是手动挪文件夹否则依赖引用的 import 全断第二把数据库脚本里带学校或人名痕迹的备注、表前缀、测试数据删掉或替换统一成“城市垃圾分类回收管理系统”的命名体系第三重写 README只保留项目介绍、技术栈、启动步骤和功能模块不要照抄原文档里“本系统由 xx 设计”的字样第四把配置文件的注释改成自己写的语气这会让项目“像你的”远比只改几个文案更有说服力。同时至少把 4.1 到 4.3 里我讲的分类表、订单状态、积分流水这三段能讲清楚能对着数据库脚本讲出每一张表是干什么的这才是“你的东西”的实质证据。6. 让这份源码变成可持续维护的项目版本化、表驱动与一个导出功能拿到这套源码如果只改个名字交差下次还是要在同样的坑里爬一遍。三个小动作能让它更像一个正经工程也能在答辩或后续二次开发时提供实际价值。第一个动作是把数据库脚本纳入版本管理在项目根目录建db/migrations/目录初始脚本命名为V1__init.sql后续每次加表就新增V2__xxx.sql不要再去改 V1。这会让数据库变更看得见回滚有据可查和“直接用数据库同步软件拖整个库”相比这个做法成本低得多也更符合团队协作的惯例。第二个动作是消灭硬编码。很多模板项目里回收积分单价是散在 service 代码里的魔法数字改价要改代码重编译。每月调价应该做的是用这段代码从数据库读取当前配置而不是去改常量。// 表驱动每次取分类配置的最新价格和积分系数 GarbageCategory config categoryMapper.selectByCode(R001); BigDecimal pricePerKg config.getRecyclePrice(); int pointsPerKg config.getPointsRate();第三个动作是加一个顺手的小功能比如订单导出 CSV二十行代码能给项目增加一个实用的收尾功能也能在答辩时当作“我做的扩展功能”讲。/** * 导出指定日期区间的订单为 CSV直接用 HttpServletResponse 写回 */ GetMapping(/export) public void exportCsv(RequestParam String start, RequestParam String end, HttpServletResponse resp) throws IOException { ListRecycleOrder orders orderMapper.selectByDateRange(start, end); resp.setContentType(text/csv;charsetutf-8); resp.setHeader(Content-Disposition, attachment;filenameorders.csv); StringBuilder sb new StringBuilder(订单号,分类,重量,积分,状态\n); for (RecycleOrder o : orders) { sb.append(o.getOrderNo()).append(,) .append(o.getCategoryName()).append(,) .append(o.getRealWeight()).append(,) .append(o.getPoints()).append(,) .append(o.getStatusDesc()).append(\n); } resp.getWriter().write(sb.toString()); }这三件事做下来这套源码基本就脱离了“别人的遗留物”定位。我自己的习惯是拿到任何课设压缩包先做两件事把原始 ZIP 备份一份不动再在改完基本配置后跑一次三条主链路确认基线是绿的才碰业务逻辑。很多人在改包名时顺手把配置弄坏了备份能让你随时退回起点这就是我常说的后悔药。这套系统本身不复杂分类标准、订单状态、积分流水三条线抓住后它就是一台结构清晰的增删改查机器用对方法能很快吃透。希望帮到你。本文还有配套的精品资源点击获取