简介这是一套面向计算机专业本科生的微信小程序毕业设计实战项目聚焦个人日程管理场景兼顾前端交互与后端业务逻辑适用于课程设计、毕设选题及全栈开发能力训练。资源包含1175个文件涵盖163个JS逻辑脚本、128个Vue组件、111个Java后端服务类、80个WXSS样式文件及231个PNG界面素材完整呈现小程序Spring BootMySQL三层架构的工程组织方式压缩包大小40.44MB结构清晰含build/run/install三类批处理脚本及多份.bak备份文件便于环境快速部署与代码比对。已有160人学习下载提供配套演示视频编号156、详细功能说明文档及管理员/用户双角色操作流程覆盖日程增删改查、会面与用餐安排、重要日提醒、系统权限管理等核心模块可直接运行调试或作为二次开发基础模板。1. 为什么一个“个人日程安排”小程序值得花三个月做毕设——它不是待办清单而是轻量级协同调度入口很多同学拿到“个人日程安排”这个毕设题目第一反应是太简单了不就是增删改查时间选择器但去年带某高校计算机专业毕设时A同学交的第一版确实只做了用户添加日程、设置提醒、按日期查看——答辩被导师当场叫停“你这和手机自带日历有啥区别系统管理在哪多角色权限怎么体现数据导出能支持Excel吗管理员怎么批量初始化100个测试用户”——一句话点破本质毕业设计要验收的从来不是“能不能跑”而是“有没有工程闭环意识”。这份【微信小程序毕业设计】个人日程安排系统恰恰卡在了学生最容易忽略的临界点上它用Java后端MySQL构建了真实可运维的数据层前端完整覆盖管理员与普通用户双视角且所有模块从用餐管理到会面管理都预留了扩展字段和状态机逻辑。它不追求炫技但每一步操作都有日志埋点、每张表都有索引优化说明、每个接口都带Swagger文档截图——这才是企业级小系统该有的样子。适合需要交一份“看得见设计、摸得着代码、讲得清取舍”的课程设计或毕业设计的同学尤其当你答辩PPT里能指着sys_user_role表结构说“这里用位运算压缩权限标识比字符串枚举节省37%存储空间”评委眼睛就亮了。2. 总体架构设计前后端分离的三层结构与四个核心业务域划分这套方案采用清晰的分层架构避免学生项目常见的“所有逻辑堆在app.js里”的黑匣子写法。整体分为表现层微信小程序前端、服务层Java Spring Boot后端、数据层MySQL 5.7三者通过RESTful API通信所有接口均遵循/api/v1/{module}/{action}规范比如/api/v1/schedule/create创建日程/api/v1/meeting/listByDate按日期查会面。这种结构让代码可读性大幅提升也方便后期拆分微服务。2.1 前端模块化组织基于Vue.js的组件树与路由守卫小程序前端实际使用的是uni-app框架兼容微信小程序平台而非原生WXML。项目目录中出现的.vue.bak文件如update-password.vue.bak是开发过程中的备份主逻辑集中在pages/下的页面组件和components/下的可复用单元。关键设计点在于路由守卫机制// router/index.js const routes [ { path: /pages/user/login, meta: { requiresAuth: false } }, { path: /pages/schedule/list, meta: { requiresAuth: true, roles: [user, admin] } }, { path: /pages/admin/user-manage, meta: { requiresAuth: true, roles: [admin] } } ] // 全局前置守卫 router.beforeEach((to, from, next) { const token uni.getStorageSync(token) if (to.meta.requiresAuth !token) { uni.navigateTo({ url: /pages/user/login }) return } if (to.meta.roles) { const userRole uni.getStorageSync(userRole) // user or admin if (!to.meta.roles.includes(userRole)) { uni.showToast({ title: 无权限访问, icon: none }) uni.navigateBack() return } } next() })这段代码不是摆设——它直接决定了用户点击“系统管理”菜单时普通用户看到的是403提示而非空白页。meta.roles字段与后端sys_user_role表中的role_code严格对应避免前端硬编码权限字符串。所有页面组件通过BreadCrumbs /和IndexHeader /实现统一导航栏而IndexAsideStatic.vue.bak这类备份文件的存在恰恰说明开发者经历过“侧边栏动态加载失败导致白屏”的血泪经验最终选择静态化处理保底。2.2 后端技术栈选型Spring Boot 2.7.x MyBatis-Plus JWT后端选用Java而非Node.js核心考量是企业级项目对事务一致性、线程安全和监控能力的要求。Spring Boot 2.7.x版本非最新3.x是为兼容JDK 8环境避免学生因环境配置问题卡死。关键依赖如下!-- 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 !-- 避免3.5.4的JDK17强依赖 -- /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-api/artifactId version0.11.5/version /dependencyJWT令牌生成逻辑封装在TokenService.java中采用HS256算法密钥存于application.yml的jwt.secret字段实际部署时需替换为环境变量。特别注意所有Controller方法均标注Valid注解进行参数校验例如创建日程时强制校验startTime不能早于当前时间PostMapping(/create) public Result create(Valid RequestBody ScheduleDTO dto) { // 校验逻辑在ScheduleDTO的Future注解中已声明 // 实际执行前还会调用service.checkTimeConflict(dto) return scheduleService.create(dto); }这种“双重校验”DTO层Service层是防止恶意请求绕过前端限制的关键防线也是答辩时展示“安全意识”的硬核细节。2.3 数据库设计六张核心表与状态机驱动的业务流转MySQL数据库共12张表但真正承载业务逻辑的是以下六张核心表。设计时严格遵循第三范式同时为高频查询添加复合索引表名主要字段关键索引业务价值sys_userid, username, password, real_name, phone, statusidx_status_phone用户基础信息status字段支持禁用/启用状态切换sys_roleid, role_code, role_namePRIMARY KEY角色定义表role_code值为user,adminsys_user_roleuser_id, role_idUNIQUE(user_id, role_id)多对多关系支持用户拥有多个角色schedule_infoid, user_id, title, content, start_time, end_time, type, statusidx_user_time(type,user_id,start_time)日程主表type字段区分工作/会面/用餐等类型meeting_infoid, schedule_id, location, participants, meeting_linkidx_schedule_id会面扩展表与schedule_info一对一关联meal_infoid, schedule_id, restaurant, budget, is_vegetarianidx_schedule_id用餐扩展表同样一对一关联提示schedule_info.type字段采用枚举值1工作日程2会面3用餐而非外键关联字典表。这是权衡结果——当类型极少变动且查询频次极高时整数比较比JOIN字典表快15%~20%符合“个人日程”场景的读多写少特征。2.4 四大业务域的功能边界与数据流向系统将功能划分为四个明确业务域每个域对应独立的API前缀和数据库表簇避免功能耦合日程管理域/api/v1/schedule/处理schedule_info主表CRUD含重复日程生成、时间段冲突检测算法复杂度O(n)、提醒推送开关。会面管理域/api/v1/meeting/操作meeting_info扩展表重点实现participants字段的JSON数组解析如[u1001,u1002]并关联查询参会人姓名。用餐管理域/api/v1/meal/管理meal_info表budget字段支持小数精度is_vegetarian布尔值用于筛选素食选项。系统管理域/api/v1/sys/涵盖用户管理、角色分配、操作日志sys_log表、数据字典维护是管理员专属区域。数据流向严格单向前端发起请求 → 网关校验JWT → Controller接收DTO → Service层编排业务逻辑如创建会面时先插入schedule_info再插入meeting_info→ Mapper执行SQL → 返回Result包装体。这种链路让调试时能快速定位问题环节——比如日程创建失败先看Controller日志是否收到参数再查Service层事务是否回滚。3. 核心模块实现从“重要日管理”到“系统管理”的落地细节3.1 重要日管理模块高亮标记与智能归档策略“重要日”并非独立实体而是schedule_info表中is_important1的特殊日程子集。其价值在于两点视觉强化与归档逻辑。前端通过view classimportant-tag重要/view样式实现红色角标而后端在归档任务中赋予更高优先级// ScheduleServiceImpl.java Transactional public void archiveOldSchedules() { // 重要日程保留180天普通日程保留90天 LocalDateTime now LocalDateTime.now(); int importantDays 180; int normalDays 90; QueryWrapperScheduleInfo importantWrapper new QueryWrapper(); importantWrapper.eq(is_important, 1) .lt(end_time, now.minusDays(importantDays)) .eq(status, completed); scheduleInfoMapper.delete(importantWrapper); // 物理删除已完成的重要日程 QueryWrapperScheduleInfo normalWrapper new QueryWrapper(); normalWrapper.eq(is_important, 0) .lt(end_time, now.minusDays(normalDays)) .eq(status, completed); scheduleInfoMapper.delete(normalWrapper); }这段归档逻辑被配置为Quartz定时任务每天凌晨2点执行。关键点在于物理删除而非软删除。因为个人日程数据量小软删除带来的is_deleted字段和额外索引反而增加查询负担。答辩时可强调“我们根据数据生命周期做存储策略分级——高频访问的近期日程走热库低频的历史归档走冷备而不是一刀切用逻辑删除”。3.2 工作日程管理模块时间段冲突检测算法与可视化反馈工作日程的核心难点是防止用户创建重叠事件。后端采用“区间相交判定”算法而非暴力遍历// ScheduleService.java public boolean checkTimeConflict(ScheduleDTO dto) { // 查询同一用户下所有未完成的日程排除自身 QueryWrapperScheduleInfo wrapper new QueryWrapper(); wrapper.eq(user_id, dto.getUserId()) .ne(id, dto.getId()) // 排除自身更新 .in(status, pending, ongoing); // 只检查进行中的日程 ListScheduleInfo existing scheduleInfoMapper.selectList(wrapper); LocalDateTime newStart dto.getStartTime(); LocalDateTime newEnd dto.getEndTime(); for (ScheduleInfo exist : existing) { LocalDateTime existStart exist.getStartTime(); LocalDateTime existEnd exist.getEndTime(); // 区间相交判定max(start1,start2) min(end1,end2) if (existStart.isBefore(newEnd) newStart.isBefore(existEnd)) { return false; // 冲突 } } return true; // 无冲突 }前端配合实现可视化反馈当用户拖动日程结束时间导致重叠时立即高亮冲突日程并显示“⚠️ 与[项目评审]时间冲突”。这种“后端校验前端即时反馈”的组合比单纯弹窗提示体验更优也是答辩时演示的重点环节。3.3 会面管理模块多用户关联与实时状态同步会面管理的特殊性在于participants字段存储JSON数组需解决两个问题一是关联查询参会人姓名二是状态变更实时通知。解决方案如下关联查询MyBatis-Plus的TableField(exist false)配合自定义SQL实现!-- ScheduleMapper.xml -- select idselectMeetingWithParticipants resultTypecom.example.dto.MeetingDetailDTO SELECT s.id, s.title, s.start_time, s.end_time, m.location, m.meeting_link, GROUP_CONCAT(u.real_name SEPARATOR , ) as participantNames FROM schedule_info s JOIN meeting_info m ON s.id m.schedule_id JOIN sys_user u ON FIND_IN_SET(u.id, m.participants) WHERE s.id #{id} GROUP BY s.id, m.id /select状态同步采用WebSocket长连接spring-boot-starter-websocket当会面状态变更为“已开始”时向所有参会人推送消息// WebSocketController.java MessageMapping(/meeting/status) public void updateMeetingStatus(MeetingStatusUpdate update) { // 广播给participants列表中的所有用户 for (String userId : update.getParticipants()) { simpMessagingTemplate.convertAndSend( /topic/meeting/ userId, update ); } }前端监听/topic/meeting/{userId}收到消息后更新本地会面卡片状态。这种设计让“会面开始提醒”不再是轮询消耗而是真正的实时触达。3.4 系统管理模块角色权限控制与操作日志审计系统管理是管理员专属区域其安全性设计体现在三个层面菜单级控制前端IndexAsideStatic.vue中v-ifuserRole admin控制“用户管理”“系统设置”菜单显示。按钮级控制button v-ifhasPermission(user:delete)删除/button权限码由后端/api/v1/sys/permission/list接口返回。数据级控制UserManageController.java中管理员查询用户列表时自动追加QueryWrapper条件GetMapping(/list) public Result list(RequestParam(defaultValue 1) Integer page, RequestParam(defaultValue 10) Integer limit) { PageSysUser userPage new Page(page, limit); // 普通管理员只能查本部门用户此处简化为全部实际可加tenant_id过滤 QueryWrapperSysUser wrapper new QueryWrapper(); wrapper.orderByDesc(create_time); return Result.success(userService.page(userPage, wrapper)); }操作日志记录在sys_log表中字段包括operator_id操作人、module模块名、action动作如create_user、paramsJSON格式参数快照、ip_address客户端IP。答辩时可指出“日志表设计包含params快照而非仅记录ID是为了满足审计要求——当用户投诉‘我明明没删过这个日程’我们可以回溯当时提交的完整参数而不是只看到一条‘delete by admin’的模糊记录”。4. 部署与运行从本地调试到生产环境的三步走验证4.1 本地开发环境搭建三脚架式启动流程项目提供1-install.bat、2-run.bat、3-build.bat三个批处理脚本构成标准的“安装-运行-构建”三步链。这不是噱头而是降低学生环境配置门槛的务实设计1-install.bat自动执行npm install前端依赖和mvn clean compile后端编译并检查MySQL服务是否运行通过netstat -ano | findstr :3306。2-run.bat并行启动后端mvn spring-boot:run和前端npm run dev并在启动成功后自动打开微信开发者工具并导入项目。3-build.bat执行npm run build:mp-weixin生成小程序生产包并调用mvn clean package打包后端jar。注意脚本中所有路径均使用相对路径如cd ..\backend避免绝对路径导致跨机器失效。某次帮A同学调试时发现他把MySQL密码写死在application.yml里结果脚本执行到一半报错“Access denied”后来改成读取config/db.properties文件密码由1-install.bat首次运行时交互式输入并加密存储。4.2 微信小程序配置要点AppID绑定与HTTPS强制微信小程序上线必须配置合法域名本项目在project.config.json中已预置开发环境配置{ description: 个人日程安排系统, setting: { urlCheck: false, // 开发阶段关闭域名校验 es6: true, enhance: true, postcss: true, preloadBackgroundData: false, minified: true, newFeature: true }, compileType: miniprogram, libVersion: 2.28.2, appid: wx1234567890abcdef, // 此处为占位符实际需替换 projectname: personal-schedule, debugOptions: { hidedInDevtools: [] }, scripts: { build: npm run build:mp-weixin } }关键点在于正式提交审核前必须将request合法域名配置为后端服务器地址如https://api.yoursite.com且该域名需支持TLS 1.2。很多同学卡在“request:fail net::ERR_CERT_COMMON_NAME_INVALID”根源是用了免费SSL证书但未正确绑定子域名。建议使用Lets Encrypt的certbot工具配合Nginx反向代理配置示例# nginx.conf server { listen 443 ssl; server_name api.yoursite.com; ssl_certificate /etc/letsencrypt/live/api.yoursite.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/api.yoursite.com/privkey.pem; location /api/ { proxy_pass http://localhost:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }4.3 MySQL数据库初始化一键导入与字符集校验项目根目录的db_init.sql文件包含完整建表语句和初始数据如管理员账号admin/123456。执行前必须确认MySQL字符集为utf8mb4否则emoji表情如日程标题中的会乱码-- 执行前校验 SHOW VARIABLES LIKE character_set%; SHOW VARIABLES LIKE collation%; -- 若非utf8mb4需修改my.cnf [client] default-character-set utf8mb4 [mysql] default-character-set utf8mb4 [mysqld] character-set-server utf8mb4 collation-server utf8mb4_unicode_ci导入命令mysql -u root -p --default-character-setutf8mb4 personal_schedule db_init.sqldb_init.sql中特意包含SET NAMES utf8mb4;开头指令作为双重保险。某次部署翻车就是因为跳过了字符集校验导致用户输入“☕️下午茶”变成“??下午茶”最后花了两小时回溯数据。4.4 生产环境Jar包部署内存优化与进程守护后端打包为schedule-backend-1.0.jar推荐使用以下方式启动以保障稳定性# 启动脚本 start.sh nohup java -Xms512m -Xmx1024m \ -XX:UseG1GC \ -Dfile.encodingUTF-8 \ -Dspring.profiles.activeprod \ -jar schedule-backend-1.0.jar \ app.log 21 echo $! app.pid参数说明-Xms512m -Xmx1024m初始堆内存512MB最大1024MB避免频繁GC-XX:UseG1GC启用G1垃圾收集器适合中小应用-Dspring.profiles.activeprod激活生产配置此时application-prod.yml中的数据库密码、Redis地址等生效进程守护使用supervisord更稳妥但对学生项目而言nohup pid文件已足够。可通过kill $(cat app.pid)优雅停止服务。5. 常见问题排查学生最易翻车的五个节点及根治方案5.1 现象小程序登录后首页空白控制台报Cannot read property real_name of undefined原因前端store/index.js中用户信息未正确初始化。uni.getStorageSync(userInfo)返回null但组件直接访问userInfo.real_name。解决在App.vue的onLaunch钩子中强制校验onLaunch() { const userInfo uni.getStorageSync(userInfo) if (!userInfo || !userInfo.real_name) { // 未登录或信息不全跳转登录页 uni.redirectTo({ url: /pages/user/login }) } }同时后端/api/v1/user/info接口增加空值保护GetMapping(/info) public Result getUserInfo() { SysUser user userService.getById(getCurrentUserId()); if (user null) { return Result.fail(用户不存在); } // 强制填充默认值避免前端判空 user.setRealName(Optional.ofNullable(user.getRealName()).orElse(未知用户)); return Result.success(user); }5.2 现象管理员在“用户管理”页无法删除用户点击无响应原因前端按钮绑定了clickdeleteUser(id)但deleteUser方法未定义或定义在错误的Vue实例中如写在data()里而非methods:{}。解决检查pages/admin/user-manage.vue的methods区块确保有methods: { deleteUser(id) { uni.showModal({ title: 确认删除, content: 删除后不可恢复确定吗, success: (res) { if (res.confirm) { this.$http.post(/api/v1/sys/user/delete/${id}) .then(() { uni.showToast({ title: 删除成功 }) this.loadUserList() // 重新加载列表 }) } } }) } }5.3 现象日程创建时时间选择器显示NaN/NaN/NaN原因微信小程序picker modedate的value属性必须是YYYY-MM-DD格式字符串但后端返回的startTime是2023-05-20T09:00:00ISO8601格式。解决前端统一格式化工具函数// utils/date.js export function formatDate(dateStr) { if (!dateStr) return const date new Date(dateStr) return ${date.getFullYear()}-${String(date.getMonth() 1).padStart(2, 0)}-${String(date.getDate()).padStart(2, 0)} } // 在页面中使用 data() { return { dateValue: formatDate(this.schedule.startTime) // 而非直接赋值dateStr } }5.4 现象2-run.bat执行后端启动失败报错Failed to configure a DataSource原因application.yml中数据库配置被注释或格式错误常见于复制粘贴时缩进丢失。解决用YAML校验工具如 yamlchecker.com 验证配置确保spring: datasource: url: jdbc:mysql://localhost:3306/personal_schedule?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: your_password # 此处必须填写真实密码 driver-class-name: com.mysql.cj.jdbc.Driver特别注意password字段后不能有多余空格url中的serverTimezone必须指定否则MySQL 8.0会报时区错误。5.5 现象演示视频中“重要日”红色角标未显示原因main.css.bak是备份文件实际生效的是main.css但开发者忘记将.bak后缀移除导致样式未加载。解决检查static/css/目录确认main.css存在且内容包含.important-tag { display: inline-block; background: #e63946; color: white; font-size: 12px; padding: 2px 6px; border-radius: 3px; margin-left: 4px; }然后在pages/schedule/list.vue中正确引用view classschedule-item text{{ item.title }}/text text v-ifitem.is_important classimportant-tag重要/text /view6. 答辩与验收用三份材料构建可信度闭环答辩不是背诵PPT而是用可验证的材料证明你真的做过。我带过的项目里最常被问住的问题不是技术细节而是“你怎么证明这个功能真的可用”——所以验收必须围绕“可演示、可追溯、可复现”展开用三份材料构建闭环。6.1 演示视频聚焦“三分钟黄金片段”而非全程录屏提供的演示视频编号156时长12分钟但答辩时只需截取其中三分钟黄金片段播放0:00-1:20管理员登录 → 进入“用户管理” → 新建用户A输入姓名/手机号/密码→ 切换至用户A视角登录 → 查看个人中心显示正确信息。1:21-2:40用户A创建一个“重要日”日程标题项目答辩时间明天14:00勾选重要→ 返回首页红色角标立即高亮 → 点击进入详情页确认is_important1字段已写入数据库。2:41-3:00管理员后台执行SELECT * FROM schedule_info WHERE is_important1 AND statuspending;终端显示刚创建的日程记录。关键技巧播放视频时鼠标不要停在播放器上而是用另一台设备打开MySQL客户端实时执行查询语句。当视频里出现红色角标时你同步敲出SQL并回车屏幕上立刻跳出结果——这种“视频终端”双屏联动比任何PPT都更有说服力。评委看到的不是“我做了”而是“此刻正在发生”。6.2 源码交付包用文件清单建立信任锚点源码压缩包名为【微信小程序毕业设计】个人日程安排系统开发项目(源码演示视频说明).rar解压后必须包含以下不可缺失的12个文件/目录缺一不可文件路径类型验收要点为什么重要/backend/目录Maven项目结构完整含pom.xml和src/main/java证明后端可编译非截图伪造/frontend/目录uni-app标准结构含pages/和static/证明前端可运行非静态HTML/db_init.sqlSQL文件包含CREATE TABLE和INSERT INTO sys_user语句证明数据库可一键初始化/docs/目录含需求规格说明书.md和API接口文档.pdf证明有设计过程非边写边猜/video/demo-156.mp4视频文件时长≥12分钟含片头片尾证明演示真实存在/config/application-prod.yml配置文件spring.profiles.active: prod已激活证明生产环境配置完备/scripts/1-install.bat批处理内容可读含npm install和mvn compile证明部署流程标准化/static/css/main.cssCSS文件存在.important-tag样式定义证明UI细节真实实现/pages/admin/user-manage.vueVue文件含v-for循环和click事件绑定证明管理功能非占位符/src/main/java/com/example/service/ScheduleService.javaJava文件含checkTimeConflict()方法实现证明核心算法真实编码/README.md文档包含“如何运行”“常见问题”章节证明交付物面向使用者/LICENSE许可文件MIT协议文本证明代码可合法使用答辩时不必逐个展示但当评委问“你这个权限控制怎么实现的”你可以立刻打开/src/main/java/com/example/controller/SysUserController.java定位到PreAuthorize(hasRole(ADMIN))注解并指向旁边的/docs/API接口文档.pdf第23页——这种“源码→文档→视频”的三角印证会让质疑声瞬间消失。6.3 答辩话术用“设计权衡”替代“技术名词堆砌”评委最反感的回答是“我用了Spring Boot因为它很流行”。要升级为“我选Spring Boot 2.7.x而非3.x是因为团队成员普遍使用JDK 8而Spring Boot 3.x强制要求JDK 17强行升级会导致Maven插件兼容性问题这是我们组在预研阶段实测发现的”。把技术选择转化为具体约束下的理性决策。准备三个必答题应答模板Q为什么用MyBatis-Plus而不是JPAA“JPA的Hibernate二级缓存对个人日程这种低并发场景收益有限反而增加学习成本MyBatis-Plus的LambdaQueryWrapper让我们能用eq(User::getUsername, admin)代替硬编码字段名既保证类型安全又避免SQL注入代码可读性提升40%。”Q小程序前端为什么不用原生WXMLA“uni-app的跨平台能力是冗余的但我们看重它的Vue语法生态。当需要快速接入图表库时可以直接用vue-echarts而原生小程序要自己封装Canvas绘图逻辑——毕设周期只有12周我们必须把时间花在业务逻辑上而不是重复造轮子。”Q数据安全怎么保障A“三重防护1密码用BCrypt加密存储盐值随机生成2JWT令牌设置2小时过期且每次刷新都更新refresh_token3所有敏感接口如删除用户要求二次确认前端拦截后端才执行SQL。您看SysUserController.java第87行DeleteMapping(/delete/{id})上方有PreAuthorize(hasAuthority(sys:user:delete))权限校验在Spring Security过滤器链中完成不可能绕过。”从那以后我每次带毕设都强制学生在答辩前三天用一台干净电脑从零部署一次下载压缩包 → 解压 → 运行1-install.bat→ 启动小程序 → 完成一次完整日程创建 → 登录管理员后台查看记录。如果中间任何一步失败立刻回溯日志。这个习惯让我避开了90%的“答辩现场翻车”事故——希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?