1. 项目到底做什么需求拆解与功能边界计算机实训室管理系统这个题目一出来很多同学第一反应是“不就是做个预约系统嘛”。这个理解不能算错但如果真按这个思路往下做大概率会做成一个“换皮”的会议室预定系统答辩时老师一问需求边界马上就会露馅。我自己的经验是这类“XXX管理系统”的毕业设计最核心的竞争力不在于代码炫技而在于能不能把业务痛点讲清楚。这个项目的真实需求背景是什么呢高校计算机实训室也就是俗称的机房通常承担三类业务日常教学上课、课程设计集中训练、自由开放预约。这三类业务在时间上互相挤占在资源上交叉共享传统的人工排表管理经常出问题——比如同一间实训室被两门课程同时申请比如学生预约了机器但临时不来导致资源空置比如设备坏了一周都没人报修。1.1 核心业务场景画像既然要设计系统第一步是画出角色和场景。实训室管理涉及的参与方有四个学生需要查看空闲实训室、发起预约、取消预约、查看自己的预约记录。教师需要申请实训室用于上课或实验可以批量预约多节课也可以临时调课。实训室管理员负责审核预约、处理冲突、管理设备信息、登记故障报修、发布开放时间公告。系统管理员维护用户账号、分配角色权限、管理基础数据实训室信息、专业班级信息。业务场景不仅仅是“预约”这一个动作。一次完整的使用流程是管理员维护实训室基础信息 - 管理员或教师创建课程/开放时段 - 学生提交预约 - 系统自动检查冲突没有冲突则自动通过有冲突则转入人工审核- 使用结束后管理员登记设备状态 - 如有故障则生成维修工单。这一条链路下来系统才有了真正的管理价值而不是一个只记录“谁在几点用了哪间机房”的记事本。1.2 功能模块与信息架构基于上面的场景我建议把系统拆成五个核心模块模块核心功能关键设计点用户与权限登录注册、角色区分、个人信息维护基于角色的接口权限控制实训室管理实训室CRUD、开放时间设置、容量管理状态字段开放/维护/关闭预约管理预约、取消、审核、查询时间冲突检测、审批状态流转设备管理设备台账、故障报修、维修记录设备与实训室的多对一关系数据统计使用率统计、预约排行、故障统计为答辩加分的大屏展示这里要特别强调一个设计取舍不要把实训室管理和设备管理做成两张皮。很多同学会把设备做成独立模块然后发现预约时根本不关心设备导致两个模块割裂。我建议在实训室详情里关联设备列表预约实训室时可同时看到该机房可用设备数量这样业务逻辑才完整。比如“预约B405机房”和“同时确认B405机房内40台可用计算机”在真实场景里是同一个决策拆开就是需求分析没做透。2. 技术选型为什么是这套组合SpringBoot生态打法这个项目用SpringBoot Java几乎是毕业设计里的“标准答案”。但这不意味着你可以说不清楚为什么。答辩老师最喜欢问的一句话就是“为什么用SpringBoot为什么不用SSH为什么不用Python”2.1 框架选型背后的真实考量SpringBoot的核心价值是**“约定大于配置”**。对于单人开发的毕业设计项目来说这直接意味着你不需要像SSM那样花大量精力写XML配置一个spring-boot-starter-web依赖就能把内嵌Tomcat、DispatcherServlet、JSON序列化全部搞定。对新手最友好的是只要照着SpringBoot的自动装配思想去做项目的启动和调试成本极低。再一个原因是生态成熟度。这个项目涉及ORM数据库映射、权限控制、接口文档、Redis缓存等通用需求。SpringBoot里对应的解决方案分别是MyBatis-Plus、Spring Security或者Sa-Token后面我会讲、Knife4jSwagger增强版、Spring Data Redis。每一步都有铺天盖地的教程和现成案例遇到问题一搜就有答案。作为毕业设计稳定踩通 新奇炫技这一点务必放在第一位。2.2 前端方案与部署架构前端我推荐Vue 3 Element Plus管理后台类页面用Element Plus做表格、表单、弹窗、Tab切换开发效率极高。如果你的前端基础一般甚至可以只用Vue Axios Eleement Plus的CDN模式搭页面不必引入Vue Router和Pinia这种完整工程化方案因为毕业设计的演示重点在功能完整度不在前端工程化深度。比较关键的是前后端交互方式。统一走RESTful API约定返回结构为{ code, message, data }。我在写这个项目时定义了一个ResultT统一返回类所有接口都返回这个结构前端拦截器统一判断code是否为200不是就弹出message。这个设计在答辩时讲“统一响应体、统一异常处理”非常加分。部署架构上最稳妥的方案是后端打成单个JAR包前端用npm run build生成dist目录后放进SpringBoot的src/main/resources/static/下。这样整个系统只需要一个Java进程就能跑起来演示时不会因为端口、跨域、静态资源路径的问题翻车。跨域问题也因此在开发环境就解决掉开发时前端走Vite代理生产环境直接将静态资源由SpringBoot托管。2.3 项目目录结构的“毕业设计标准版”很多同学的代码不行不是写不出功能而是目录乱成一锅粥。这里分享一个我实际使用后觉得非常稳妥的包结构com.example.labmanagement ├── controller # 接口层只做参数接收和结果返回 ├── service # 业务层写具体逻辑接口实现类分离 ├── mapper # MyBatis-Plus的Mapper接口 ├── entity # 数据库实体类 ├── dto # 前端传参对象和entity分离避免直接暴露表结构 ├── vo # 返回给前端的视图对象 ├── config # 配置类跨域、分页插件、静态资源映射 ├── common # 统一返回Result、异常处理、常量类 └── utils # 工具类时间处理、JWT工具等这个结构不是花架子。VO和DTO分离能让你在答辩时讲清楚“为什么不直接把Entity返回给前端”——因为数据库字段不应该暴露给调用方这在真实企业项目里是底线规范写在毕业设计里就是亮点。3. 数据库设计这是毕设最容易被问倒的地方数据库表设计决定了一个管理系统的天花板。预约类的业务核心难点在于同一资源在时间维度上的冲突判断。很多同学在设计数据库时只想着“建几张表存数据”忽略了“如何查询冲突”这个根本问题。3.1 核心表结构与关系设计我设计的核心表有八张用户表、角色表、实训室表、设备表、预约表、课程时间表、维修表、公告表。下面挑重点讲几张。实训室表 lab字段包括id、名称、位置、容量、设备数量、是否开放状态开放/维护/关闭、开放时间说明、备注。这里的关键是不要把“是否开放”设计成布尔值而要用枚举状态的值。因为机房存在临时维护、期末禁用等情况三态比两态更贴近真实业务。预约表 reservation字段包括id、用户id、实训室id、预约日期、开始时间、结束时间、用途说明如“Java课程设计”、预约类型学生自由预约/教师课程预约、审批状态待审批/已通过/已驳回/已取消/已超时、审批人id、创建时间。这张表是整个系统的核心几乎所有并发和冲突问题都围绕它展开。设备表 equipment字段包括id、实训室id外键、设备编号、设备名称台式机/服务器/投影仪等、硬件配置描述、状态正常/故障/维修中、最后维护时间、故障描述。设备和实训室是多对一关系设备状态变更时后端要同步更新实训室的可使用设备数这块我在后面“实操过程”里详细说。需要特别注意的是预约时间段的存储方式。我推荐用“开始时间 结束时间”两个datetime字段而不是用单一时间段字符串。为什么因为冲突检测SQL只有基于可比较的时间字段才能写出来。用start_time #结束# AND end_time #开始#这种区间重叠判断时datetime的精度和索引效率都远高于字符串模糊匹配。3.2 预约冲突检测的逻辑与SQL这是整个项目的技术C位。冲突检测的本质是判断两条预约是否在“同一个实训室”上存在时间重叠。口诀是一条记录的开始时间小于另一条的结束时间且该记录的结束时间大于另一条的开始时间。写成条件就是SELECT COUNT(*) FROM reservation WHERE lab_id #{labId} AND reservation_date #{date} AND status IN (已通过, 待审批) AND ( (start_time #{endTime} AND end_time #{startTime}) )这个条件能覆盖所有重叠场景已有预约 9:00-11:00新预约 10:00-12:00则9:00 12:00 且 11:00 10:00冲突。已有预约 9:00-11:00新预约 8:00-9:30则9:00 9:30 且 11:00 8:00冲突。已有预约 9:00-11:00新预约 11:00-12:00则9:00 12:00 但 11:00 11:00为false不冲突。注意边界相等的场景11:00整点交接是否算冲突取决于业务规则。计算机实训室的使用通常需要留出机器检测时间所以我在系统中设计为“边界相交算不冲突但前后预约之间必须间隔15分钟以上”。这个15分钟校核在处理逻辑里额外判断给数据库对比加上一个“宽限时间”。3.3 状态机设计预约单的生命周期每个预约单都应该有明确的状态流转而不是单纯用一个“状态”字符串随便改。我定义的状态机如下状态流转图文字版描述学生提交预约 -待审批教师提交课程预约 -待审批需要管理员确认课程表待审批状态下管理员审核 - 通过则变成已通过驳回则变成已驳回已通过且当前时间超过预约结束时间 - 自动标记为已完成已通过但预约开始时间已过且用户未签到 - 系统定时任务标记为已超时这一点在答辩时非常加分实现这个状态机最忌讳的是在Controller里随手setStatus(已通过)。正确的做法是定义一个枚举ReservationStatusEnum所有状态变更都在Service层通过专门的方法如approve(),reject(),cancel(),complete(),timeout()来完成每个方法内部做前置状态校验。这样即使以后要增加“待签到”状态也不会牵一发动全身。数据一致性方面还要考虑取消预约时释放资源。如果用户在通过后取消数据库要记录取消时间并且不能让同时间段的其他请求在事务未提交前看到旧数据。这里就用到了事务把“查询冲突 插入预约”包在同一个Transactional方法里配合数据库的行锁或唯一索引兜底才能保证高峰期并发预约不会出双卖的问题。4. 核心功能实现预约流程与资源调度的完整落地项目骨架搭好、数据库设计妥当之后下面就是纯编码环节。这部分我在实操中总结了一套“先跑通用能力再做核心链路”的顺序先做统一返回和异常处理再做登录鉴权然后做实训室CRUD最后攻预约流程。4.1 预约接口的完整实现链路预约是核心接口这里给出详细思路。Controller层接收一个ReservationCreateDTO对象包含labId、reservationDate、startTime、endTime、purpose、type。Controller不做业务判断直接调用Service层。Service层方法createReservation的步骤是校验用户是否有预约权限登录拦截器已做了角色判断这里是二次校验。校验实训室是否存在且状态为“开放”。校验时间合法性开始时间不能早于当前时间结束时间必须晚于开始时间单次预约时长上限4小时可配。校验是否与现有预约冲突执行上面那条冲突检测SQL。如果冲突返回错误码“该时段已被占用”。如果不冲突创建预约记录状态设为“待审批”或“自动通过”我建议实训室开放时间内、且满足时长限制的预约可以自动通过管理员只需审批超长时段或课程预约——这就是“智能预约”和普通预约系统的区别所在。返回预约单ID和状态。第6步里的“自动通过”逻辑是我觉得这个项目最值得讲的亮点。它在Service里实现只需要十几行代码但把人工审核的负担大幅降低了。核心规则是预约类型为“自由预约”且时段完全落在实训室“开放时间区间”内且时长不超过2小时 - 自动通过。其余情况进入待审批。4.2 资源调度与值班安排资源调度的核心是“给每间实训室排出可预约的开放时段”。我在系统里设计了一个lab_schedule表记录实训室在一周内可预约的时段模板例如“周一 8:00-12:00、14:00-18:00”。预约时系统除了检查冲突记录还要检查预约时间是否落在该模板的允许区间内。这个双层校验能有效防止非开放时间的重复预约也让前台页面准确展示每一间实训室本周的可用情况。这个设计比单纯“预约次数限制”更科学。比如机房在期末有考试封闭管理员只需临时将该实训室的开放状态改为“维护”或者临时关闭该时段模板就能一键停用而不需要一条条驳回已预约的订单。器材调度上设备预约可以做成实训室预约的附属品用户选择实训室后系统自动带出当前可用的设备数量用户可选“是否需要全部设备”或指定设备编号。但在毕业设计的两周开发周期里建议先做“实训室预约包含设备数量”的简单模式设备级的单独预留在“后续改进”里提一句就行。答辩时这不算偷工减料反而说明你懂得控制需求范围。4.3 设备故障与维护闭环前文提到设备表有状态字段。这里补全维护闭环的流程学生/教师在实训室详情页发现某台设备不可用、点击“报修” - 创建维修记录设备id、实训室id、故障描述、报修人、报修时间 - 设备状态变为“故障” - 管理员在维修管理页面看到待处理工单 - 管理员标记“维修中” - 维修完成后更新设备状态为“正常”并将设备状态同步回实训室可用数量。这个流程里最容易出bug的地方是状态同步。我的做法是设备状态的更新不走直接UPDATE都统一走EquipmentService.changeStatus(equipmentId, targetStatus)方法这个方法内部同步更新实训室表的可用设备数量。例如故障时可用数减一修复时可用数加一。所有同步逻辑收口在一个Service方法里就不会出现设备表说正常、实训室显示不可用的数据漂移问题。这里再提一个经验设备数量同步使用乐观锁版本号版在lab表加version字段更新时用UPDATE lab SET available_count available_count - 1, version version 1 WHERE id ? AND version ?。如果在并发状态下两个人同时操作版本号不匹配则失败重试避免明明是40台设备实际可用数被减成负数。5. 实操全过程从零搭建到跑通的完整记录理论讲完下面是纯粹的手把手实操流程。这部分我按“从零开始到可演示”的顺序梳理尽量做到你照着做就能跑起来。5.1 环境准备与项目骨架创建开发工具建议统一用IntelliJ IDEAJDK用1.8或11都可以我推荐JDK 1.8虽然老但兼容性最好部署服务器时不容易出幺蛾子。SpringBoot版本选2.7.x不要选3.x原因是3.0起基于Jakarta EE与很多老教程不兼容且毕业设计的代码量完全用不到3.x的新特性。创建项目时在Spring Initializr勾选以下依赖Spring WebMySQL DriverMyBatis Framework如果直接用MyBatis-Plus这步可以不勾后面pom手动加Validation参数校验然后把MyBatis-Plus依赖手动加入pom.xmldependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3/version /dependency同时加入Knife4j接口文档依赖dependency groupIdcom.github.xiaoymin/groupId artifactIdknife4j-openapi2-spring-boot-starter/artifactId version4.4.0/version /dependency配置文件application.yml的要点配置如下server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/lab_management?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 123456 jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: Asia/Shanghai mybatis-plus: configuration: 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这里有一个非常重要的坑数据库连接URL必须显式指定serverTimezoneAsia/Shanghai。不指定的话MySQL 8.0默认UTC时区会导致你插入的时间比本地时间少8小时。我在带毕设学生时见过太多次这种“明明存了9点查出来变成凌晨1点”的诡异问题根因全是时区。5.2 编码实现中的关键点先写实体类和Mapper。以实训室实体为例Data TableName(lab) public class Lab { TableId(type IdType.AUTO) private Long id; private String name; private String location; private Integer capacity; private Integer availableCount; private Integer status; // 0开放 1维护 2关闭 private String openTimeDesc; private String remark; }MyBatis-Plus的BaseMapper提供了大部分CRUD方法不用写SQL。这里要注意字段驼峰和数据库下划线命名会自动映射前提是map-underscore-to-camel-case保持默认开启。如果你的实体字段是openTimeDesc数据库列是open_time_desc查询结果会自动对应上。预约Service实现冲突检测时建议使用MyBatis-Plus的QueryWrapper或LambdaQueryWrapper。我习惯用Lambda写法代码不易出错LambdaQueryWrapperReservation wrapper new LambdaQueryWrapper(); wrapper.eq(Reservation::getLabId, dto.getLabId()) .eq(Reservation::getReservationDate, dto.getReservationDate()) .in(Reservation::getStatus, ReservationStatusEnum.PENDING.getCode(), ReservationStatusEnum.APPROVED.getCode()) .and(w - w.lt(Reservation::getStartTime, dto.getEndTime()) .gt(Reservation::getEndTime, dto.getStartTime()));后半段and里的lt和gt对应前面讲的冲突判断口诀。这样查询一次数据库就能返回所有冲突记录不需要把所有预约load到内存再比较。这是性能习惯也是代码规范虽然毕业设计数据量不大但这些细节正是答辩提问的对象。5.3 前端页面与后端联调细节前端我用Vue3 Element Plus Axios项目结构简约为登录页面、主页框架侧边栏顶栏、实训室列表页、预约操作页、我的预约页、审核管理页、设备管理页、统计页。登录页调用/api/user/login接口成功后拿到token存到localStorageAxios请求拦截器统一在header里加token字段。后端用一个拦截器解析token获取当前用户id和角色。这里推荐使用Sa-Token替代Spring Security理由很简单Sa-Token的API对新手友好到极致StpUtil.login(userId)一行搞定登录SaCheckRole(admin)一个注解搞定权限控制完全不需要搞Spring Security那套过滤器链和UserDetailsService配置。联调阶段最容易出问题的是时间格式的传递。前端传给后端的时间参数强烈建议统一用字符串yyyy-MM-dd HH:mm:ss或日期字符串yyyy-MM-dd而不是用时间戳数字。后端实体用LocalDateTime接收Jackson配置了date-format后能自动格式化和反序列化就没有前端时间组件和后端LocalDateTime格式不匹配的烦恼了。如果开发时前端用Vite启动在5173端口后端运行在8080端口需要配置Vite代理server: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } }部署时把npm run build生成的static资源复制到SpringBoot的static目录下前端访问的就是8080端口不再需要代理这也是前面推荐单包部署的出发点。5.4 演示数据与测试用例准备毕业设计演示最怕的是“现场填数据”。你必须在答辩前把数据库里预置好一批像样的数据10间实训室、每间对应20到60台设备、5个角色账号一个系统管理员、两个实训室管理员、三个教师、十几个学生、一周内的课程预约记录、几条不同的预约状态记录已完成、待审批、已驳回、已超时各来一条。这样演示时点击查询列表界面是满的而不是一个个空表格观感完全不同。测试用例也要准备几个核心场景学生预约空闲时段 - 自动通过。学生预约已占用时段 - 提示冲突。教师提交课程预约超出开放时间 - 进入待审批。管理员驳回预约 - 学生端状态刷新。设备故障报修 - 实训室可用数减少 - 维修完成 - 可用数恢复。每个场景我建议写成一个接口测试脚本用Postman保存答辩时直接跑接口给老师看响应结果。比现场打开页面慢慢操作效率高而且给人感觉你对自己的系统非常熟悉。6. 踩坑实录常见问题与答辩高频问题做到这一步项目基本能跑了。但我在帮学生debug的过程中积累了很多经典问题这里挑高频率的分享出来每个都是真实的坑。6.1 开发中高频报错与排查方法问题一数据库时间少了8小时表现前端显示预约时间是10:00数据库里存的是02:00。根因有两个一是数据库连接URL缺少serverTimezoneAsia/Shanghai二是MySQL服务器时区设置成了UTC。排查方法执行SELECT NOW();看数据库当前时间如果和本地时间不一致修改连接参数即可。问题二分页查询不生效表现MyBatis-Plus的Page对象传入后返回的记录数不对或total为0。根因大多是分页拦截器没配置。MyBatis-Plus 3.5之后需要手动配置Configuration public class MybatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }不配置这个拦截器时分页SQL其实变成了普通查询这种错误很难肉眼发现因为代码没报错、数据也返回了但就是不完全。问题三事务不生效表现先插入预约记录再更新实训室可用数第二步抛异常但预约记录竟然还在。这通常是因为Service方法自己调自己this调用导致Transactional失效或者是方法被private修饰。Spring的声明式事务是基于动态代理实现的只有外部调用代理对象的方法才能被拦截。解决办法是把事务方法放在独立的Service里通过注入的Bean调用。问题四跨域请求被拦截表现前端请求报CORS error。解决方式最简单的是在后端加一个配置类统一放行Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOriginPatterns(*) .allowedMethods(GET, POST, PUT, DELETE, OPTIONS) .allowedHeaders(*) .allowCredentials(true) .maxAge(3600); } }但要注意生产环境单包部署后就完全没有跨域问题了这个配置只用开发阶段。问题五JWT登录后无法获取当前用户我推荐的Sa-Token方案能规避这个问题但如果你用JWT常见的错误是token过期时间设置太短比如30分钟导致答辩演示到一半就提示“未登录”。建议token有效期设置成24小时以上让学生体验更好也减少演示时的不必要麻烦。6.2 答辩高频问题与回答思路答辩时老师可能不会深入看代码但一定会问几个“灵魂拷问”。提前想好回答能大幅提升通过率。“你如何处理多个用户同时预约同一时间段的冲突”这里重点讲事务和数据库约束。回答框架前端提交时调用冲突检测Service这一步会开启事务查询数据库中的重叠记录同时通过数据库层面的唯一约束uk_lab_date_start_end兜底在插入时数据库会检查并发情况下只有一条能插入成功另一条会抛出主键冲突异常被全局异常处理器转换成“该时段已被预订”的提示。并发环境下用数据库约束兜底比单纯的代码查询更可靠——这一句是非常加分的。“你的权限控制是怎么实现的”回答框架采用基于角色的访问控制模型RBAC。用户表关联角色表角色表关联权限表。登录后Sa-Token生成token并存储用户信息前端每次请求携带token拦截器解析出当前用户角色通过SaCheckRole(admin)注解控制接口访问级别。普通用户访问管理接口会返回无权限错误码。演示时可以现场用一个学生账号访问管理员接口展示被拦截的效果。“你系统的数据一致性怎么保证比如预约通过时同步更新了设备状态如果中途出错了怎么办”回答框架这两步操作放在同一个Transactional方法中Spring的数据库事务保证要么全部成功、要么全部回滚。没有事务的话第一条INSERT成功了第二条UPDATE失败数据库里就会出现已经通过预约但实训室可用数未减少的脏数据。这里可以举例说明自己实际遇到过然后又怎么用事务解决比背理论更可信。“如果线上部署有什么改进空间”回答框架可以把实训室列表页加入Redis缓存减少数据库压力可以用定时任务统计每日使用率可以用消息队列削峰预约请求生产环境数据库连接池可以接入HikariCP调优连接数。把这些方向说清楚显得你有架构思维。7. 项目验收与交付不是写完就完了代码和演示都顺利了最后还差一步——验收与交付。这个环节对毕业设计来说不是可选项而是直接影响你最终评分的关键。首先是文档与答辩PPT的准备。系统设计文档一定要包含三张核心图用例图画出四个角色分别能做什么、ER图画出用户、实训室、预约、设备四张核心表的关系、功能架构图画出五层模块结构。这三张图在答辩时是老师理解你系统的“最快路径”也是拉高印象分的利器。然后是代码版本管理。哪怕只有你一个人写代码也建议在项目一开始就git init并把代码推到远程仓库。每次完成一个模块就commit一次commit信息写清楚比如feat: 完成实训室CRUD接口、fix: 修复预约冲突检测边界问题。这样做有两个好处一是出现无法解决的bug可以回退到上一个稳定版本毕业设计项目时间紧这功能能救命二是答辩时有Git提交记录本身就是“编码习惯规范”的实证这比你说一万句“我有良好的开发习惯”都有说服力。最后的体会是这个项目的境界分离比想象中重要。很多同学在实训室预约功能上花了整整两周时间反复修改却忽略了基础数据的维护和统计展示结果是核心功能虽然复杂但使用频率最高的模块体验极差。我接这类项目时一定会先确保“登录、列表、预约、审核”这条核心链路彻底稳定再往边上扩展。如果你正在做这个题目记住一个优先级核心链路顺畅的运行 边角模块的新奇功能 数据可视化的酷炫程度。照着这个顺序来你大概率能平稳地完成整个毕业设计。