ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Spring Boot垃圾分类管理系统:从数据库设计到前后端分离实战

Spring Boot垃圾分类管理系统:从数据库设计到前后端分离实战 1. 接到这个题目后我第一件事是划清“管理”和“识别”的边界如果你打开搜索引擎查“基于Spring Boot的环保垃圾分类管理系统”会看到大量论文和开源项目。但说实话很多项目一看就是从“CRUD模板”里复制出来的功能表写得天花乱坠点进去连一个完整的业务闭环都没有。我这次重新梳理这个题目时先做的一件事不是写代码而是把“垃圾分类管理”这个概念的边界划清楚。先明确一个很容易混淆的点这个系统本质上是一个“管理系统”不是一个“识别系统”。它能做的是把用户、垃圾类别、投放记录、积分奖励、公告反馈这些数据管起来而不是像AI视觉项目那样识别一张图片里是什么垃圾。当然你可以在设计里留出扩展点后续接入图像识别模型但核心功能一定是围绕“人—垃圾—记录—积分”这条业务链走的。那“管理”到底体现在哪我把它拆成了四个层面知识管理垃圾分类标准不是静态写在页面上的而是放在数据库里由管理员动态维护。哪类垃圾属于可回收、哪类属于有害都能增删改查而不是写死在前端。行为管理用户每次投放的记录时间、垃圾类型、重量或数量都要入库形成行为轨迹。这既是为了积分计算也是为了给社区或学校提供数据统计的基础。激励管理积分规则、积分流水、积分兑换这是让用户“愿意分类”的关键环节。没有激励闭环系统就是一个纯记录工具用户活跃度会非常低。信息管理公告发布、意见反馈、投诉处理这些周边功能看起来简单但反而是管理员最常使用的功能。角色权限上我当时设计了三类用户普通用户、环保管理员、系统管理员。普通用户能查看分类指南、提交投放记录、查看积分、兑换商品环保管理员能维护分类知识库、审核投放记录、发布公告、处理反馈系统管理员则负责账号权限、数据统计和系统设置。这三类角色落在数据库里就是一张用户表加一个角色字段或角色表权限控制通过拦截器或Spring Security实现。这个题目有价值的地方在于它要求你真正理解“一个可用系统”需要哪些模块而不是堆功能。也就是说你要输出的是一套能跑通“用户注册—查询分类—填写投放—获得积分—查看排行—管理员审核—数据统计”全流程的完整作品而不是几十个互不关联的页面。后文我会把实现路径逐步展开。2. 数据库设计五张核心表如何把分类逻辑真正落进MySQL我见过不少毕业设计项目代码写得稀烂但数据库表设计却非常扎实——反过来也成立哪怕是毕业设计表设计如果混乱整个项目后期全是补丁。垃圾分类管理系统这类业务表数量不需要很多但每张表之间的关系必须清晰。我最终的核心表大概有这些表名用途关键字段关联关系user用户信息表id, username, password, nickname, role, points, avatar与积分流水、投放记录关联waste_category垃圾分类标准表id, name, type, description, icon_url与投放记录中的垃圾类型关联recycle_record投放记录表id, user_id, category_id, weight, images, location, status, create_time关联用户和分类points_flow积分流水表id, user_id, change_type, points, description, create_time关联用户notice/feedback公告表与反馈表id, title, content, create_time / user_id, content, reply公告面向全体用户反馈关联用户最有设计感的是waste_category这张表。它不能只放“可回收、有害、厨余、其他”四条固定记录因为分类标准在各地是动态变化的。我设计成两个层面一级分类四个大类和二级分类具体物品明细。一级分类用type字段区分二级分类通过parent_id自关联挂在对应一级分类下。比如“废旧纸张”属于“可回收”parent_id指向可回收这个大类的id。这样设计的好处是管理员不需要改代码只要在后台维护明细数据前端页面就会自动同步更新。recycle_record表是整个业务流的枢纽。一条记录要能回答以下问题谁投的、投了哪类垃圾、多重或多少件、当时在哪投放的、是否有图片证明、审核状态如何、对应产生多少积分。所以字段除了基本外键还有weight、status待审核/已通过/已驳回、audit_time、audit_remark等。这里有一个很关键的逻辑积分的产生不直接在recycle_record表里算而是审核通过后通过事务同时写入points_flow表并更新用户表的总积分。这样分表存储既保证积分流水可追溯也避免用户总积分字段被反复用SELECT SUM计算导致性能问题。关于积分规则我没有把规则硬编码而是专门建了一张points_rule配置表存储“每公斤可回收垃圾积多少分、每单厨余垃圾多少分”这类规则。投放记录里通过外键关联到具体的规则记录后续如果要调整积分策略改配置表即可代码不用动。这里强烈建议你在设计时留一个deleted逻辑删除字段——这在 MyBatis-Plus 里是标配的全局逻辑删除功能。毕业设计答辩时被问到“数据怎么防误删”这是个很加分的细节。另外create_time和update_time用数据库自动填充DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_TIMESTAMP不要让前端传入这样数据时间一定可信。3. Spring Boot分层实现Controller、Service、Mapper各管一摊事很多初学者写Spring Boot项目喜欢把全部业务逻辑写在Controller里导致一个接口四五百行。这个项目的规模不大但依然要严格走分层结构因为答辩时面试官最在意的就是有没有工程化思维。我的目录结构是这样划分的controller包只负责接收请求参数、调用Service、返回统一响应体。不写任何if (xxx ! null)这种业务判断只做参数最简单的收口。service包承载业务逻辑比如积分计算、审核通过后的联动更新、分类知识库的变更。事务注解Transactional必须加在Service层方法上而不是加在Controller方法上。mapper包继承 MyBatis-Plus 的BaseMapperT用最简单的CRUD方法复杂查询用Select注解或 XML 文件写 SQL。entity包对应数据库表的实体类字段用 Lombok 的Data注解简化getter/setter表名和实体名映射用TableName明确指定。common包放统一响应体ResultT、全局异常处理GlobalExceptionHandler、常量定义、JWT工具类等。这里我挑几个真正有事说的细节讲。第一个是统一响应体。我和前端约定的格式是{ code: 200, message: 操作成功, data: {} }所有接口都返回这个结构前端只用判断code是否为200即可。ResultT里我用了泛型这样data可以是任何类型。为了生成方便我写了三个静态方法Result.success()、Result.success(data)、Result.error(code, message)。这样Controller里一行就能返回。第二个是全局异常处理。Spring Boot里用RestControllerAdvice加ExceptionHandler就能统一捕获异常。我分了三类处理业务异常BusinessException比如积分不足、重复提交、参数校验异常MethodArgumentNotValidException、兜底的系统异常。特别注意参数校验我用了ValidatedNotBlank这类注解校验不通过时会被全局处理器捕获并转成友好的提示信息而不是直接把框架默认的英文报错抛给前端。Service层实现方面拿“投放记录提交”这个核心接口举例它的完整流程是接收前端的RecycleRecordDTO校验用户ID、分类ID、重量是否合规。根据分类ID查points_rule表算出本次应得积分。插入recycle_record记录状态为“待审核”。先不生成积分流水等管理员审核通过后再在auditRecycleRecord()方法里通过Transactional同时更新记录状态、写入points_flow、累加用户积分。这里有一个非常容易踩的坑如果你在提交记录时就把积分算给用户而管理员审核时发现数据造假驳回那积分流水就得做冲正非常麻烦。我第一版就是这么写的后来在测试联调时发现积分流水极其混乱。改成审核后再加积分之后整条链路就清晰了很多。这个经验希望你直接抄作业。4. 权限与安全拦截器、密码加密和XSS过滤一个都不能少垃圾分类管理系统是个带用户体系的项目安全这块如果不做答辩时被问一下“你这个接口是不是谁都能调”会很被动。我在这套项目里做了三层基础安全设计。第一层是登录状态校验。用JWT生成token登录成功后返回给前端前端在后续请求头里带上Authorization: Bearer token。后端写一个拦截器HandlerInterceptor在preHandle里解析token验证通过才放行。这里有一个细节不需要引入Spring Security那么重的框架因为项目角色只有三种用拦截器加自定义注解就能控制权限。我定义了一个RequireRole注解标注在Controller方法上值为admin或user。拦截器里从token解析出的角色如果不符合直接返回403。比如recycle_record的审核接口标注RequireRole(admin)普通用户访问就会被拦截。这样做的好处是权限逻辑和业务代码解耦组里每个人都能看懂。第二层是密码存储。密码绝对不能明文入库。我用的是BCrypt算法通过Spring Security自带工具类只引入spring-security-crypto这个jar不需要全量Security做加密和校验。注册时BCrypt.hashpw(password, BCrypt.gensalt())加密后存储登录时BCrypt.checkpw校验。你问为什么不用MD5因为MD5加盐不够规范且速度太快容易被暴力破解BCrypt自带高强度盐值对毕业设计来说已经是满分方案。第三层是XSS过滤。这个是我踩过不少坑的地方。Spring Boot中如果前端提交的内容包含script标签后端直接存入数据库再原样返回就会产生存储型XSS漏洞。解决方案是写一个请求包装器HttpServletRequestWrapper重写getParameter和getInputStream方法把lt;、gt;、quot;之类的危险字符转义后再传给Controller。这里有一个极其关键的注意点不要对文件上传接口做XSS转义。如果前端上传的是图片或PDF你强行对InputStream里的二进制内容做字符串替换文件就直接损坏了。我当时的处理方式是只对getParameter做转义文件流走getInputStream的接口单独放行。这也是项目中全局过滤器最容易出问题的地方。如果你是初学者我建议这个XSS过滤用一个OncePerRequestFilter配合自定义的XssWrapper实现。不需要引入第三方库核心代码也就五六十行。它能让你在答辩时自信地说出“我考虑到了常见Web攻击中的XSS”这是非常加分的亮点。5. 前端对接与文件上传Vue页面怎么和这套后端打通这个项目热词里出现了 “springboot vue前后端分离”所以前端我就按Vue来聊。Vue端我是用 Vue 3 Element Plus 做的后台管理界面普通用户端则是用了另一套更简洁的移动端页面通过user-agent判断跳转。整体是前后端分离开发后端纯提供JSON接口前端通过Axios请求数据。联调阶段遇到最多的坑基本集中在三类跨域、token传递、参数类型不匹配。跨域问题的标准解法是后端配置CORS。我在项目里加了一个CorsConfig配置类放行了本地开发时的localhost:5173Vite的默认端口和localhost:8080。注意如果你用了拦截器CORS配置必须在拦截器之前生效否则预检请求OPTIONS会直接被拦截器拦截返回401浏览器就报跨域错误。这个顺序问题我当初调试了一上午才反应过来。Token传递这块前端Axios统一了请求拦截器每次请求前从localStorage里取token放进请求头。后端如果校验失败返回401前端响应拦截器会自动清空本地token并跳到登录页。这样用户重新登录后不需要手动清缓存。参数类型不匹配的问题最容易出现在“重量”这种字段上。用户在前端填的是“1.5公斤”后端接收用的是BigDecimal如果前端传的是字符串“1.5”Spring Boot的自动转换能处理但如果前端传的是“1.5kg”这种带单位的值后端就会直接报400。这是一个典型的类型约定问题。我的建议是前后端约定好重量字段统一传数字类型单位前端展示时拼接不往后端传。这个约定写进接口文档里后面基本不会再出错。文件上传这块我要多说几句。投放记录允许上传垃圾照片这个功能在系统中很常见。我当时面临两个选择本地存储还是接入对象存储服务本地存储最简单项目里配置一个上传目录文件按日期存放返回给前端的URL是类似http://ip:8080/uploads/2024/05/xx.jpg这样。但这有一个问题如果你用Docker部署容器重启后上传目录可能丢失如果不挂载卷。对象存储服务呢虽然可靠但要额外引入依赖和配置对一个毕设来说增加了复杂度。最终我两个方案都实现了一遍。本地存储方案主要用于单机演示为了稳妥起见我把上传目录挂载在宿主机上对象存储则作为后续扩展方向在文档里写明。这里我可以给你一个建议毕设阶段优先做本地存储但代码要留出切换的接口。我当时写了一个FileStorageService接口本地存储和对象存储两个实现类都实现了这个接口通过配置项切换ConditionalOnProperty。这样既保证了演示可行答辩时又能说“这个模块可以无缝对接对象存储”属于典型的低成本高回报设计。6. 配置文件与部署细节application.yml里的那些事先写好的坑配置这块是Spring Boot项目里最不起眼但最容易出状况的部分。我先说版本问题再给一套可直接用的配置参考。热词里有一条“springboot版本太高”这句话我理解很多。确实如果你用了 Spring Boot 3.x那JDK必须是17以上而且很多老版本的依赖库比如某些分页插件会不兼容。我做这个项目选的是Spring Boot 2.7.18它是2.x系列的最终版本支持JDK 8生态最成熟绝大多数教程、插件、面试题都基于这个版本。如果你不是专门想研究新特性2.7.18是安全性最高的选择。application.yml我放几个核心段落作为参考spring: datasource: url: jdbc:mysql://localhost:3306/green_waste?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver servlet: multipart: max-file-size: 10MB max-request-size: 50MB jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8 mybatis-plus: configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0 server: port: 8080这里有几个容易被忽略但必须说清楚的关键点数据库连接串里的serverTimezoneAsia/Shanghai必须加否则MySQL 8.0默认时区和本地时间对不上所有时间字段会差8小时。这个坑我见过太多人踩了包括我当年第一次写连接串也漏过。map-underscore-to-camel-case: true让数据库的create_time自动映射到实体的createTime不需要你手写每个查询的AS别名。log-impl设置成StdOutImpl后控制台会打印完整SQL日志联调阶段特别有用。上线前记得关掉否则生产日志全是SQL。全局逻辑删除配置好之后MyBatis-Plus 的所有查询会自动追加WHERE deleted 0删除操作自动变成UPDATE ... SET deleted 1。这个机制对数据审计非常友好。Docker部署这个环节我给出一份实际的Dockerfile和docker-compose.yml结构。后端镜像用openjdk:8-jre-alpine把打好的jar包直接复制进镜像暴露8080端口即可。Compose文件里把MySQL也一起编排进去挂载数据卷保证数据库重启不丢数据。FROM openjdk:8-jre-alpine COPY target/waste-system.jar app.jar ENTRYPOINT [java, -jar, /app.jar]version: 3 services: mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: 123456 MYSQL_DATABASE: green_waste volumes: - ./mysql-data:/var/lib/mysql app: build: . ports: - 8080:8080 depends_on: - mysql实际部署时你只需要在服务器上执行docker-compose up -d然后访问http://服务器IP:8080就能看到后端接口文档Swagger或前端页面。这里提醒一个细节如果你的服务器带宽较小首次构建依赖时下载会很慢建议本地先把jar包打好Dockerfile里直接用COPY而不是在容器里用Maven重新构建。7. 答辩展示与后续扩展这套系统还能往哪些方向加分最后聊点答辩和项目展示的经验。功能做完只是第一步怎么把你的设计思路讲清楚、让评委觉得“这个项目是有思考的”是需要单独准备的。我在展示这套系统时遵循的是一个“业务场景驱动”的叙事结构从“居民不知道怎么分类、管理人员难以统计”这个痛点说起讲如何通过“知识库 投放记录 积分激励”解决然后落到具体的表结构和接口设计上。而不是按“登录模块、注册模块、公告模块”这种功能清单一条条念那样评委听了三分钟就走神了。具体的加分点有三个。第一个是数据统计的可视化。我加了一个简单的首页统计看板用ECharts柱状图展示“各类垃圾投放占比”、“近7天投放趋势”。数据源就是recycle_record表按分类和时间维度做GROUP BY统计。工程量不大但演示效果非常直观评委一看就知道这套系统有价值。第二个是可以扩展的方向——OCR识别辅助分类。前端用户在投放垃圾时如果不知道属于哪类可以上传一张照片后端可以预留一个接口对接OCR组件识别照片上的文字或物品返回可能的分类。这个接口可以做成先不实现具体逻辑、只返回默认分类的“模拟接口”。答辩时说明“当前版本预留了该扩展点可通过替换实现类对接具体模型”就能体现你对项目边界和演进方向是有认识的。第三个是高阶玩法——基于HanLP的评论关键词分析。我们系统里有反馈功能用户会提交“小区垃圾桶太少”、“某类垃圾不知道扔哪”。这些文本数据加到一定程度后可以用HanLP分词做简单的高频词统计看看居民的共性问题集中在哪些词上。这样可以告诉评委你不仅做了业务系统还具备用算法分析业务数据的能力。这个扩展并不需要真正的算法背景调用封装的API即可。如果你还有余力把前端的部署也改成Nginx反向代理实现前端静态资源由Nginx提供、API反向代理到后端8080端口那整个项目的工程化完整度就又上了一个台阶。个人体会是这套系统做完之后的收获远不止能跑通一个毕业设计它覆盖了完整的CRUD、权限、事务、文件、安全、部署、前端联调全栈链路相当于一次对Spring Boot相关技术的全面体检。你在做项目时遇到的每个问题都能在后续求职面试里转化成值得讲的案例。
返回列表