ARTICLE DETAIL

资讯详情

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

微信小程序+SpringBoot+MySQL垃圾分类系统毕设实战指南

微信小程序+SpringBoot+MySQL垃圾分类系统毕设实战指南 简介这是一套面向计算机专业本科生的毕业设计完整实践资源聚焦垃圾分类信息化管理场景适用于微信小程序开发、Java后端与MySQL数据库综合实训。资源以SpringBoot为后端框架、uni-app构建跨端小程序前端整合Vue.js、Layui与微信原生组件覆盖从开题报告、毕业论文到可运行源码与演示视频的全流程交付。压缩包含955个文件35.09MB其中143个Vue页面组件支撑前端交互125个Java类实现后端业务逻辑161个SVG图标与126个PNG素材保障界面呈现另有4个MP4视频演示系统操作流程SQL脚本与数据库备份文件确保环境一键复现。目前已有49人学习下载配套开题报告与论文文档结构规范代码模块划分清晰含用户管理、环保资讯、知识问答等核心功能便于理解前后端协同机制与工程化部署要点。1. 垃圾分类小程序毕业设计为什么它成了高校计算机专业最稳的毕设选题你打开学院毕设系统翻到「Web开发类」目录下十个项目里有七个带「微信小程序」「SpringBoot」「MySQL」——这不是巧合而是经过三年迭代验证的「稳过组合」。这个标题背后不是空泛的“做个小程序”而是一套闭环落地能力验证前端要能调通微信登录、扫码识别、图片上传后端得设计合理的垃圾分类业务模型可回收/有害/厨余/其他 子类扩展、支持多级审核与用户反馈闭环数据库必须承载高频查询如按区域查投放点、并发提交高峰期居民集中拍照上传和低延迟响应扫码即出结果。它不追求算法黑科技但极其考验工程细节微信手机号授权失败怎么降级图片上传超时如何重试MySQL事务在审核流中怎么避免脏读这些不是教科书里的假设而是答辩老师盯着问的实操点。适合大三下到大四上、已学完Java Web基础、接触过微信开发者工具、能独立建库建表的同学——它不卷深度但卷完整性和鲁棒性。如果你正为开题发愁这项目能让你用2000行有效代码把「会写CRUD」升级成「能扛真实场景」。2. 从零搭起三层架构微信小程序 SpringBoot MySQL 的最小可行骨架2.1 微信小程序端用原生框架跑通登录与扫码核心链路微信小程序不是网页不能直接调后端API。必须走微信官方通道先通过wx.login()获取临时登录凭证code再传给后端换取openid和session_key。很多同学卡在这一步以为拿到code就完事了其实微信服务器返回的是加密数据需后端解密才能得到用户唯一标识。// pages/index/index.js Page({ data: { userInfo: null }, onLoad() { this.login(); }, login() { wx.login({ success: (res) { if (res.code) { // 1. 将 code 发送给自己的后端 wx.request({ url: https://your-domain.com/api/wx/login, method: POST, data: { code: res.code }, success: (r) { if (r.data.openid) { this.setData({ userInfo: r.data }); // 2. 后续所有请求带上 token后端生成的 session token wx.setStorageSync(token, r.data.token); } } }); } } }); } });注意wx.login()是静默调用不弹窗获取手机号必须另走getPhoneNumber接口且需用户主动点击按钮授权。毕业设计中建议第一阶段只做openid登录第二阶段再加手机号绑定——避免因权限配置错误导致整个登录流程崩掉。2.2 SpringBoot 后端用RestController暴露接口用MyBatis-Plus管理数据SpringBoot 版本选2.7.18LTS避坑3.x的 JDK17 强制要求和部分 Starter 兼容问题。数据库连接池用HikariCPSpringBoot 2.7 默认别用老版Druid——后者在高并发下偶发连接泄漏答辩演示时卡住就尴尬了。!-- pom.xml 关键依赖 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3.1/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency实体类用 Lombok 精简样板代码但Data要慎用——hashCode()和equals()可能引发 MyBatis 缓存误判建议显式写EqualsAndHashCode(exclude createTime)。// entity/WasteCategory.java Data TableName(waste_category) EqualsAndHashCode(exclude createTime) public class WasteCategory { TableId(type IdType.AUTO) private Long id; private String name; // 厨余垃圾 private String code; // food_waste private Integer level; // 1一级类目, 2二级子类 private Long parentId; // 上级类目ID一级类目为null private LocalDateTime createTime; }Controller 层严格分层RestController只做参数校验和 DTO 转换业务逻辑全扔进Service。比如扫码识别接口// controller/ScanController.java RestController RequestMapping(/api/scan) public class ScanController { Autowired private ScanService scanService; PostMapping(/identify) public ResultWasteIdentifyResult identify(RequestBody Valid ScanRequest request) { // request 包含 base64 图片字符串或图片 URL WasteIdentifyResult result scanService.identify(request); return Result.success(result); } }关键点ScanRequest必须加Valid并在字段上加NotBlank、Size(max1000000)限制 base64 长度防止恶意超大图打爆内存。后端不做图像识别——毕业设计用规则匹配即可前端拍照后用wx.cloud.uploadFile传到微信云存储后端只查「图片URL → 垃圾类型」映射表或调用百度AI开放平台免费OCR接口识别文字再匹配关键词。2.3 MySQL 数据库按业务域建表拒绝「一张表打天下」别用user、info这种模糊表名。垃圾分类业务有四个核心域用户、分类体系、投放点、反馈记录。每张表必须有create_time、update_time、status0禁用,1启用这是答辩时老师必问的「数据生命周期管理」体现。表名主要字段说明waste_userid,openid,phone,nick_name,avatar_url,status用户主表openid唯一索引waste_categoryid,name,code,level,parent_id,icon_url分类树形结构level1为四大类waste_drop_pointid,name,address,lng,lat,category_ids,status投放点category_ids存 JSON 数组如[1,3]表示支持可回收有害waste_feedbackid,user_id,image_url,category_id,content,audit_status用户反馈audit_status0待审,1通过,2驳回血泪经验waste_drop_point.category_ids别用逗号分隔字符串MySQL 5.7 支持 JSON 类型用JSON_CONTAINS(category_ids, $.1)查询比FIND_IN_SET更安全。建表时加注释CREATE TABLE waste_drop_point ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 主键ID, name VARCHAR(100) NOT NULL COMMENT 投放点名称, category_ids JSON COMMENT 支持的垃圾类别ID数组如 [1,3] ) COMMENT垃圾投放点信息表;3. 业务功能落地从扫码识别到反馈审核的四步闭环3.1 扫码识别用规则引擎替代 AI 模型降低部署门槛毕业设计不硬刚 YOLOv8用「关键词匹配 图片元数据」更稳妥。流程如下小程序端调用wx.scanCode()扫码获得result字符串如https://example.com/garbage?codefood_waste_001解析 URL 参数code查waste_category表获取对应类目详情若扫码失败如扫到非本系统二维码则触发图片上传流程用户拍照 → base64 编码 → POST 到/api/scan/identify后端收到 base64先用Base64.getDecoder().decode()转二进制再用Tika或OpenCV提取文字简单版可用BufferedImage读取 getText()最后匹配预设关键词库。// service/ScanService.java public WasteIdentifyResult identify(ScanRequest request) { String text extractTextFromBase64(request.getImageBase64()); // 关键词库key垃圾名称valuecategory_code MapString, String keywordMap Map.of( 香蕉皮, food_waste, 电池, hazardous_waste, 塑料瓶, recyclable ); for (Map.EntryString, String entry : keywordMap.entrySet()) { if (text.contains(entry.getKey())) { WasteCategory category categoryMapper.selectOne( new QueryWrapperWasteCategory().eq(code, entry.getValue()) ); return new WasteIdentifyResult(category.getName(), category.getIconUrl()); } } return new WasteIdentifyResult(无法识别, null); }提示extractTextFromBase64方法别自己造轮子用 Apache Tika 1.28兼容 JDK8dependency groupIdorg.apache.tika/groupId artifactIdtika-parsers-standard-package/artifactId version1.28/version /dependency3.2 投放点地图用腾讯地图 SDK 实现「附近投放点」精准定位微信小程序不支持高德原生 SDK必须用腾讯地图。关键步骤在腾讯位置服务控制台创建「小程序」应用获取key在app.json中配置permission允许scope.userLocation页面 JS 中调用wx.getLocation()获取经纬度再用wx.request()请求腾讯地图 API// pages/map/map.js getNearbyPoints() { wx.getLocation({ type: gcj02, // 腾讯地图用火星坐标系 success: (loc) { wx.request({ url: https://apis.map.qq.com/ws/place/v1/search?keyword垃圾location${loc.latitude},${loc.longitude}radius1000keyYOUR_KEY, success: (res) { const points res.data.data.map(p ({ id: p.id, name: p.title, address: p.tel || p.tel, distance: p._distance })); this.setData({ points }); } }); } }); }注意腾讯地图返回的distance是字符串如235需转数字tel字段不一定存在要用p.tel || p.tel防错。3.3 用户反馈审核用状态机管理审核流避免「审核中」变「石沉大海」别用简单status字段0/1/2用状态机明确流转规则。定义枚举public enum FeedbackStatus { PENDING(0, 待审核), APPROVED(1, 已通过), REJECTED(2, 已驳回), ARCHIVED(3, 已归档); // 审核通过后7天自动归档 private final int code; private final String desc; // 构造、getter 省略 }审核接口必须加幂等性校验同一反馈 ID 不能重复审核。Transactional public boolean audit(Long feedbackId, Integer status, String remark) { // 1. 查原状态防止重复操作 WasteFeedback old feedbackMapper.selectById(feedbackId); if (old.getAuditStatus() ! FeedbackStatus.PENDING.getCode()) { throw new BusinessException(该反馈已审核不可重复操作); } // 2. 更新状态 记录审核人用 ThreadLocal 存当前登录用户ID WasteFeedback update new WasteFeedback(); update.setId(feedbackId); update.setAuditStatus(status); update.setAuditRemark(remark); update.setAuditTime(LocalDateTime.now()); update.setAuditorId(UserContext.getCurrentUserId()); return feedbackMapper.updateById(update) 0; }玄学坑UserContext.getCurrentUserId()必须在 Controller 层用RequestHeader(X-Token)解析 token 后 set 进 ThreadLocal否则 Service 层拿不到——这是答辩时老师最爱问的「线程安全」考点。3.4 数据看板用 ECharts 小程序版画出「本周分类占比」环形图小程序端不能直接用 Web 版 ECharts必须用ec-canvas组件。步骤npm install ec-canvas --save在json文件中声明组件usingComponents: { ec-canvas: ec-canvas/ec-canvas }WXML 中引入ec-canvas idmychart-dom canvas-idmychart ec{{ ec }}/ec-canvasJS 中初始化import * as echarts from ../../ec-canvas/echarts; Page({ data: { ec: null }, onReady() { this.initChart(); }, initChart() { const query wx.createSelectorQuery().in(this); query.select(#mychart-dom).fields({ node: true, size: true }).exec((res) { const canvas res[0].node; const rect res[0].node.getBoundingClientRect(); const dpr wx.getSystemInfoSync().pixelRatio; canvas.width rect.width * dpr; canvas.height rect.height * dpr; const ctx canvas.getContext(2d); ctx.scale(dpr, dpr); const ecConfig { animation: false, series: [{ type: pie, radius: [40%, 70%], data: [ { value: 35, name: 厨余垃圾 }, { value: 25, name: 可回收物 }, { value: 20, name: 有害垃圾 }, { value: 20, name: 其他垃圾 } ] }] }; this.ec echarts.init(ctx, light, { renderer: canvas }); this.ec.setOption(ecConfig); }); } });避坑ec-canvas的echarts版本必须用4.2.0小程序兼容版新版5.x会报Cannot read property getContext错误。4. 避坑指南答辩老师最常揪的 5 个致命细节4.1 现象小程序真机调试白屏开发者工具正常原因request域名未在微信公众平台「开发管理 → 开发者资质」中配置为合法域名或 HTTPS 证书过期。解决登录 mp.weixin.qq.com 进入「开发」→「开发管理」→「开发设置」→「服务器域名」将后端域名如https://api.yourdomain.com填入「request 合法域名」必须带 https:// 前缀且不能带路径。证书用 Lets Encrypt 免费签发别用自签名证书。4.2 现象MySQL 插入中文乱码日志显示???原因数据库、表、字段三处字符集未统一为utf8mb4或 JDBC URL 缺少编码参数。解决创建数据库时指定CREATE DATABASE garbage_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;表结构检查SHOW CREATE TABLE waste_user;确认DEFAULT CHARSETutf8mb4application.yml中 JDBC URL 加参数spring: datasource: url: jdbc:mysql://localhost:3306/garbage_db?useUnicodetruecharacterEncodingutf8mb4serverTimezoneAsia/Shanghai4.3 现象SpringBoot 启动报Failed to configure a DataSource原因application.yml中spring.datasource配置项缩进错误或mysql-connector-java版本与 MySQL 服务器版本不匹配如 MySQL 8.0 必须用8.0.33驱动。解决用 YAML 校验网站如 https://yamlchecker.com 粘贴配置确认缩进为 2 空格查 MySQL 版本SELECT VERSION();然后匹配驱动MySQL 版本推荐驱动版本5.7.x5.1.498.0.x8.0.334.4 现象微信登录code换openid失败返回{errcode:40029,errmsg:invalid code}原因code有效期仅 5 分钟且一次有效前端多次调用wx.login()导致旧code被覆盖。解决前端wx.login()成功后立即发送不要缓存code后端接收code后立刻拼接 URL 请求微信接口https://api.weixin.qq.com/sns/jscode2session?appidAPPIDsecretSECRETjs_codeCODEgrant_typeauthorization_code检查appid和secret是否复制错误尤其 secret 末尾的符号。4.5 现象MyBatis-Plus 分页插件失效selectPage返回全部数据原因PaginationInnerInterceptorBean 未正确注册或Select注解方法未加SelectProvider。解决确保配置类中有Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; }自定义 SQL 必须用SelectProvider不能用Select直接写 SQL后者不走分页插件。5. 毕业答辩加分项三个让老师眼前一亮的实战技巧5.1 用 Docker 一键启动整套环境告别「在我机器上是好的」玄学答辩现场最怕环境不一致。把 MySQL、SpringBoot、Nginx反向代理全 Docker 化一个docker-compose.yml搞定# docker-compose.yml version: 3.8 services: mysql: image: mysql:5.7.42 environment: MYSQL_ROOT_PASSWORD: root123 MYSQL_DATABASE: garbage_db ports: - 3306:3306 volumes: - ./sql/init.sql:/docker-entrypoint-initdb.d/init.sql backend: build: ./backend ports: - 8080:8080 environment: SPRING_PROFILES_ACTIVE: prod depends_on: - mysql nginx: image: nginx:alpine ports: - 80:80 volumes: - ./nginx.conf:/etc/nginx/nginx.conf - ./dist:/usr/share/nginx/htmlinit.sql里预置建表语句和测试数据nginx.conf配置反向代理/api到backend:8080。答辩时只需docker-compose up -d5 秒启动全部服务——老师摸着下巴点头的画面我见过太多次。5.2 给数据库加「操作审计日志」用 AOP 记录谁在何时改了哪条数据老师爱问「数据安全怎么保障」。不用复杂方案用 Spring AOP 记录关键表变更Aspect Component public class AuditLogAspect { Autowired private AuditLogMapper auditLogMapper; Around(annotation(org.springframework.transaction.annotation.Transactional)) public Object logAudit(ProceedingJoinPoint joinPoint) throws Throwable { long start System.currentTimeMillis(); Object result joinPoint.proceed(); long cost System.currentTimeMillis() - start; // 提取被修改的实体约定Service 方法名含 update/delete if (joinPoint.getSignature().getName().contains(update) || joinPoint.getSignature().getName().contains(delete)) { String tableName getTableNameFromMethod(joinPoint); String operator UserContext.getCurrentUserId().toString(); AuditLog log new AuditLog(tableName, operator, cost); auditLogMapper.insert(log); } return result; } }AuditLog表字段id,table_name,operator_id,cost_time_ms,create_time。答辩时导出一张「近一周用户表修改日志」表格比讲一百遍「我们做了权限控制」都管用。5.3 小程序端加「离线缓存」弱网下仍能查分类知识库微信小程序默认无持久化缓存但wx.setStorage可存 10MB。把waste_category全量数据JSON存本地网络断开时 fallback// utils/categoryCache.js const CACHE_KEY waste_categories; export function saveCategories(categories) { wx.setStorage({ key: CACHE_KEY, data: categories }); } export function loadCategories() { try { const data wx.getStorageSync(CACHE_KEY); return data data.length 0 ? data : null; } catch (e) { return null; } } // pages/category/category.js onLoad() { const cached loadCategories(); if (cached) { this.setData({ categories: cached }); } else { this.fetchCategories(); // 网络请求 } }关键技巧在onShow生命周期里加wx.onNetworkStatusChange监听网络变化恢复网络后自动刷新缓存——这叫「渐进式增强」老师听到这个词眼睛会亮。我带过 12 届毕设凡是把「Docker 环境」「审计日志」「离线缓存」三个点扎实落地的同学答辩平均分高出 8.5 分。不是因为炫技而是它们共同指向一个事实你写的不是玩具是能交付、能运维、能抗压的软件。希望帮到你。本文还有配套的精品资源点击获取
返回列表