ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

智慧校园微信小程序毕设实战:Java后端+MySQL从搭建到答辩

智慧校园微信小程序毕设实战:Java后端+MySQL从搭建到答辩 简介这份智慧校园管理系统毕业设计源码包基于微信小程序JavaMySQL实现面向计算机相关专业毕业生或课程设计者可快速理解前后端分离的校园管理平台开发思路。资源总计1759个文件涵盖339个vue前端页面、224个java后端接口、184个json配置、85个wxml/wxss小程序页面及sql数据库脚本等包体约41.01MB。系统功能覆盖用户认证、课程表查询、图书馆服务、校园活动、成绩查询等模块后端提供完整API接口前端小程序封装交互并配套环境说明、数据库表设计、答辩PPT等文档便于从0到1复现与扩展。已有114人学习下载适合需要完整可运行毕设项目、参考小程序端与Java端联调机制的开发者。1. 这套智慧校园毕设包是什么拆开看它的技术选型与使用人群又到毕设季微信小程序毕业设计的需求几乎占了我这里咨询量的一半其中「智慧校园管理系统」又是出现频率最高的那一类。java 后端 微信小程序 MySQL再加一份 LW论文文档这个组合几乎是国内计算机类毕设的标配形态。它解决的问题很直接让一个只有 Java 基础、没独立做过完整系统的学生在两个月内交付一个前端能点、后端能查、数据库有数据、论文有截图的闭环系统。这套系统的典型场景是学生通过小程序查课表、看通知、查成绩、提交请假管理端在 Web 或小程序里维护学生信息、课程安排、公告发布。核心价值在于它覆盖了「登录鉴权、角色区分、CRUD、文件展示」这几块毕设答辩必问的内容。适合三种人想快速跑通一个完整项目再改造成自己题目的学生想拿现成架构补业务模块的 Java 初学者以及需要一套可演示 demo 做课程设计的在校生。2. 从 ZIP 到能跑环境准备、目录解读与前后端启动的最小路径拿到 zip 包之后最怕的是解压完对着几十个文件夹发呆。先别急着点启动花十几分钟把项目的骨架看清楚后面能省下一下午的排错时间。2.1 先给项目定调前后端分离的经典三层结构这套系统虽然标题写的是「java 小程序」但大多数源码包内部是标准的前后端分离结构。你会在压缩包里看到至少四个东西后端工程Maven 结构、小程序前端目录、数据库脚本通常是 .sql 文件、LW 文档。simple-upms/ # 后端 Java 工程Maven 结构 ├── src/main/java # Java 源码按 controller/service/mapper 分层 ├── src/main/resources # 配置文件 application.yml、mapper xml └── pom.xml # Maven 依赖声明 ├── miniprogram/ # 微信小程序前端目录 │ ├── pages/ # 页面文件夹 │ ├── app.js # 小程序入口逻辑 │ ├── app.json # 页面注册与全局配置 │ └── utils/ # request 封装、工具函数 ├── sql/ # 数据库初始化脚本 └── LW/ # 论文文档通常是 Word 或 PDF后端分层是经典的 Controller → Service → Mapper 三层Controller 接收小程序端的请求Service 写业务逻辑Mapper 用 MyBatis 操作 MySQL。前端小程序通过 wx.request 发起 HTTP 请求到这个后端接口拿到 JSON 数据再渲染到页面上。注意每个源码包的目录命名不一样有的后端叫 server有的叫 back-end小程序文件夹有的叫 miniprogram有的叫 pages。不用背名字找「有 pom.xml 的是后端有 app.json 的是小程序前端」这个规律就够了。2.2 环境准备JDK、Maven、MySQL、微信开发者工具的版本搭配这套技术栈最怕的不是代码难而是版本不配套导致启动失败。我一般建议按下面这套组合装踩坑最少组件推荐版本说明JDK1.88u201 以上绝大多数毕设后端基于 Spring Boot 2.xJDK 8 最稳Maven3.6.x不要用最新的 4.x镜像源和插件兼容性容易出问题MySQL5.7 或 8.08.0 需要改驱动名和时区参数下文细说微信开发者工具稳定版即可用测试号 AppID 也能编译运行IDEIDEA 2020 或 Eclipse推荐 IDEA社区版免费够用有个容易被忽略的点是 Maven 的 settings.xml 镜像。国内网络直接拉中央仓库依赖会非常慢甚至超时失败。建议先把仓库镜像配到阿里云mirror idaliyunmaven/id mirrorOfcentral/mirrorOf name阿里云公共仓库/name urlhttps://maven.aliyun.com/repository/public/url /mirror这段配置放在 Maven 安装目录下的 conf/settings.xml 里或者用户目录下的 .m2/settings.xml 中。mirrorOf 写 central 表示只镜像中央仓库不会影响其他私服配置。如果拉依赖的时候你看到 pom.xml 里一堆红色波浪线或者控制台报Cannot resolve symbol SpringBootApplication八成是依赖没下全。这时候不要反复点刷新先确认镜像配置对不对再在 IDEA 的 Maven 面板里执行 clean install。MySQL 安装完以后记得把 root 密码设置成符合源码里配置的值。很多毕设源码的数据库密码直接写在 application.yml 里最常见的是 root/123456还有 root/root 的。你可以在后续自己改回安全密码但第一次跑通建议先用源码默认值减少变量。2.3 启动前先看懂三块关键配置数据库连接、小程序 AppID、接口地址后端能否启动成功百分之七十取决于 application.yml 里的数据库配置。通常长这样server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/smart_campus?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 123456 mybatis: mapper-locations: classpath:mapper/*.xml configuration: map-underscore-to-camel-case: true这里三个参数最关键。driver-class-name如果是 MySQL 8.0必须用com.mysql.cj.jdbc.Driver用老的com.mysql.jdbc.Driver会直接启动报错url里的serverTimezoneAsia/Shanghai是 MySQL 8.0 的强制要求不加会报时区异常map-underscore-to-camel-case开了以后数据库里的create_time字段能自动映射到 Java 的createTime没开的话查询结果会一堆 null。如果你在 zip 包里没找到 application.yml 而是 application.properties也没关系核心配置项就是那几行写法换一下而已。小程序端的配置要看两处。第一处是app.js里的全局变量通常定义了baseUrl或apiBaseUrl// app.js App({ globalData: { // 开发环境下指向本机后端地址 baseUrl: http://localhost:8080 } })第二处是project.config.json里的 appid。如果没有自己的小程序 AppID可以先在微信公众平台注册一个测试号或者用开发者工具里的「测试号」选项只是部分 API比如真机预览会受限。2.4 一键启动顺序与验证后端启动成功日志、小程序编译通过启动顺序有讲究。正确顺序是先启动 MySQL 并导入数据库脚本再启动 Java 后端最后打开微信开发者工具。数据库导入用命令行最直观mysql -u root -p123456 sql/smart_campus.sql导入成功后验证一下表是否完整SHOW TABLES;常见表有t_user、t_student、t_course、t_notice这类前缀带 t_ 的表。如果 SHOW TABLES 出来是空的说明导入失败检查一下 sql 文件里有没有CREATE DATABASE语句如果文件里只建表没建库你得手动先建库再导入。后端启动在 IDEA 里找到启动类类名通常叫Application或SmartCampusApplication带SpringBootApplication注解右键 Run。看到Started Application in X.XX seconds就是成功了。小程序端启动打开微信开发者工具导入 miniprogram 目录AppID 填测试号编译后如果首页能加载数据说明前后端链路已经通了。提示如果小程序页面白屏且控制台报url not in domain list是开发工具默认校验合法域名导致的在「详情 → 本地设置」里勾掉「校验合法域名」即可这是开发阶段的常规操作。3. 后端实现拆解用户表设计、鉴权逻辑与查询接口怎么写才经得起答辩后端是答辩时被追问最密集的部分。把表结构、登录鉴权、查询逻辑这三块吃透答辩基本就稳了。3.1 数据表设计核心表与字段user / student / course / notice智慧校园的数据表设计通常围绕「角色」和「业务」两条线展开。角色线解决谁在用什么业务线解决具体做什么。角色线至少三张表用户表t_user、学生表t_student、教师表t_teacher。用户表存登录凭证学生表存学号、班级、专业等档案信息。这两张表通过user_id关联而不是把学生所有字段塞进用户表这是答辩时能说清楚的第一个设计亮点。CREATE TABLE t_user ( id INT NOT NULL AUTO_INCREMENT, username VARCHAR(50) NOT NULL COMMENT 登录账号, password VARCHAR(100) NOT NULL COMMENT MD5或BCrypt加密后的密码, role TINYINT NOT NULL DEFAULT 2 COMMENT 1管理员 2学生 3教师, status TINYINT NOT NULL DEFAULT 1 COMMENT 1启用 0禁用, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_username (username) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户表;password 字段千万不能存明文。常见做法是 MD5 后加盐或直接用BCryptPasswordEncoder。答趴时如果被问「密码安全性怎么保证」能说出至少两层加密方案就已经超过平均水平。业务线围绕「校园日常生活」展开课程表t_course、课表t_timetable、通知公告t_notice、失物招领t_lost_found。这套系统的业务不重但覆盖面广刚好覆盖了 CRUD 的每个操作类型。3.2 登录与鉴权token 怎么生成、拦截器怎么放行毕设里最常被问到的就是「你怎么知道当前请求是谁发的」这个问题的答案是 token 或 session。现在毕设源码主流用 token因为小程序不像浏览器那样天然支持 Cookietoken 在请求头里带前后端分离更自然。登录接口的核心逻辑很简单查询用户是否存在 → 校验密码 → 生成 token → 返回用户信息和 token。PostMapping(/login) public Result login(RequestBody LoginRequest req) { // 1. 根据用户名查用户 User user userMapper.selectByUsername(req.getUsername()); if (user null) { return Result.error(用户不存在); } // 2. 校验密码MD5后比对 String md5Pwd DigestUtils.md5DigestAsHex(req.getPassword().getBytes()); if (!user.getPassword().equals(md5Pwd)) { return Result.error(密码错误); } // 3. 用户被禁用则拒绝登录 if (user.getStatus() 0) { return Result.error(账号已被禁用); } // 4. 生成tokenUUID简单可靠毕设阶段不需要引入JWT String token UUID.randomUUID().toString().replace(-, ); tokenMapper.save(token, user.getId()); // 5. 返回给前端 return Result.success(new LoginResponse(token, user)); }这段代码里每步都值得在答辩时展开讲。第二步为什么要 MD5 而不是明文第三步为什么要禁用状态字段第四步为什么用 UUID 而不用 JWT——因为毕设项目没有分布式部署需求UUID 存在库表里够用且实现简单JWT 的优势在这种单应用场景体现不出来说清楚这个权衡反而显得你懂取舍。有了 token 之后需要一个拦截器拦截所有需要登录的接口。逻辑是从请求头里拿 token查到一个有效 token 就放行查不到就返回 401。public class AuthInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token request.getHeader(token); if (token null || token.isEmpty()) { response.setStatus(401); return false; } Integer userId tokenMapper.getUserIdByToken(token); if (userId null) { response.setStatus(401); return false; } // 把userId放到请求上下文里后续Controller可以取 request.setAttribute(userId, userId); return true; } }注意拦截器只是「拦」还要在配置类里告诉 Spring「哪些接口要拦、哪些放行」。登录接口本身必须放行否则就死循环了。3.3 查询接口的答辩点分页参数与 SQL 注入毕设的管理端列表页几乎全部要走分页查询。分页做得好不好是区分「自己写过」和「背了套代码」的试金石。小程序端请求列表接口时最常见的参数设计是pageNum和pageSize后端返回一个带total的对象这样前端才能渲染分页组件。GetMapping(/notice/list) public Result listNotices(RequestParam(defaultValue 1) Integer pageNum, RequestParam(defaultValue 10) Integer pageSize, RequestParam(required false) String title) { // PageHelper做分页底层是拦截器自动拼接LIMIT PageHelper.startPage(pageNum, pageSize); // title参数支持模糊查询使用CONCAT避免拼接SQL ListNotice list noticeMapper.selectListByTitle(title); PageInfoNotice pageInfo new PageInfo(list); return Result.success(pageInfo); }对应的 Mapper XML 里模糊查询的正确写法是select idselectListByTitle resultTypecom.example.entity.Notice SELECT * FROM t_notice where if testtitle ! null and title ! AND title LIKE CONCAT(%, #{title}, %) /if /where ORDER BY create_time DESC /select用#{}而不是${}传参能避免 SQL 注入。这里我用CONCAT(%, #{title}, %)而不用%#{title}%是因为后者在 MyBatis 里会被当作普通字符串查不出结果。这是新手在 mapper 里最容易犯的错。4. 小程序端对接登录、列表渲染、请求封装与真机调试注意点小程序端看似只是「套页面」但坑都在细节里。跟我说的方法走能把联调时间砍掉一半。4.1 小程序的目录结构与工具函数小程序前端的核心文件是app.js、app.json、app.wxss和pages目录下的页面文件。pages 下每个功能一个文件夹比如pages/login/、pages/home/、pages/course/每个文件夹里一对四件套.js、.wxml、.wxss、.json。先做一个统一请求封装不然每个页面都写一遍wx.request到后期想改接口地址会想死。常见的做法是在 utils 里写一个request.js// utils/request.js const BASE_URL getApp().globalData.baseUrl function request(url, method GET, data {}) { return new Promise((resolve, reject) { // 从缓存里拿token登录后存进去 const token wx.getStorageSync(token) wx.request({ url: ${BASE_URL}${url}, method: method, data: data, header: { Content-Type: application/json, token: token }, success: (res) { // 后端返回的code为200表示成功 if (res.data.code 200) { resolve(res.data.data) } else if (res.statusCode 401) { // token失效跳转登录页 wx.removeStorageSync(token) wx.reLaunch({ url: /pages/login/login }) reject(new Error(未登录)) } else { reject(new Error(res.data.msg || 请求失败)) } }, fail: (err) reject(err) }) }) } module.exports { request }这个封装做了三件很重要的事统一带 token、统一处理 401、统一返回数据体。后续每个页面的请求都走这个函数代码量能少三分之一。参数method默认 GETdata默认空对象页面传参时不用每次写全。4.2 从 wx.login 到拿到自己的 token登录链路实现小程序的登录和我们平时在网页里输入用户名密码不太一样。微信生态的常规流程是前端调wx.login拿到一个临时code把 code 发给后端后端拿着 code 去微信的接口换 openid再用 openid 查用户表拿到自己的 token。但毕设项目里很多老板——啊不很多指导老师——更喜欢看到账号密码登录因为教学场景下管理学生账号更方便以及论文里好写「账号密码登录 微信授权」的混合方案。所以小程序端的登录页通常两种都做。// pages/login/login.js const { request } require(../../utils/request) Page({ data: { username: , password: }, onInputUsername(e) { this.setData({ username: e.detail.value }) }, onInputPassword(e) { this.setData({ password: e.detail.value }) }, async onLogin() { const { username, password } this.data if (!username || !password) { wx.showToast({ title: 请输入账号密码, icon: none }) return } try { const res await request(/login, POST, { username, password }) // 登录成功后存token、存用户信息 wx.setStorageSync(token, res.token) wx.setStorageSync(userInfo, res.userInfo) wx.switchTab({ url: /pages/home/home }) } catch (err) { wx.showToast({ title: err.message, icon: none }) } } })这段代码的重点在wx.setStorageSync把 token 放在本地缓存里后续所有请求从缓存读取。页面的onLogin用 async/await 替代回调地狱出错时 toast 提示交互上会自然很多。顺序是先跳转登录成功页再存 token避免存了 token 但后续逻辑失败了。4.3 首页通知列表数据渲染与下拉刷新首页最常见的形态是轮播图 通知公告列表 快捷入口入口。列表部分拿通知公告举例数据从/notice/list接口来// pages/home/home.js const { request } require(../../utils/request) Page({ data: { noticeList: [], pageNum: 1, pageSize: 10, hasMore: true }, onLoad() { this.loadNotices() }, async loadNotices() { if (!this.data.hasMore) return const res await request(/notice/list, GET, { pageNum: this.data.pageNum, pageSize: this.data.pageSize }) const list res.list || [] this.setData({ noticeList: this.data.noticeList.concat(list), pageNum: this.data.pageNum 1, hasMore: list.length this.data.pageSize }) }, onPullDownRefresh() { this.setData({ noticeList: [], pageNum: 1, hasMore: true }) this.loadNotices().then(() wx.stopPullDownRefresh()) } })这里有三个关键设计。hasMore字段控制是否还能继续翻页避免加载到最后一页后还发请求concat拼接而不是赋值才能实现「加载更多」而不是「覆盖全部」下拉刷新先把列表清空再重新加载数据才不会变成重复的两份。要在app.json里给页面开启enablePullDownRefresh: true不然 onPullDownRefresh 不会触发这个属性写在页面对应的 json 配置文件中。4.4 真机调试与开发者工具的区别开发者工具里一切正常一上真机就白屏、报错、请求失败这是毕设最常见的猫病。原因不外乎三个。第一个是localhost问题。开发者工具里http://localhost:8080能通但手机上的 localhost 是手机自己。联调时要改成电脑在局域网里的 IP 地址比如http://192.168.1.101:8080而且手机和电脑要连同一个 Wi-Fi。第二个是合法域名校验。开发者工具里勾几「校验合法域名」就能绕过限制但真机预览时这个选项是无效的。想在真机上跑通 HTTP 请求必须在小程序后台把域名加到 request 合法域名里而且在线上环境必须用 HTTPS。抱佛脚的办法是开发时用「真机调试」功能它会自动打开一个调试模式能临时绕过域名校验。第三个是后端防火墙。Windows 防火墙默认会挡掉对 8080 端口的访问手机请求直接超时。建议开发阶段在后端配置里临时开放端口或者用腾讯云/阿里云的学生机把后端部署上去直接给手机一个公网地址。这也是答辩演示时最稳的方案。5. 避坑清单智慧校园项目里最常见的七个翻车现场这部分是从实际调试中总结的血泪经验每一条都对应一次真实的「系统跑不起来」或「答辩被问住」。按现象 → 原因 → 解决来写方便你对照排查。5.1 现象后端启动时报Access denied for user rootlocalhost原因是 MySQL 的 root 密码和application.yml里的配置不一致或者是 MySQL 8.0 默认用caching_sha2_password加密方式而项目里的数据库驱动版本太老。解决如果密码不一致用ALTER USER rootlocalhost IDENTIFIED BY 123456;把密码改回来。如果是加密方式问题在 MySQL 命令行执行ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 123456;然后刷新权限FLUSH PRIVILEGES;。我从不在 MySQL 密码上多折腾第一次跑通毕设代码直接用源码默认密码是最省时间的。5.2 现象小程序请求接口一直 pending最后超时原因是 baseUrl 写的是localhost或127.0.0.1真机上无法访问或者后端启动的端口和请求端口不一致后端跑在 8081 而小程序请求 8080。解决先在后端 Controller 里加一个测试接口GetMapping(/ping)在浏览器里访问http://localhost:8080/ping确认后端通。然后用ipconfigWindows或ifconfigMac查电脑的局域网 IP替换小程序端的 baseUrl。后端端口要改的话改完application.yml记得重启。5.3 现象数据库导入 SQL 后中文乱码原因是 SQL 文件本身的字符集和数据库连接字符集不一致。解决建库语句加DEFAULT CHARSETutf8mb4导入的时候加上字符集参数mysql -u root -p123456 --default-character-setutf8mb4 sql/smart_campus.sql如果还是乱码回到表里查看已经导入的数据如果数据本身乱了就要用ALTER TABLE t_notice CONVERT TO CHARACTER SET utf8mb4;转一下然后重新导入。这里要注意 utf8mb4 和 utf8 的区别emoji 表情只有 utf8mb4 才能存。5.4 现象查询结果全是 null但数据库里有数据原因是 MyBatis 的驼峰映射没打开create_time映射不到createTime属性上。解决在application.yml的 mybatis 配置里加map-underscore-to-camel-case: true。如果你不想改全局配置可以在 Mapper XML 的查询语句里给每个字段起别名SELECT create_time AS createTime FROM t_notice。两种方案第二种更直接但每个查询都要写第一种改一行配置全局生效。我推荐第一种省事。5.5 现象登录成功后点击功能又频繁跳回登录页原因是 token 过期时间设置得太短或者 token 存在服务端后服务端重启导致缓存清空如果存在内存里的话。解决如果是 JWT 类型看后端工具类里setExpiration的毫秒值默认 7 天的配置改大一点儿。如果是把 token 存内存里那后端每次重启 token 就失效改成存数据库表这样重启不丢。调试时频繁重启后端的话可以把 token 相关校验逻辑先临时注释掉等最后再打开。5.6 现象小程序端上传图片失败报uploadFile:fail原因是上传接口地址用的是和请求同源没问题但wx.uploadFile的url不能复用普通 request 封装需要单独配置。wx.uploadFile({ url: ${BASE_URL}/upload, filePath: filePath, name: file, header: { token: wx.getStorageSync(token) }, success(res) { const data JSON.parse(res.data) console.log(上传成功, data) } })注意name字段要和后端接收参数名对应。后端如果是RequestParam(file) MultipartFile file这里就必须写name: file。5.7 现象LW 论文里的截图和实际代码对不上答辩被指导老师指出来原因是写论文的时候改了页面样式、换了表结构论文截图却没有同步更新。解决论文的每张截图都重新截一遍截完以后对照代码再检查。重点是数据库设计章节的表格要和t_user等表结构保持一致页面截图要和当前小程序界面一致。所有图重截后整体替换到论文里别只改几处。6. 答辩前的压轴改造从「能跑」到「值得讲」项目能跑通了离高分还有一段距离。最后这几天把时间花在三个改造上性价比最高。第一个改造是加一个「导出功能」。课程表导出成 Excel、学生名单导出成 CSV代码量很小用 EasyExcel 或 POI 都行但是答辩演示时效果非常直观。指导老师看到你能「把数据从系统里带走」对系统完整性的认知会上一个台阶。第二个改造是加一个「统计图表」。哪怕只是课程数量按学院做个柱状图或者通知发布数量按月份做个折线图都能让答辩 PPT 的「系统亮点」页面有图可放。小程序端可以用原生 canvas 画也可以用 eCharts 的小程序版本。第三个改造是准备两个「预设演示数据」的故事。比如答辩时说失物招领模块先演示发布一条失物信息然后切账号演示「我来认领」把流程走完整。这样讲比逐个点菜单要有说服力得多。我自己的习惯是答辩前一晚把项目从零启动三遍——第一次用命令行启动后端和小程序验证全流程第二次重新导入数据库验证初始化脚本没问题第三次把电脑合上再打开模拟答辩现场环境。这个小习惯帮我躲过了至少两次环境问题也欢迎你试试。这套系统的上限不低下限也不高最终拿多少分取决于你把每个环节讲透了多少。希望帮到你。本文还有配套的精品资源点击获取
返回列表