简介:这是一份面向高校毕业设计及课程设计的智慧校园管理系统完整源码包,采用微信小程序作为前端、Java作为后端、MySQL作为数据库,涵盖用户认证、课程查询、成绩查看、校园活动等常见功能模块。压缩包共含1759个文件,整体大小约41MB,其中Java文件承载后端业务逻辑,Vue/JS搭建管理端界面,WXML/WXSS绘制小程序页面,SQL脚本提供数据库结构,另有docx、pptx、md等设计说明与答辩文档,目录结构清晰便于按需查阅。目前已有115人学习下载,适合作为毕业设计或课程设计的参考项目。资源内置完整可运行的前后端源码与数据库文件,并附环境配置说明(JDK1.8、MySQL5.7、Tomcat7等),可帮助掌握小程序与Java服务端的数据交互流程,同时提供答辩PPT与数据库设计文档,便于快速部署演示及二次开发。
1. 微信小程序毕业设计 智慧校园管理系统源码:先别急着解压,你看到的是四件套
微信小程序毕业设计 智慧校园管理系统源码(java+小程序+mysql+LW).zip 这个标题,这几天在毕业设计圈里被反复搜。做过的人都知道,zip 解压只是开始:Java 后端、微信小程序前端、MySQL 脚本和 LW 文档四样东西,缺一个跑通环境,后面所有功能都是黑匣子。上周有个学生卡在 401 上整整两天,最后发现是登录密码加密方式对不上,数据库里存的是明文,后端却用 MD5 去校验。这篇笔记就按我平时调毕设项目的顺序,从拆包、配环境、联调、填坑到答辩演示一路说清楚。适合正在做这个选题、或者刚把项目下下来还不知道从哪下手的人,也适合准备拿它做二次开发的熟手。
2. 智慧校园管理系统到底在管什么:模块拆解与 Java + 小程序 + MySQL 的选型逻辑
如果你刷到过“基于微信小程序的校园食堂订餐系统”这类选题,那套系统核心就是点餐、订单、支付。智慧校园管理系统是这种单点系统的上位整合版,功能覆盖面广,但每个功能点难度都不高。毕设选它,论文好写,演示效果好,这也是它成为热门源码包的原因。
2.1 系统边界:从食堂订餐到智慧校园,差在模块数量
我经手的智慧校园项目里,最常见的模块包括学生信息管理、教师信息管理、课程表、成绩查询、考勤签到、公告通知、宿舍报修、失物招领,有时候还会塞一个校内论坛。你拿到源码后,第一件事应该是打开 LW 文档的“系统功能结构图”,从上往下理一遍,搞清楚这套系统是把哪几个模块放在了一起。
从技术本质看,这种系统就是一个典型的信息管理系统(MIS),核心操作是增删改查,外加角色权限、分页列表、统计图表。智慧校园的“智慧”更多体现在演示层面,比如首页放几个统计图、按课程表自动生成当日课表,而不是真正的人工智能算法。理解这一点非常重要:你后面改代码、补功能、应付答辩提问,都可以围绕“超基础 CRUD + 必要的业务规则”来展开。
举个例子,课程表模块的排序,后端拿到数据库里的 weekday 和 section 字段后,用 Java 排序接口按星期和节次排一下,再返回给小程序端;这种逻辑在论文里能写半页,在代码里不过十行。知道系统边界后再去读源码,你才不会迷失在几十个 Controller 方法里。
2.2 技术选型:为什么源码包基本都是 Java + MySQL,小程序端反而最省事
Java 后端在毕业设计里最常见是 Spring Boot 2.x + MyBatis,也有少量是 Spring Boot + Spring Data JPA,或者是更老的 SSH(SpringMVC + Hibernate)工程。用 Java 当主力,是因为 Maven 管理依赖清晰、启动方式统一、踩坑记录最多。面试时还能顺手答上几道 java 面试题,比如 Controller 的作用域、MyBatis 参数绑定、事务传播行为,这些都能从这套项目里找到实例。MySQL 则是免费数据库里资料最全的,建库、导数据、权限配置,随便搜一个 mysql 安装配置教程都能照做。
小程序端最大的好处是用户不需要安装,微信开发者工具里一扫码就能在手机上跑,答辩现场用真机演示比 PPT 截图强太多。技术选型的逻辑就是“后端重、前端轻、数据库通用”。如果你解压发现不是 Spring Boot 而是 JSP 老项目,也别急着删,思路一样,只是配置位置不同;无非是数据库连接写到 jdbc.properties,前端页面用 JSP 渲染,小程序端改成请求 JSP 地址罢了。
2.3 解压 zip 后先做三件事:确认目录、读 sql 脚本、找 LW 里的接口表
拿到 zip 之后,我一般先在命令行解压,别用 Windows 自带右键解压,因为中文文件名和长路径容易截断出怪问题。解压后先看目录层级,确认四个部分是不是齐了。
unzip "【微信小程序毕业设计】智慧校园管理系统源码(java+小程序+mysql+LW).zip" -d smart-campus cd smart-campus find . -maxdepth 2 -type d | head -30解压命令里,-d 参数指定输出目录,避免把所有文件直接摊在当前目录。find 的 maxdepth 限制查看两层目录,足够判断整体结构。常见的目录名是 backend 或 server 放 Java 工程,client 或 miniapp 放小程序前端,sql 目录放数据库脚本,LW 目录放论文和演示视频。如果这些目录没有严格区分,就去找两个关键文件:pom.xml 是 Java 后端工程的标志,project.config.json 是微信小程序工程的标志。
看完目录再检查数据库脚本:
head -50 sql/smart_campus.sql重点看前几行有没有 CREATE DATABASE,以及建表语句是否指定了 utf8mb4 字符集。脚本里如果已经写了 CREATE DATABASE,你后面就不用手动建库;如果没写,你就得根据建表语句里的库名去建。再看一眼有没有 CREATE USER 或 GRANT 语句,有些毕设源码会把数据库账号写在脚本里,这会影响你本地能不能连得上。
最后翻 LW 文档,先看“数据库设计”和“接口设计”两章。接口设计里通常有个表格,列出路径、请求方式、参数和返回结果,这就是前后端联调的契约。我习惯把这个表格复制出来,对着后端的 Controller 一一核对,后面联调能省一半时间。
3. 从零跑通本地环境:JDK、MySQL、微信开发者工具的初始化顺序
环境配置的顺序决定了你踩坑的数量。我见过太多人先开微信开发者工具,再回头改后端,结果前端一直报“网络错误”,排查半天才发现数据库都没连上。我的习惯顺序是:先装 JDK 和 Maven,再初始化 MySQL 并导入脚本,接着启动后端用 curl 验证,最后才用微信开发者工具导小程序。
3.1 版本先定死:JDK 8 + Maven 3.6 + MySQL 5.7/8.0 + 微信开发者工具稳定版
毕设项目在版本上有很强的惯性,很多坑其实不是代码问题,是版本不匹配。先看项目里的 pom.xml,如果 Spring Boot 的 parent 版本是 2.x,那推荐用 JDK 8;如果看到的是spring-boot-starter-parent版本 3.x,那必须用 JDK 17。判断错了,后端启动时会报 UnsupportedClassVersionError,这是第一道坎。
| 组件 | 推荐版本 | 原因 |
|---|---|---|
| JDK | 1.8(对应 Spring Boot 2.x) | 大量毕设源码基于 Spring Boot 2,JDK 8 行为最稳 |
| Maven | 3.6.3 | 避免新版对镜像仓库和私有仓库的默认行为差异 |
| MySQL | 5.7.44 或 8.0 | 看 sql 脚本语法;5.7 兼容性最好,8.0 功能更强 |
| 微信开发者工具 | 最新稳定版 | 模拟器和调试器更完善,但基础库按项目配置来,别调到最新 |
这里单独说一句 MySQL。我本机用的是 5.7.44,因为这个版本和绝大多数毕设 sql 脚本都不冲突。如果你用 MySQL 8.0,就要额外处理加密插件和连接串参数,后面避坑章节会展开。微信开发者工具装好后,第一次导入项目时会提示基础库版本,建议先按 project.config.json 里写的版本选,不要直接选最新,免得因为某几个 API 在新基础库上废弃导致页面报错。
3.2 数据库初始化:跟着 mysql 安装配置教程装完之后,还剩三件事
MySQL 安装本身不难,网上一个 mysql 安装配置教程就能搞定,难的是把毕设项目的数据库脚本导入进去。装好 MySQL 后,打开命令行,一步步执行:
mysql -u root -p输入密码后,进入 MySQL 命令行交互界面。先建库,再切库,再导入脚本:
CREATE DATABASE IF NOT EXISTS smart_campus DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE smart_campus; SOURCE /home/user/smart-campus/sql/smart_campus.sql; SHOW TABLES;建库时指定 utf8mb4 和对应的排序规则,能避免后面插入中文变成问号。SOURCE 后面的路径要写你解压出的 sql 文件绝对路径,注意目录名里如果有中文或空格,可能导入失败。SHOW TABLES 是验证步骤,如果能看到 user、course、notice 这类表,说明导入成功。
如果 sql 脚本开头已经有 CREATE DATABASE,你可以不手动建库,直接 SOURCE;但我永远建议手动指定字符集,因为很多脚本里的建库语句只写了 DEFAULT CHARSET,没有 COLLATE。要是导入时报错,先检查 sql 文件是不是被 Windows 记事本存成了带 BOM 的 UTF-8,这会让你死都不知道怎么死的。用 VS Code 或 Notepad++ 打开,另存为“UTF-8 无 BOM”再试。
3.3 微信开发者工具导入小程序端:AppID 与校验域名两个入口
打开微信开发者工具,选择“导入项目”,目录指向解压路径下的 client 或 miniapp 目录。AppID 可以用自己注册的,也可以选测试号。测试号能看模拟器,但真机预览有限制,如果你后面要手机扫码演示,最好提前注册一个个人小程序 AppID,不用企业认证,个人类型就能跑大部分功能。
导入后第一件事是检查 project.config.json:
{ "appid": "touristappid", "projectname": "smart-campus-miniapp", "setting": { "urlCheck": false, "es6": true, "postcss": true, "minified": true } }urlCheck 这个字段是关键。本地调试时,微信开发者工具默认会校验 request 合法域名,如果你打开的页面写的是 http://localhost:8080,且没有配置合法域名,请求就会被打回。把它设为 false,本地才能直接请求 http 接口。如果你在“详情-本地设置”里手动勾选了“不校验合法域名”,效果一样。
导入后如果页面白屏,先按 Ctrl+Shift+M 调出模拟器看 console 日志。最常见的是 app.js 里访问了一个 undefined 的全局变量,或者页面 json 里写入了不存在的模板组件。耐心点,模拟器里能直接打断点,比在真机上瞎猜快得多。
3.4 后端启动:先改 application.yml,再 mvn spring-boot:run
后端工程在 backend 目录,找到 src/main/resources/application.yml,如果没有这个文件就找 application.properties。先改数据源,把数据库名、用户名、密码换成你自己的:
server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/smart_campus?useUnicode=true&characterEncoding=utf8mb4&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true username: root password: "123456" mybatis: mapper-locations: classpath:mapper/*.xml configuration: map-underscore-to-camel-case: trueurl 里的参数每一个都有说法。characterEncoding=utf8mb4 要和数据库字符集保持一致,否则中文乱码;serverTimezone=Asia/Shanghai 解决 JDBC 驱动拿服务器默认时区导致的时间差 8 小时问题;useSSL=false 是关闭 SSL 握手,本地调试没必要开;allowPublicKeyRetrieval=true 是 MySQL 8 的 caching_sha2_password 插件导致的经典报错。password 用引号包住,是防止密码里有特殊字符被 YAML 解析误伤。
然后在 backend 目录下执行:
mvn clean package -DskipTests java -jar target/*.jar如果 Maven 还没装依赖,也可以直接mvn spring-boot:run。看到控制台输出“Started Application”和“Tomcat started on port(s) 8080”就说明后端起来了。这时用 curl 验证接口:
curl http://localhost:8080/api/login -X POST -H "Content-Type: application/json" -d '{"username":"admin","password":"123456"}'能返回 JSON,哪怕返回的是“密码错误”,都说明后端已经能接住请求;如果返回 404 或 connection refused,再回头看配置。
4. 前后端联调避坑指南:接口 404、端口占用、真机白屏的排查清单
联调阶段的问题基本集中在“请求没到后端”“到了后端但路径不对”“后端接住但处理不了”三处。遇到问题先别急着改代码,用 charles 抓包看小程序实际发出的请求,比盯代码快得多。
4.1 先把接口契约对清楚:LW 文档里的接口表怎么用
最笨也最有效的办法,是把 LW 文档里的接口表格抄出来,对着后端的 Controller 一个一个核对。我通常用下面的表格结构:
| 模块 | 路径 | 请求方式 | 参数 | 后端 Controller 方法 |
|---|---|---|---|---|
| 登录 | /api/login | POST | username, password | LoginController.login |
| 公告列表 | /api/notice/list | GET | pageNum, pageSize | NoticeController.list |
| 学生列表 | /api/student/list | GET | keyword, pageNum | StudentController.list |
核对的时候重点看路径里有没有多斜杠、少参数、方法名对不上。一个非常常见的 404 原因是小程序端 url 写成了/api/noticeList,而后端实际路径是/api/notice/list。用 charles 抓包后,你能直接看到请求 URL,一眼就能对比出来。
后端控制台也要盯。Spring Boot 启动后,每次请求进来都会打印日志,如果请求到了后端但路径没匹配上,通常会显示“No mapping found for HTTP request with URI”。这时候去 Controller 里搜那个 URI,基本就能定位是少写了注解里的路径,还是类上少写了 @RequestMapping。
4.2 高频踩坑记录:本地调试阶段最常见的五个宕机点
现象1:小程序 console 报 request:fail,页面数据出不来。
原因:本地请求的是 http 接口,但“不校验合法域名”没打开;或者真机预览时,baseUrl 填的是 localhost,手机根本访问不到电脑。
解决:模拟器调试时,在“详情-本地设置”里勾选“不校验合法域名”。真机预览时,把 baseUrl 改成电脑的局域网 IP,比如http://192.168.1.100:8080,保证手机和电脑连着同一个 WiFi。别用“网络连接”里查到的那个虚拟网卡 IP,那个地址真机访问不通。
现象2:数据库中文变成问号,或者插入时直接报“Incorrect string value”。
原因:建库时没指定 utf8mb4,或者 JDBC URL 少了 characterEncoding 参数。还有一种情况是 sql 脚本里建表时随手写了 DEFAULT CHARACTER SET utf8,utf8 在 MySQL 里是 utf8mb3 的别名,存中文够用但 emoji 会炸。
解决:按 3.2 的做法重建数据库,字符集全部指定 utf8mb4;同时把 3.4 的 YAML 里连接串补全。改完必须重启后端,连接池里的旧连接还带着老的字符集。
现象3:MySQL 8 下后端启动直接报 Public Key Retrieval is not allowed。
原因:MySQL 8 默认的 caching_sha2_password 认证插件要求客户端先取公钥,而 JDBC URL 里没开 allowPublicKeyRetrieval。
解决:连接串加allowPublicKeyRetrieval=true和useSSL=false。如果你用的 mysql-connector-java 依赖是老版本 5.x,还有一个兼容方案是把 root 密码认证方式改回 mysql_native_password:
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '123456'; FLUSH PRIVILEGES;但这条 SQL 有隐患,新驱动新插件其实没问题,别为了兼容老驱动给自己留把锁。优先换驱动版本。
现象4:端口被占用,后端起不来,日志里出现 Port 8080 was already in use。
原因:之前跑过别的 Spring Boot 项目,或者 IDE 里还挂着一个没停掉的进程。
解决:Windows 上执行netstat -ano | findstr :8080找到 PID,去任务管理器结束进程;Linux 或 Mac 上执行lsof -i:8080看占用情况。如果不想杀进程,就把 application.yml 里 server.port 改成 8081,同时把小程序端 config.js 里的 baseUrl 同步改掉。记住,小程序端和后端端口是两处都要改,漏一处请求就打到老端口上。
现象5:登录接口返回 401,但数据库里明明有这条用户。
原因:最常见是密码加密不一致。后端注册时用了 MD5 加盐,但 sql 脚本里的测试数据是明文;或者登录接口被拦截器拦住了,连匿名访问也不放过。
解决:先打开后端的拦截器或过滤器配置,确认/api/login是不是被放行。然后找到项目里的密码加密工具类,通常是 Md5Util 或 PasswordEncoder 一类,把数据库里的密码改成用同一套算法重新生成的密文。如果你要现场改,可以用后端启动后的某个修改密码接口,没有就用 SQL 更新:
UPDATE user SET password = '加密后的密文' WHERE username = 'admin';注意这里的密文不要用你自己手写的 MD5,因为后端代码里可能还有盐值拼接逻辑,必须跟着源码里的方法走。
5. 二次开发与 LW 配套验收:让“页面列表加载更多”和“导航栏高度”这类细节经得起提问
答辩评委最喜欢问的一句话是“这个功能你做过哪些细节”。很多学生对着源码讲不出所以然。下面三个细节是高频提问点,把它们吃透,比背十页 PPT 有用。
5.1 微信小程序页面列表加载更多:onReachBottom 的正确打开方式
毕设里的公告列表、成绩列表、失物招领都有分页。新人最容易犯的错误是在 wxml 里用 scroll-view 包整个页面,再用 scrolltolower 触发加载,导致和微信原生的 onReachBottom 冲突。我更推荐直接用整页滚动,也就是 Page 的 onReachBottom 生命周期。
Page({ data: { list: [], pageNum: 1, pageSize: 10, hasMore: true, loading: false }, onLoad() { this.loadList(); }, onReachBottom() { if (!this.data.loading && this.data.hasMore) { this.setData({ pageNum: this.data.pageNum + 1 }); this.loadList(); } }, loadList() { this.setData({ loading: true }); wx.request({ url: getApp().globalData.baseUrl + '/api/notice/list', data: { pageNum: this.data.pageNum, pageSize: this.data.pageSize }, success: (res) => { const rows = res.data.rows || []; this.setData({ list: this.data.list.concat(rows), hasMore: rows.length === this.data.pageSize, loading: false }); }, fail: () => this.setData({ loading: false }) }); } });这里的关键参数是 pageNum 和 pageSize。onReachBottom 触发时先把 pageNum 加一,再发起请求,避免加载第一页时被重复触发;hasMore 用最后一次返回的 rows 长度是否等于 pageSize 来判断,因为只有当满页时才可能还有下一页。loading 这个标志很重要,否则快速滑动会连续发出重复请求,数据会重复拼接。
后端接口也要配合。如果用的是 MyBatis + PageHelper,代码里要注意 PageHelper.startPage 必须紧挨着查询语句,中间不能有其他 SQL 操作,因为 PageHelper 是基于线程上下文的下一条 SQL 做拦截的。手动分页则简单:
@GetMapping("/api/notice/list") public Result list(@RequestParam(defaultValue = "1") Integer pageNum, @RequestParam(defaultValue = "10") Integer pageSize) { int offset = (pageNum - 1) * pageSize; return Result.success(noticeMapper.selectPage(offset, pageSize)); }这里的 offset 就是数据库 LIMIT 的第一个参数。写论文时,这一段可以对应“系统性能优化”章节,说明你是如何避免一次性加载全部数据导致小程序端卡顿的。
5.2 微信小程序顶部导航栏高度:自定义导航不能写死
很多毕设小程序会在页面的 json 文件里写"navigationStyle": "custom",目的是让页面背景图延伸到顶部。这时候你就必须自己处理状态栏高度和胶囊按钮位置,否则会出现按钮顶到刘海屏的状态栏里、或者导航栏高度在 iPhone 和安卓上不一致的情况。
在 app.js 的 onLaunch 里算一次,存到 globalData:
const system = wx.getSystemInfoSync(); const menu = wx.getMenuButtonBoundingClientRect(); const navBarHeight = (menu.top - system.statusBarHeight) * 2 + menu.height; App({ globalData: { statusBarHeight: system.statusBarHeight, navBarHeight: navBarHeight } });计算逻辑是:胶囊按钮的上边界到状态栏底部的距离,乘以 2 再加上胶囊自身高度,得到整个自定义导航栏的高度。不要手动写死一个数字,比如 44 或 88,因为不同手机的胶囊位置不一样。这个计算代码在论文里可以作为“适配不同机型”的亮点,延伸到 RTL 布局、安全区概念。
5.3 权限控制:前端隐藏按钮只是摆设,后端拦截器才算数
前端菜单里把“管理员入口”藏起来,只是体验优化,真正要防的是用户直接拼一个 URL 去调后端接口。毕设里最常见的方案是登录后把用户角色放进 session,后端用拦截器统一判断。
@Component public class AuthInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String uri = request.getRequestURI(); if ("/api/login".equals(uri)) { return true; } Object role = request.getSession().getAttribute("role"); if (role == null) { response.setStatus(401); return false; } if (uri.startsWith("/api/admin/") && !"ADMIN".equals(role)) { response.setStatus(403); return false; } return true; } }这段代码只表达思路,实际要按源码里的用户表字段来写。注意拦截器里放行登录接口是必须的,否则死循环。如果你用的是 JWT token,后端拦截器要从 header 里解析 token,并检查过期时间。论文里的时序图或权限模块设计,这部分可以写得比前端更多。
5.4 LW 文档跟代码对不上,答辩前改哪边
这是所有毕设源码包的通病:论文是作者最开始写的,代码是最后才改完的,两边经常不一致。答辩前不要傻乎乎地改代码去迎合论文,而是先做一个检查,分清小差异和功能缺失。
| 检查项 | LW 里怎么写的 | 代码实际表现 | 处理方式 |
|---|---|---|---|
| 管理员删除学生 | 论文写“支持删除” | 页面只有停用按钮 | 补一个删除接口和对应按钮,或者论文里改成“停用” |
| 课程表显示范围 | 论文写周一至周五 | 代码里有周日数据 | 改论文,别删代码,周日没课不影响演示 |
| session 超时时间 | 论文写 30 分钟 | 代码实际 10 分钟 | 改代码,把超时时间调成 30 分钟,保证演示不中断 |
| 密码加密方式 | 论文写 MD5 | 代码用了 BCrypt | 以代码为准,论文里把 MD5 改成 BCrypt 并附一句加盐原因 |
原则是小差异改论文,明确功能缺失才补代码。千万不要为了跟论文保持一致,把已经能跑的复杂功能砍掉。
6. 答辩演示前的一个压轴技巧:让测试数据帮你控制演示节奏
别用空数据库演示,也别随机灌一堆“test”字符串。手动造一套时间线合理的测试数据,能让你的演示过程按部就班。课程表数据要覆盖一周七天,但答辩演示只展示周一和周五;公告内容要有日期梯度,让“加载更多”出现;学生姓名用真实感强的中文名,别用英文拼音。
INSERT INTO course (id, name, teacher, weekday, section, location) VALUES (1, '计算机网络', '赵老师', 1, 1, 'A101'), (2, '数据库原理', '钱老师', 1, 2, 'B202'), (3, '操作系统', '孙老师', 5, 3, 'A305'); INSERT INTO notice (id, title, content, create_time) VALUES (1, '关于智慧校园系统上线试运行的通知', '试运行期间请各位师生及时反馈问题', NOW()), (2, '图书馆周末开放时间调整', '周六日开馆时间调整为 9:00-17:00', NOW());这里的 create_time 用 NOW() 比写死一个日期更安全,因为后端列表接口按时间排序时,NOW() 会被当成本月的数据,展示起来像真的一样。外键字段要提前查清楚,比如报修的 student_id 必须先有对应用户,否则插入时会报外键约束错误,你不可能在答辩现场查这条 SQL。
演示顺序我建议固定下来:登录管理员账号,先看首页统计盘,再点进公告列表,在底部连续上滑两次让“加载更多”出现,然后切到课程表强调按周排列的逻辑。这一条路走完,主流程覆盖了登录、查询、列表分页、业务规则四个环节。如果你做的版本接的是 uniapp 打包出来的小程序,流程会不一样,但这份源码包从目录结构来看,更接近原生微信小程序工程,别把 uniapp 的打包概念混进来讲。
我大学时做过同方向的项目,答辩现场后端被同学无意间关掉了,接口全部超时。评委老师顺势问了一句“你的异常处理是怎么设计的”,我才磕磕巴巴把话题圆回来。自那以后,我每次演示前都会重启后端、清掉旧日志、再走一遍关键路径,这个习惯一直留到现在。希望帮到你。
本文还有配套的精品资源,点击获取