资讯动态

Vue+SpringBoot垃圾分类系统:项目解析、避坑与部署全攻略

发布时间:2026/10/27 17:20:12 来源:尧图企业网站定制
简介这是一套基于Vue与SpringBoot的垃圾分类系统完整设计项目面向毕业设计、课程设计、期末大作业等场景尤其适合计算机相关专业学生作为前后端分离开发实践参考。系统前端采用Vue框架构建用户查询、分类指导、反馈提交及管理员后台等交互界面后端由SpringBoot实现用户认证、垃圾数据管理、回收站管理、数据统计分析等业务逻辑并通过RESTful接口与前端通信。压缩包大小23.5MB包含437个文件其中Java源码96个、Vue组件51个、JavaScript脚本18个、SVG图标161个另有数据库脚本db.sql、垃圾分类回收系统表结构文档、基于web的垃圾分类回收系统论文以及一键安装、运行、编译的bat脚本代码、文档与部署辅助一应俱全。资源已有36人学习下载适合具备一定Java和前端基础的学习者深入研读。借助项目源码和论文材料可以系统掌握SpringBoot与Vue的数据交互方式、数据库表设计原则以及项目从环境搭建到部署上线的完整流程同时项目以垃圾分类为业务背景实现了查询、统计、管理等功能对未来开发同类型管理系统也具有迁移价值。1. 垃圾分类系统设计.zip这套VueSpringBoot项目到底是什么、能拿来做什么每年毕业季和求职季都会有一大批“基于Vue与SpringBoot的XXX系统”的压缩包在同学之间流转垃圾分类系统就是其中出现频率很高的一类。它的本质并不复杂前端用Vue做页面交互后端用SpringBoot提供接口配合MySQL存数据实现用户登录、垃圾名称查询分类、分类知识展示、积分奖励和后台管理这一整套闭环。之所以这类项目能一直流行是因为它业务边界清晰、数据库表不多、前端页面也直观特别适合作为全栈入门练手或者课程设计交付物。这篇文章不评价这份打包好的zip质量如何而是从“拿到之后怎么用起来”的角度把项目拆开、把环境配好、把常见坑填平让你能真正把这个项目跑起来并讲清楚它的设计逻辑。2. 先拆项目结构Vue前端与SpringBoot后端是怎么分工的2.1 解压后先别急着跑把目录结构看明白拿到打包好的zip第一步不是双击运行而是解压后把目录结构梳理清楚。常见做法是这类项目压缩包内包含三个主要部分前端工程通常以vue或web或frontend命名、后端工程通常以server或backend命名也可能直接是SpringBoot的Maven工程根目录、以及一个sql文件夹放数据库初始化脚本。有些打包不规范的项目还会带一份说明文档但不要依赖它很多说明文档都是复制粘贴的里面写着别人的数据库密码。我一般会用tree命令先看一遍目录层级确认前端和后端是不是分开了。如果前端文件全部堆在后端的src/main/resources/static里那说明作者可能做的是前后端混合部署Vue编译后的静态资源直接由SpringBoot托管运行逻辑会有差异。如果前后端目录分离则走的是标准的前后端分离方案开发时需要启动两个服务部署时再考虑用Nginx或者把dist包并进去。tree -L 3 -d注意-d参数只显示目录不显示文件3层深度足够让你判断工程结构了。执行后重点看有没有backend/pom.xml或者backend/build.gradle以及前端目录里有没有package.json和vue.config.js。这两个文件分别决定了后端依赖管理和前端构建配置缺任何一个都不是完整的可运行工程。2.2 数据库脚本是整套系统的地基先看sql文件垃圾分类系统的业务核心不在代码里在数据里。打开sql文件夹下的脚本文本第一件事看里面有没有INSERT语句。一套完整的垃圾分类系统必须预置四个基础分类可回收物、有害垃圾、厨余垃圾、其他垃圾以及若干条具体的垃圾条目数据比如“废电池-有害垃圾”“剩菜剩饭-厨余垃圾”。如果脚本里只有建表语句没有数据那你跑起来之后页面上什么都查不到会误以为程序坏了。典型的初始化数据长这样INSERT INTO waste_category (id, name, code) VALUES (1, 可回收物, recyclable), (2, 有害垃圾, harmful), (3, 厨余垃圾, kitchen), (4, 其他垃圾, other); INSERT INTO waste_item (name, category_id, search_alias, disposal_tip) VALUES (废电池, 2, 电池,干电池,充电电池, 投放至有害垃圾收集容器), (剩菜剩饭, 3, 剩饭,剩菜,厨余, 沥干水分后投放), (旧报纸, 1, 报纸,书籍,纸板, 叠放整齐后投放), (烟头, 4, 香烟,烟灰, 投放至其他垃圾收集容器);脚本里的search_alias字段是这类系统的灵魂。用户输入“废电池”能查到输入“电池”也应该能查到靠的就是这个别名列。查看脚本时留意这个字段是否填充了数据如果为空前端搜索逻辑做得再好也搜不出多义词的结果。另外确认建表语句用的是utf8mb4字符集否则输入中文垃圾名称时可能产生乱码这个坑后面章节会专门展开。2.3 核心数据模型四张表撑起整个垃圾分类业务绝大多数这类系统的数据库都维持在四到五张表正因为表少才适合用来学全栈。最基本的是waste_category分类表存四个分类名称和编码waste_item垃圾条目表存具体垃圾名称、所属分类ID和别名sys_user用户表存账号、密码、角色和积分points_record积分记录表存用户查询确认垃圾分类后获得积分的流水。有后台管理功能的系统还会加一张管理员表或者直接在用户表里用role字段区分管理员和普通用户。CREATE TABLE waste_item ( id int(11) NOT NULL AUTO_INCREMENT, name varchar(100) NOT NULL COMMENT 垃圾名称, category_id int(11) NOT NULL COMMENT 所属分类ID, search_alias varchar(200) DEFAULT NULL COMMENT 搜索别名, disposal_tip varchar(255) DEFAULT NULL COMMENT 投放提示, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_category (category_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT垃圾条目表;这里的category_id关联了分类表是查询的核心关联字段所以建索引是合理的。积分表的结构能看出系统设计者的水平是否区分了积分来源类型查询获得、签到获得、消费抵扣是否记录了操作时间。如果积分表里没有任何record_type字段说明系统只有单一积分逻辑后期扩展会异常痛苦。拿到项目后先把这几张表的字段过一遍你就大概知道这个系统的完成度了。3. 把核心业务落到SpringBoot垃圾查询与积分逻辑的接口设计3.1 Controller与Service分层搜索接口和积分接口的代码骨架SpringBoot项目最忌讳Controller里写满业务逻辑。看一个后端工程质量先看Controller是不是只做参数接收和结果返回。垃圾分类系统里最核心的接口是“根据关键词搜索垃圾分类”正常的写法是Controller只调Service方法真正的查询逻辑放在WasteItemService里。RestController RequestMapping(/api/waste) public class WasteItemController { Resource private WasteItemService wasteItemService; GetMapping(/search) public Result search(RequestParam String keyword) { ListWasteItemVO items wasteItemService.searchByKeyword(keyword); return Result.success(items); } PostMapping(/confirm/{itemId}) public Result confirm(PathVariable Long itemId, RequestParam Long userId) { wasteItemService.confirmClassification(itemId, userId); return Result.success(垃圾分类确认成功积分10); } }Result是统一响应体一般包含code、message、data三个字段。注意search接口用的是RequestParam接收前端传来的关键词而confirm接口把垃圾条目ID放在路径里这种设计比较符合REST风格。积分逻辑放在confirmClassification方法内部因为用户确认一次分类就要给一次积分同时要在积分记录表里写一条流水这两个操作必须在一个事务里完成。Service public class WasteItemServiceImpl implements WasteItemService { Resource private WasteItemMapper wasteItemMapper; Resource private PointsRecordMapper pointsRecordMapper; Override Transactional public void confirmClassification(Long itemId, Long userId) { WasteItem item wasteItemMapper.selectById(itemId); if (item null) { throw new BusinessException(垃圾条目不存在); } PointsRecord record new PointsRecord(); record.setUserId(userId); record.setWasteItemId(itemId); record.setPoints(10); record.setRecordType(add); pointsRecordMapper.insert(record); // 积分累加到用户表 LambdaUpdateWrapperSysUser updateWrapper new LambdaUpdateWrapper(); updateWrapper.eq(SysUser::getId, userId) .setSql(points points 10); sysUserMapper.update(null, updateWrapper); } }Transactional注解是这段代码的关键保证积分流水插入和用户积分累加要么都成功要么都失败避免用户积分加了但流水丢了。有些二手项目会在这里漏掉Transactional实际运行中一旦数据库异常积分就对不上账。如果你拿到的项目里这个注解缺失建议自己补上这在答辩时也是可以讲的优化点。3.2 模糊搜索的两种实现like查询与分词匹配垃圾名称搜索接口看起来简单但细节决定体验。最常见的实现是MyBatis-Plus配合like条件做模糊查询一条SQL就能搞定但有个明显的缺陷如果垃圾名称是“废电池”用户输入“电池”能查到输入“废电”也能查到但输入“lei电池”这种带拼音的输入就查不到。用户实际使用场景里很多人记不住垃圾准确名称只会输入模糊词甚至拼音关键词。public ListWasteItemVO searchByKeyword(String keyword) { LambdaQueryWrapperWasteItem wrapper new LambdaQueryWrapper(); wrapper.like(WasteItem::getName, keyword) .or() .like(WasteItem::getSearchAlias, keyword); ListWasteItem items wasteItemMapper.selectList(wrapper); // 补充垃圾分类名称 return convertToVO(items); }这里用.or()把名称匹配和别名匹配串起来实现“一个关键词命中两个维度”。但要注意如果后续再加条件.or()的优先级容易出问题常见做法是把条件包在嵌套的and()里wrapper.and(w - w.like(WasteItem::getName, keyword) .or() .like(WasteItem::getSearchAlias, keyword));这一段是不少新手会忽略的地方不加括号的话后续一旦追加categoryId等过滤条件生成的SQL条件组合就错了。至于拼音匹配需要在数据表里额外加拼音列或者用HanLP这类分词工具在搜索前做转换这点到最后一章再展开。3.3 SpringBoot整合MyBatis-Plusmapper扫描与分页配置垃圾分类系统的数据库操作基本都是单表简单查询用MyBatis-Plus比直接用MyBatis省掉大量重复的XML文件。项目启动报“找不到Mapper”或者“Invalid bound statement”错误大半是MapperScan没有扫到Mapper接口所在的包或者XML文件路径和mapper-locations配置不一致。spring: datasource: url: jdbc:mysql://localhost:3306/garbage_system?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver mybatis-plus: mapper-locations: classpath*:mapper/**/*.xml configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl map-underscore-to-camel-case: true global-config: db-config: id-type: auto启动类上要配合MapperScan(com.example.garbage.mapper)包路径写错是这类项目的头号启动报错来源。log-impl配置建议留上开发阶段能在控制台直接看到SQL语句排查查询问题非常有用部署到生产环境再关掉。serverTimezoneAsia/Shanghai这个参数必填否则MySQL 8.x连接时会因为默认时区问题直接报错后面避坑章节会细说。4. 打通Vue前端到SpringBoot接口查询页与后台管理页的联动4.1 Vue项目初始化与依赖安装从npm install到项目跑起来前端工程拿到手先看package.json里的依赖版本。这类项目流行用Vue 2配合Element UI因为Element UI的表格、表单、弹窗组件写后台管理页面非常顺手也有新一点的用Vue 3配Element Plus。无论哪个版本第一步都是安装依赖。cd frontend npm install npm run servenpm install执行后如果报错一大片先看Node版本。Vue 2的旧项目在Node 18以上的环境里经常出现node-sass编译失败因为node-sass需要从二进制包下载匹配当前Node版本的编译文件下载失败就直接报错。遇到这种问题先检查package.json里用的是node-sass还是sass前者建议替换成sassnpm uninstall node-sass npm install sass --save-devnpm run serve启动成功后控制台会打印一个本地地址默认是http://localhost:8080。如果这个端口被占用Vue CLI会默认改到8081。这一步要注意因为后端SpringBoot默认也是8080端口看到前端启动在8080就以为一切正常实际联调时前端连后端8080端口结果访问的是自己接口全部404。4.2 Vue页面调用SpringBoot接口axios封装与请求路径Vue前端请求后端接口的常用做法是封装一个统一的axios实例把baseURL、拦截器、错误处理集中在一个文件里。垃圾分类系统的请求大部分集中在登录、搜索、积分查询这几个模块封装一次能省大量重复代码。import axios from axios const request axios.create({ baseURL: /api, timeout: 10000 }) request.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers[Authorization] token } return config }) request.interceptors.response.use( response { const res response.data if (res.code ! 200) { alert(res.message || 请求失败) return Promise.reject(new Error(res.message)) } return res }, error { alert(网络异常请检查后端服务是否启动) return Promise.reject(error) } ) export default request注意baseURL写的是/api而不是http://localhost:8080/api这是为了让开发环境的代理配置接管请求转发。如果直接写后端地址会立刻撞上跨域问题浏览器会拦截响应接口明明能通但前端就是拿不到数据。Authorization头带上token是为了保持登录状态很多二手项目压根没做这个拦截器导致每次刷新页面路由都跳回登录页。在页面上调用时按Vue 2的Options API写法就是methods: { async searchWaste() { const res await request.get(/waste/search, { params: { keyword: this.keyword } }) this.resultList res.data } }这样/api/waste/search经过代理转发到后端就是http://localhost:8080/api/waste/search。4.3 前端打包放进SpringBoot把dist目录变成静态资源项目最终交付或者部署到服务器一般不会同时跑两个服务而是把Vue打包后的静态资源交给SpringBoot托管。这是热搜词“vue打包放进springboot中”对应的场景做法分两步npm run buildVue构建完成后frontend/dist目录下会生成index.html、css、js等静态文件。把整个dist目录里的内容复制到后端工程的src/main/resources/static下再重新mvn package打包SpringBoot启动后直接访问http://localhost:8080就能看到前端页面不再需要单独启动Vue开发服务器。mvn clean package -DskipTests java -jar target/garbage-system-0.0.1-SNAPSHOT.jar需要注意每次前端代码修改后都要重新npm run build并复制文件这个流程重复性强所以实际项目中更推荐前端用Nginx部署、后端用SpringBoot独立部署这样前后端可以分别迭代。但如果只是毕业设计演示把dist塞进SpringBoot里是最省事的方案。4.4 配置开发代理一张图看懂为什么axios连不上后端开发模式下前端跑在8080端口后端跑在8080或者9090端口浏览器访问前端页面时页面里的fetch(/api/waste/search)请求目标是前端服务器必须通过代理转发才能落到后端。这个配置在vue.config.js里module.exports { devServer: { port: 8080, proxy: { /api: { target: http://localhost:8081, changeOrigin: true } } } }这段配置通常放在frontend/vue.config.js文件里。changeOrigin: true很关键它会让后端收到的请求头里的Host字段变成后端地址规避部分后端框架对Host的校验。如果代理配好后接口依旧404优先检查后端SpringBoot项目的server.port到底是多少很多二手项目的配置文件里改过端口而vue.config.js里的target还是默认的8080。后端若设置了server.servlet.context-path那接口路径还会多一层前缀比如项目访问路径是http://localhost:8081/garbage/api/waste/search代理target后面也要带上/garbage这是联调时最容易忽略的一处。5. 避坑指南这类SpringBootVue项目最常见的5个翻车点5.1 MySQL版本与驱动问题启动直接报错的头号原因现象SpringBoot启动时抛java.sql.SQLException: The server time zone value Öйú±ê׼ʱ¼ä is unrecognized或者提示ClassNotFoundException: com.mysql.jdbc.Driver。原因MySQL 8.x版本的驱动类已经变成com.mysql.cj.jdbc.Driver连接串必须指定serverTimezone旧项目里写的com.mysql.jdbc.Driver是MySQL 5.x时代的驱动SpringBoot 2.7以上的版本默认驱动换成了新的。解决确认本地MySQL版本8.x就用com.mysql.cj.jdbc.Driver连接串末尾加上?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai。如果数据库是5.7保持旧驱动和连接串即可但建议也加上useSSLfalse避免SSL握手告警。5.2 端口冲突与上下文路径接口全部404的元凶现象前端页面能正常打开但搜索接口全部返回404。启动Vue服务时看到端口被占用自动改到了8081而后端的接口恰好也在8080起了一个服务前后端接口请求串到了Vue自身的服务上。原因前后端端口设计不一致。Vue脚手架在8080端口被占用时会自动1后端如果恰好也用8080就会产生这种互相打架的情况。解决调整后端application.yml中的server.port统一规划。我一般习惯后端固定用8081前端开发用8080这样代理转发目标明确不会因为端口自动偏移导致问题。另外如果后端设置了context-path只让/api前缀的请求走正式接口其他路径返回404要确认代理配置里target地址是否带上了这个前缀。5.3 Node版本过高导致npm install失败依赖装不上的玄学现场现象npm install卡住不动或者报gyp ERR! build error、node-sass: Command failed甚至有经验的人会直接把node_modules删了重装结果还是失败。原因node-sass这类原生依赖需要下载对应Node版本的二进制文件Node 18环境下很多旧版node-sass已经没有预编译包可以下载了会回退到源码编译但本机往往没有安装完整的编译工具链于是失败。解决不升级Node版本的情况下直接换掉node-sass。在package.json里找到sass-loader对应的版本把node-sass依赖删掉换成sassDart Sass。如果项目用的Vite构建配置css.preprocessorOptions.scss.additionalData时可能还需要同步处理全局变量导入这类小坑属于换依赖之后的连锁反应遇到报错再查对应配置即可。另一个更粗暴但省事的办法是安装NVM切换到Node 14版本旧项目基本都能顺利跑通。5.4 前后端分离下的登录状态与token刷新就掉登录是设计问题现象登录成功后跳转首页一切正常但按一下F5刷新页面又跳回登录页。前端请求带着用户信息后端却没有这个人的会话。原因很多二手项目用session存登录状态但前后端分离部署后前端域名和后端域名不一致浏览器默认不携带第三方CookiesessionId传不到后端登录态自然就丢了。解决改成前后端约定token的认证方式。登录接口返回一个token字符串前端存在localStorage里后续请求通过axios拦截器把token放进Header的Authorization字段后端用拦截器校验这个token并解析出用户信息。如果不想大改可以在后端配置CORS时显式允许携带凭证allowCredentials(true)同时前端axios要设置withCredentials: true。但这个方案只适合开发和演示线上部署还是会因为Cookie跨域限制出问题。能改token方案就改token方案这是这类项目从“课程设计”走向“可部署应用”的关键一步。5.5 图片上传与静态资源路径垃圾分类宣传图为什么会白屏现象后台管理里上传的垃圾分类宣传图片在本地开发时能正常显示部署到服务器后全部变成裂图或者刷新页面后图片消失。原因上传图片的代码写的是本地绝对路径比如D:/upload/2024/xx.png数据库里存了这个路径前端直接用这个路径访问图片。换一台机器运行或者部署到Linux服务器后这个路径根本不存在。另外SpringBoot默认不开放本地磁盘静态资源映射直接用绝对路径访问肯定404。解决写一个配置类继承WebMvcConfigurer把本地上传目录映射为虚拟路径/upload前端图片地址统一以/upload开头访问Configuration public class WebConfig implements WebMvcConfigurer { Value(${file.upload-dir}) private String uploadDir; Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler(/upload/**) .addResourceLocations(file: uploadDir /); } }file.upload-dir在application.yml里配置成绝对路径开发环境指向本机目录生产环境指向服务器目录这样项目管理图片才不会因为路径飘移而白屏。6. 部署与进阶让这套垃圾分类系统从“跑起来”变成“拿得出手”6.1 用宝塔面板把前后端部署到一台服务器上既然项目是前后端分离的部署时最省心的方案就是前端Nginx托管后端Java进程独立运行。用宝塔面板操作的话流程很直接后端用mvn clean package -DskipTests打jar包传到服务器在宝塔的“Java项目”里添加jar运行指定端口前端把dist目录上传到Nginx的站点根目录配置好反向代理/api到后端端口。Nginx配置核心就这一段location /api/ { proxy_pass http://127.0.0.1:8081; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }proxy_pass注意末尾的斜杠决定了路径是否透传。以http://127.0.0.1:8081结尾不带斜杠请求/api/waste/search会原样转发带斜杠的话可能丢失/api前缀后端接口如果你的项目里有多一层context-path这里很容易配错。部署完记得检查数据库地址是否从localhost改成了服务器的实际IP以及数据库密码是否更新了。6.2 加分项改造给搜索加上拼音首字母支持这套系统做完核心功能之后有一件事值得花一个晚上去做给垃圾名称搜索加上拼音匹配。用户输入“laji”或者“feidianchi”也能找到对应分类这个体验一下就超过了绝大多数同类毕业设计答辩时作为一个亮点讲非常加分。实现方式不复杂在waste_item表增加一列pinyin_alias写一个一次性脚本把已有数据的垃圾名称转成拼音全拼搜索时同时匹配名称、别名、拼音三个字段wrapper.and(w - w.like(WasteItem::getName, keyword) .or().like(WasteItem::getSearchAlias, keyword) .or().like(WasteItem::getPinyinAlias, keyword));不追求全拼完整只对垃圾名称里每个字取拼音首字母也够用比如“废电池”转成“fdc”用户输入“fdc”也能命中。这类小改动成本低、效果直观是我在多个类似项目上验证过的思路。6.3 验收时怎么证明系统是真的能用项目做完或者拿到手改完最后要过一遍核心链路注册新账号、登录、输入“废电池”搜索、确认分类、查看积分增加、后台新增一条垃圾数据、再回到前台搜索这条新数据。按这个顺序走一遍全部通了系统才算真正交付。我习惯在验收时把后端日志打开搜索请求发出后肉眼确认SQL语句里keyword参数有没有正确传入这一步能排查掉八成“前端传参格式不对”的问题。每拿到这样一个VueSpringBoot全栈项目我都会先把数据库脚本、端口配置、Node依赖三件事检查完再动手改代码这个习惯让我少踩很多坑。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑