ARTICLE DETAIL

资讯详情

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

SpringBoot+Vue+MySQL企业车辆管理系统毕业设计实战全流程

SpringBoot+Vue+MySQL企业车辆管理系统毕业设计实战全流程 从选题那天起我就打定主意做一个能真正跑起来的毕业设计而不是交一个只停留在PPT上的原型。SpringBootVueMySQL这个组合几乎是当下企业级Web开发最主流的入门三件套网上资料多、踩坑方案全遇到问题不至于孤立无援。最关键的是企业车辆管理系统这个题目功能边界清晰、业务场景日常、数据结构不算复杂但足够展开非常适合在几个月的毕设周期内完整落地。这篇总结把我从环境搭建、数据库建模、前后端联调、部署打包到写论文答辩的全过程按真实顺序捋了一遍准备做同类系统或者准备答辩的学弟学妹可以直接照着这条链路走。1. 系统功能拆解一个企业车辆管理系统到底该管什么很多同学拿到题目后第一件事就是建表写代码这其实最容易翻车。我建议先花三四天把功能边界画清楚否则后期每加一个模块都要动表结构非常痛苦。1.1 角色权限模型先回答谁在用、能用什么车辆管理系统里最常见的角色有三种系统管理员、车管员调度员、普通员工用车人。我最后加了一个仅用于演示的超级管理员角色用来给答辩时展示权限控制逻辑。超级管理员可以查看所有数据、管理后台账号、修改系统配置。答辩时演示你改不了别人的数据就靠这个角色。车管员负责车辆档案维护、审批用车申请、登记维保与违章记录、查看全量统计报表。普通员工只提交用车申请、查看自己的申请进度与历史记录。权限模型没有做得特别重采用经典的RBAC基于角色的访问控制一张用户表、一张角色表、一张菜单权限表再加一张用户角色关联表。为什么不做细粒度的数据权限因为毕设周期有限RBAC足以满足答辩时不同角色登录后看到的菜单不同这个演示点。如果想让系统显得更完整可以在申请表里加一个归属字段让普通员工只能查询 owner_id 等于自己ID的数据这就是数据权限的雏形论文里也能多写一小节。1.2 业务模块清单照着这张表核对不会漏我列出最终实现的模块供你做需求梳理时参考。每个模块我后面都会讲关键实现但这张表可以帮你先建立整体印象模块核心功能涉及角色车辆档案管理新增/编辑/删除车辆上传行驶证照片车辆状态管理可用、维修中、已报废车管员司机信息管理司机档案CRUD、驾照到期提醒车管员用车申请审批员工提交申请、车管员审批、状态追踪员工、车管员车辆调度派车审批通过后分配车辆与司机生成出车记录车管员维保管理保养/维修记录登记保养到期提醒车管员违章管理违章记录登记、罚款金额、处理状态车管员加油管理加油记录录入统计油耗数据车管员保险年检管理保险到期时间、年检到期时间提醒车管员系统管理用户管理、角色管理、菜单管理、日志管理超级管理员数据统计用车趋势、车辆使用率、费用统计图表车管员、超级管理员这里要特别说明一下车辆调度派车这个模块它是整个系统的业务核心也是论文里可以重点展开的亮点。我的做法是申请审批通过后车管员在待派车列表里选择空闲车辆和可用的司机点击派车系统自动生成一条出车记录同时车辆状态从空闲变为出车中。答辩时演示这个流程比单纯演示增删改查有说服力得多。1.3 流程设计用车申请的全生命周期业务流程图不需要画得多复杂但状态流转必须清晰。我设计的申请状态有五个待审批、已批准、已拒绝、已派车、已完成已还车。员工提交申请后状态为待审批。车管员批准后状态变更为已批准此时可以在待派车列表中对车辆进行分配。分配车辆和司机后状态变更为已派车。车辆使用完成车管员登记还车信息后状态变更为已完成车辆状态恢复为空闲。这个状态机看着简单但实现时最容易出问题的是状态和历史记录的联动。比如一次申请被拒绝后员工不能修改原申请再提交应该重新发起一条申请。我的做法是在前端做判断如果状态不是待审批就不显示修改和重新提交按钮后端再做一次校验防止直接调接口绕过前端。2. 数据库设计的几个关键决策数据库设计直接决定开发效率和后期扩展空间网上随便找的建表脚本往往表字段命名混乱、缺少外键约束和索引跑通Demo没问题一写论文就露馅。2.1 核心表结构不能只有车辆和申请两张表我最终一共有12张表这里列一下核心表的字段设计思路具体SQL太长就不全贴了车辆信息表vehicleid 主键plate_number 车牌号必填唯一索引brand_model 品牌型号purchase_date 购置日期vehicle_type 车辆类型轿车/SUV/客车/货车status 状态空闲/出车中/维修中/已报废mileage 当前里程oil_consumption 百公里油耗基准值车牌号一定要加唯一索引核心业务数据重复了会出大问题。status字段用Integer存储1到4分别代表四种状态前端用字典表翻译比直接存中文灵活。用车申请表vehicle_applyid 主键apply_user_id 申请人工号reason 用车事由start_date / end_date 预计用车时间段destination 目的地approval_status 审批状态1待审批 2已批准 3已拒绝 4已派车 5已完成apply_time 申请时间这里有个细节我在论文里着重写了为什么不在申请表里直接放vehicle_id和driver_id的外键因为派车动作发生在审批通过之后如果设计成在申请表里填写车辆ID会出现申请刚提交就被分配车辆的逻辑漏洞。我单独建了一张派车记录表dispatch_record将申请ID、车辆ID、司机ID、实际出车时间、还车时间解耦这样审批、派车、还车才能形成完整闭环。维保记录表maintenance_recordidvehicle_id 车辆IDmaintenance_type 保养/维修maintenance_date 维保日期cost 费用next_maintenance_date 下次保养日期remark 备注这个表的目的很明确配合定时任务实现保养到期提醒。我在车管员首页放了一个提醒面板显示所有在30天内到期或者已经过期的车辆答辩演示效果很好。2.2 表关系与外键策略适度使用不要上瘾有些教程喜欢建一堆外键看起来关系严谨实际操作时很麻烦。MyBatis-Plus做复杂关联查询时外键约束反而会限制灵活性而且生成树状JSON时容易循环引用。我的做法是业务表之间保留逻辑关联通过字段名体现逻辑外键如 apply_user_id 对应用户表主键但不强制创建物理外键。仅对权限相关的表用户角色关联表使用物理外键保证数据一致性。所有核心查询字段plate_number、apply_user_id、vehicle_id、approval_status都建了普通索引。这个设计思路答辩时老师很容易追问我的解释是物理外键会降低大数据量下的插入性能而且项目用的是逻辑删除deleted字段物理外键会和逻辑删除冲突所以业务表只保留逻辑关联。这个回答提前准备好基本能堵住追问。2.3 逻辑删除与时间字段的约定对外称毕设要有工程规范实际上是为了自己后期好维护。我的约定每张表都有deleted字段0正常 1已删除配合 MyBatis-Plus 的TableLogic注解实现软删除。每张表都有create_time和update_time在插入和更新时自动填充用 MyBatis-Plus 的 MetaObjectHandler 统一处理。金额字段一律用 DECIMAL(10,2)不用Double避免精度问题。这里踩过一个坑逻辑删除字段加上了但没在实体上标注TableLogic导致删除操作变成了物理DELETE。MyBatis-Plus只有在实体类标注了 TableLogic 后才会自动改写SQL为UPDATE否则就是真的删数据。第一次没注意把一条测试数据删了又插不回来后来查MySQL日志才发现是走的物理删除。3. 后端SpringBoot实现中的核心点后端框架的选型SpringBoot 2.7.x是最稳妥的选择JDK用1.8不要一上来就用SpringBoot 3.0和JDK17很多教程和依赖在3.x下不兼容。网络安全和接口鉴权我用了Sa-Token比Spring Security轻量很多学起来快API也直观。3.1 项目分层与目录结构很多人写毕设代码时所有逻辑全堆在Controller里答辩时被老师问你用了什么设计模式就很尴尬。我的目录结构是这样的com.company.vehicle ├── controller接口层 ├── service业务层 impl实现 ├── mapper数据访问层 ├── entity实体类 ├── dto入参DTO对象 ├── vo返回视图对象 ├── config配置类Sa-Token拦截、跨域、元数据填充 ├── utils通用工具类日期处理、Excel导出 └── exception统一异常处理核心思想是Controller很薄只做参数接收和结果封装业务逻辑写在Service中Mapper只做数据库交互。这样分工清晰论文里写代码分层明确符合单一职责原则才站得住脚。3.2 登录认证Sa-Token的接入与踩坑Sa-Token接入非常简单依赖引入后在application.yml配置一下登录成功后调用StpUtil.login(userId)然后前端在请求头里带上 token 即可。有几个容易被忽略的坑必须提醒跨域配置必须允许携带请求头否则前端取到token也发不出去。我在WebMvcConfigurer里配置CorsRegistry时allowedHeaders设置了Authorization和Content-TypeallowCredentials设为true。Sa-Token的token需要设置过期时间。默认是永不过期还是较长时间我记不清了还是建议明确配置sa-token.timeout为 8640024小时防止答辩现场登录状态失效。后端拦截器放行登录接口和静态资源不然登录都访问不了。我的配置放行了/auth/login、/auth/captcha、/error其余路径全部拦截。登录逻辑还应该有一个验证码。我用的是Hutool的CaptchaUtil生成一个算术验证码图片把答案存到Session上前端输入后提交后端校验。这个不复杂但能让系统看起来更完整。3.3 权限控制拦截器 注解实现功能级权限Sa-Token里提供了SaCheckRole和SaCheckPermission注解可以直接加在Controller方法上实现功能级权限控制。我定义了两类权限码vehicle:add、vehicle:edit、vehicle:delete用于车辆管理。apply:submit用于员工提交申请。apply:approve用于审批操作。dispatch:assign用于派车操作。在Sa-Token登录配置里登录成功后查询当前用户角色关联的权限码集合调用StpUtil.login之前先放进StpUtil.getSession()这样拦截器就能直接读取。原理上跟Spring Security的权限集合类似但用起来舒服多了。答辩演示时我只需要切换账号登录点击新增车辆按钮如果是员工账号登录前端拿到403后弹出提示无权限操作整个过程非常直观。3.4 定时任务到期提醒的实现这个功能是我很自豪的一个点。车辆保养到期提醒看似简单用对了方式能体现你的工程思维。我使用Spring自带的Scheduled注解每12小时执行一次扫描维保表找出next_maintenance_date在15天内的车辆向车管员角色用户发送站内信。站内信我建了一张消息表车管员登录后在右上角看到未读数字。等等这里有个细节定时任务不能每次执行就向同一批用户发一次消息否则每次重启都会往数据库里疯狂插数据。我加了一个消息去重逻辑按 vehicle_id 和提醒类型判断如果今天已经生成过提醒则跳过。这个细节写进论文很容易给老师留下考虑问题全面的印象。3.5 文件上传行驶证照片的存储方案车辆档案模块需要上传行驶证照片我最初想存在本地路径后来答辩时老师要求迁移就改了方案。本地存储的问题是重启开发服务器后文件丢失而且打包以后路径容易乱。最终方案上传文件保存在项目的upload/目录下在application.yml里配置一个自定的file.upload-path。在配置类中实现了WebMvcConfigurer的addResourceHandlers把/upload/**映射为本地绝对路径。这样一个简单的虚拟路径映射就能让前端通过/upload/xxx.jpg访问到图片。这里还要注意文件名不能直接用原始文件名我把文件名改成了UUID加扩展名避免中文或特殊字符乱码也避免重名覆盖。4. 前端Vue页面的搭建与调试前端是整个系统的门面也是答辩时老师第一眼看的东西。很多同学花大量时间折腾布局和动画但我觉得前端最核心的还是组件封装、路由权限、状态管理、接口请求封装这四件事。4.1 环境准备别再在Node版本上翻车Vue 2 Element UI 的组合最稳妥配合 Vue CLI 4.x 或者 Vite 搭建。如果之前有Node环境强烈建议先执行node -v检查版本Node 17以上在某些依赖下会报SyntaxError: Unexpected token .我当时就是因为Node版本太高导致Vue CLI启动失败后来用 nvm 切换回 Node 16.20.2 才顺利跑起来。项目的构建方式我也带一下后端SpringBoot和前端Vue分离开发前后端通过API交互本地开发时用Vue CLI自带的proxy代理把/api请求转发到http://localhost:8080。开发期联调非常方便不需要启动Nginx。4.2 Axios封装一个文件管好所有请求前端请求不可能一个接口写一遍我在utils/request.js里统一封装Axios实例做了三件事设置baseURL所有请求自动加/api前缀。请求拦截器从localStorage取出token放到请求头Authorization。响应拦截器统一处理业务状态码。服务端返回状态为401时弹出登录过期提示并跳转到登录页返回403时触发全局提示无权限操作。这里有个实战经验很多毕设项目的前端对错误处理是散乱的每一个请求都单独写失败回调。统一拦截器才能做到后端一旦报错前端全局弹提示代码量直接减少一半别人看你的代码结构也会觉得很工程化。4.3 路由与菜单动态生成才是亮点普通的前端项目路由都是静态写死的但一个权限系统应该根据当前用户的角色动态生成菜单。我的做法是登录成功后调用后端接口/auth/getUserInfo拿到用户角色、权限码列表、菜单列表。前端使用 Vue Router 的addRoute方法根据返回的菜单数据动态添加路由。菜单栏组件根据动态路由表渲染左侧导航。答辩演示时切换一个员工账号登录菜单里只有用车申请、我的申请、个人信息管理员账号则有全部模块。视觉效果拉满代码逻辑也不复杂就是路由渲染时机要注意必须在路由 beforeEach 里判断路由是否已添加避免页面刷新时路由表被清空导致404。4.4 ECharts报表一行一行把逻辑讲清楚系统管理员的首页我放了四个图表月度用车趋势折线图、车辆类型占比饼图、费用构成柱状图、车辆使用率排名横向条形图。ECharts的关键是后端要把统计好的数据格式返回给前端。我写了一个 DashboardController用SQL聚合查询按月份统计申请数量返回[{moth:2025-04, count: 30}]格式前端把数据 map 成 ECharts 需要的{xAxis: [2025-04,...], series: [30,...]}。一开始我用错了格式图表一直不显示后来在浏览器Network里看了一下后端返回的JSON和ECharts要求的格式才明白必须数据格式对齐。这里的实战建议做图表先说清数据格式后端返回什么前端需要什么两端对齐再动手。如果自己写SQL聚合比较吃力可以在mapper里写原生SQL配合Select注解比用QueryWrapper硬拼容易得多。4.5 打包放进SpringBoot上线部署的常见路径本地开发跑通了最终要部署成一个jar包跑全站这也是很多公司实际生产的常见形态。做法是前端执行npm run build生成 dist 目录。把 dist 里的 static 文件夹和 index.html 放到SpringBoot的src/main/resources/static下。重打包启动后访问http://localhost:8080就能同时看到前端页面。与此同时后端API加一个/api前缀避免前端静态资源和API路径冲突。这里有个坑必须说明Vue Router如果启用了history模式刷新不在首页的页面会404。因为SpringBoot的静态资源处理找不到对应路径所有非API路径都指向了/需要额外配置路由fallback。由于这个绕来绕去我干脆用了createWebHashHistoryhash模式URL里会多一个#/配置简单、部署省心答辩时没人注意这件事自己也不容易出错。5. 部署与演示从本地跑通到交给答辩老师部署是很多同学的噩梦尤其数据库安装和初始化稍不注意就卡半天。下面按我自己的真实操作顺序来讲。5.1 数据库初始化MySQL 5.7 还是 8.0毕设环境里MySQL 5.7.44 是最稳的选择网上教程最多遇到问题基本都能搜到。MySQL 8.0的认证插件和连接驱动有差异如果引导里没配好SpringBoot启动会报Public Key Retrieval is not allowed新手容易卡住。我最后用的是MySQL 5.7原因就一点稳。下载安装时有几个注意事项Windows 10 上安装时选择 ZIP 解压版还是 MSI 安装版都可以关键是安装完成后要设置环境变量把MySQL的bin目录加到Path否则命令行执行mysql命令提示找不到命令。初始化时执行mysqld --initialize-insecure会自动生成一个无密码的root用户比--initialize生成随机密码友好。启动服务后用mysql -u root -p登录先改root密码再建库。执行ALTER USER rootlocalhost IDENTIFIED BY yourpassword;然后用source命令导入数据库脚本source /path/to/vehicle.sql;导入脚本时要注意SQL文件的字符集如果数据库默认是UTF8但SQL文件里没有CHARSETutf8mb4导入中文会变成乱码。我用的SQL文件头部加了SET NAMES utf8mb4;导入后数据展示正常。5.2 SpringBoot配置数据库连接和端口application.yml里的核心配置server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/vehicle_db?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai username: root password: yourpassword driver-class-name: com.mysql.cj.jdbc.Driver mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: logic-delete-field: deleted特别提醒serverTimezoneAsia/Shanghai这个参数不写的话日期时间字段会相差8小时或者直接报错。我当时踩了一次后端一切正常前端显示的时间总是比当前时间慢8小时查了半天发现是时区问题。5.3 启动顺序与常见启动报错部署时一定要按正确顺序启动数据库 → 后端 → 前端或直接访问打包后的前端页面。如果后端启动报错第一步看数据库是否已启动、账号密码是否正确、库是否存在这三个原因占了启动失败原因的80%。另外一个高频报错Error creating bean with name xxxMapper。原因是数据库里的表名和实体类名映射不上。MyBatis-Plus默认根据实体类名驼峰转下划线找表名如果你的表和实体类命名不一致需要在TableName(t_vehicle)里指定表名。我的项目全部用注解显式标注从根上断了这个坑。还有端口冲突启动后显示Port 8080 was already in use直接换端口或者在命令行执行netstat -ano | findstr 8080找到占用进程结束掉。5.4 Docker部署MySQL的注意事项如果你觉得安装本地MySQL麻烦也可以用Docker跑数据库但有几个坑必须先知道docker run时一定要映射端口通常用-p 3306:3306否则宿主机连接不上。需要设置MYSQL_ROOT_PASSWORD环境变量否则容器启动后可能没有密码或者无法登录。数据要持久化必须挂载数据卷否则容器一删数据全没了。命令示例docker run -d \ --name vehicle-mysql \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD123456 \ -e MYSQL_DATABASEvehicle_db \ -v /data/mysql:/var/lib/mysql \ mysql:5.7.44我第一次跑Docker MySQL失败是因为宿主机本地已经有一个MySQL占用了3306端口容器映射失败。解决办法是把本地MySQL停掉或者把容器映射端口改成3307:3306然后后端连接URL改成jdbc:mysql://localhost:3307/vehicle_db。这两种方法都能解决推荐用改映射端口的方式互不干扰。5.5 交付给老师的三种方式很多同学问项目源码怎么发给别人我把它扩展成三种交付方式方便你跟导师对接方式一源码工程包将后端SpringBoot工程和前端Vue工程分别打成zip附带数据库SQL脚本和部署文档。导师可以在自己的电脑上按文档复现。方式二可执行jar包前端打包后放进SpringBoot的static目录重新打包出一个jar导师电脑上只要配好MySQL执行java -jar vehicle-system.jar就能访问。方式三环境镜像把整个部署好的虚拟机做成OVA导出导师不用配环境直接开虚拟机就能跑。这方式最省事但文件体积大一般毕设用不上。我交付时选了方式一因为老师明确想看源码结构。我在部署文档里写了完整的环境版本清单JDK8、MySQL5.7、Node16、Maven3.6每一步都配了截图导师复现几乎没有障碍。6. 论文与答辩别让代码之外的东西拖后腿代码写完了只是第一步毕设占分比重更高的可能是论文质量和答辩表现。这块我有太多心得可以分享。6.1 论文结构怎么搭不用抄也能写出有逻辑的章节我最终用了标准的六章结构第1章 绪论写研究背景、国内外现状、研究意义。国内现状可以引用政府发布的公车管理相关文件国际现状写欧美企业的GPS与调度系统。第2章 相关技术介绍SpringBoot框架、Vue前端框架、MySQL数据库、Sa-Token权限框架。重点是写原理和选型理由。第3章 系统需求分析画用例图、数据流图、功能需求和非功能需求。第4章 系统设计总体架构图、功能模块设计、数据库设计ER图、表结构说明。第5章 系统实现按功能模块分别放页面截图、核心代码片段和逻辑说明。第6章 系统测试测试环境、功能测试用例表、测试结论。写论文最痛苦的是画图我之前都是手画后来学聪明了用ProcessOn在线画用例图和流程图ER图用Navicat直接导出又方便又专业。6.2 答辩评委最常问的问题结合我答辩时的经历把老师最爱问的问题整理在这张表里提前准备现场从容提问方向典型问题我的应答思路技术选型为什么用SpringBoot不用SSHSpringBoot简化配置、开箱即用适合快速迭代SSH配置繁琐、维护成本高当前企业主流已是SpringBoot权限设计多个角色权限重合怎么办RBAC中权限是独立的角色只是权限的集合多个角色可以配置同一权限通过角色菜单表做多对多关联项目难点项目里最大的难点是什么状态机流转和通知提醒比如申请审批通过后如何触发派车逻辑定时任务推送消息时如何避免重复通知优化方向系统还有哪些可以改进的地方接入Redis缓存热点数据、持续集成自动化部署、对接企业微信消息推送、统计分析引入大屏展示数据安全系统怎么保证信息安全登录接口做验证码校验、密码使用BCrypt加密存储、接口返回统一脱敏、操作日志记录关键行为部署情况系统部署在什么环境本地运行部署后端8080端口前端打包集成在SpringBoot静态资源目录数据库为MySQL5.7第3个项目难点是最值得认真准备的我的回答围绕申请、审批、派车、还车这个多步状态流转展开说明每个步骤怎么保证数据一致性比如审批通过后才能派车、派车后车辆状态才能变更等。这个回答让评委觉得业务逻辑不是想当然写的而是经过了设计。6.3 演示环节的操作顺序答辩演示不要一上来就乱点我建议按这个顺序走流程方便老师理解也方便你讲解登录页展示验证码和登录逻辑。以超管身份登录展示首页统计图表和整体菜单结构。进入用户管理演示新增一个员工账号。切换到员工账号提交一条用车申请。切换回车管员账号审批这条申请然后执行派车。查看车辆状态变化和统计数据更新。回到超管账号演示删除被审批的申请展示权限不足提示。这个流程走下来大约10分钟覆盖了系统的所有核心业务。我事先录了一个屏幕录像备用万一现场网络或环境出问题也不会傻眼。6.4 关于部署文档的写作建议部署文档看起来不起眼但它是给导师和评委的第一印象。我写部署文档时遵循一个原则假设读者是一名只有基础Java知识的大三学生每一步都要能复现。文档内容包括环境准备JDK8安装、Maven安装、Node16安装、MySQL5.7安装每个都有官网下载地址和安装截图。数据库初始化创建数据库、导入SQL脚本、修改root密码。后端启动用Idea导入后端工程、修改application.yml连接信息、运行主类。前端启动安装依赖npm install、启动开发服务器npm run serve。访问地址前端 http://localhost:8081后端 http://localhost:8080。常见问题端口冲突、数据库连接失败、前端依赖安装慢。文档写完后自己按步骤从头到尾走一遍如果能一次跑通说明文档合格。我实际走了三遍才稳定期间发现漏了两处细节一处是忘记写修改root密码的命令另一处是JDK版本没写清楚导致同学装了JDK17后项目编译报错。这两处修正后朋友们照着文档基本都能一次成功。最后分享一点我个人实操中的体会做完这个毕设我最大的收获不是背熟了SpringBoot和Vue的API而是学会了一条独立解决问题的完整路径遇到报错先确认环境版本再看数据库连接最后查业务代码和日志。这套排查逻辑放到任何项目里都通用。另外想专门提醒一句项目里所有的账号密码都不要写死在代码里虽然毕设没有安全评审但把数据库密码配置在application.yml并通过.gitignore排除提交是一个职业习惯。答辩时如果老师问到安全相关的问题你能回答出密码加密存储、接口权限校验、操作日志审计这几个点印象分会好很多。如果时间充裕可以在派车模块中进一步引入地理坐标概念演示在地图上展示车辆位置或者把静态报表升级为大屏数据可视化这些扩展方向都能成为论文的加分项。我当时因为时间不够没有做只保留了这个扩展点希望你们有机会补上。只要把主干流程做扎实配置好部署文档答辩时从容演示这套毕设就已经足够优秀了。
返回列表