我当年做毕设的时候,最头疼的就是找个既不太简单又能讲清楚前后端联动、还能直接跑起来的项目。市面上能搜到的管理系统要么老掉牙还用JSP,要么就散得不成样子,接口、SQL、文档全靠自己脑补。这次拿到一份“SpringBoot+Vue 学生干部管理系统”,反而让我眼前一亮——这个选题特别好,它不是一个通用的后台管理模板,而是真真正正有人在用的业务场景:班级干部、学生组织、考核评选、活动记录,这套数据模型稍加改造就能移植到很多高校管理系统里。如果你正在筹备Java Web方向的毕业设计,或者想找一个前后端分离、开发完整、逻辑清晰的企业级入门项目,这篇内容值得你从头到尾看完。
下面我按做项目的人最关心的顺序拆解:先讲这套系统为什么这么设计,再讲前后端怎么落地、SQL脚本怎么写得漂亮、接口文档怎么组织,最后把跑通整个项目的那些坑一次性说完。
1. 项目整体架构:为什么选SpringBoot+Vue这套组合
1.1 技术选型背后的真实考量
学生干部管理系统这个选题,最大的特点是业务明确、表结构天然清晰、权限场景典型。它不是简单的增删改查堆砌,而是真的能讲出“这个系统有什么业务价值”的项目。选SpringBoot+Vue做这套系统,在毕业设计里几乎是性价比天花板。
后端用SpringBoot,本质上是图它三件事:第一,内嵌Tomcat,不用单独部署容器,省掉一大堆环境配置的麻烦;第二,Spring生态的整合能力极强,MyBatis、MyBatis-Plus、Spring Security、JWT这些轮子装上就能用;第三,SpringBoot提供的注解式开发让代码量大幅收敛,你写一个Controller只需要标注@RestController,框架自动处理JSON序列化、请求映射这些事情。
前端用Vue,核心优势同样清晰:组件化让页面拆分成多个独立模块,你不用在HTML里堆几万行代码;Vue响应式数据绑定让表格刷新、状态联动变得极其自然;再加上Element UI这种现成的组件库,下拉框、日期选择器、分页表格、弹窗确认这些界面,几乎不用写一行CSS就能做出来。
但这里要提醒一个容易踩的坑:SpringBoot和Vue本身没有“自动连接”这回事。两者通过HTTP接口通信,前端页面发起HTTP请求,后端返回JSON数据,前端再渲染到界面。这对于毕设答辩来说反而是好事——你可以在答辩时明确说出来“系统采用前后端分离架构,前端使用Nginx或Node静态服务,后端提供RESTful API”,这句话本身就是得分点。
1.2 系统核心功能模块划分
学生干部管理系统不是泛泛的“信息管理”,它的业务域非常明确。按高校学生工作的实际流程,这套系统至少应该覆盖这五个模块:
- 干部信息管理:学生干部的基本档案,包括姓名、学号、班级、职务、任职时间、联系方式、政治面貌,人员多时还要支持按班级和职务筛选、Excel导入导出。
- 班级干部评选:发布评选活动,学生报名或班级推荐,辅导员或管理员审核,形成任期记录。评选状态必须清晰:待报名、报名中、评选审核、公示完成。
- 考核评分管理:按学期或月度对干部进行考核,考核维度包括工作态度、活动参与度、任务完成质量和同学反馈。支持多级指标打分并自动汇总。
- 活动记录管理:学生干部组织的活动或参与的活动,包含活动名称、时间、地点、参与人数、活动照片或总结。这个模块和前两个有天然关联:办活动计入考核、参加活动也能作为评选加分。
- 数据统计看板:用图表展示干部总数、部门分布、考核优秀率、活动数量趋势。这一块很能撑答辩场面,也直观展示数据库聚合查询的能力。
这三个字值得刻在脑门上:角色化。老师、辅导员、学生干事、学生干部四类角色看到的内容完全不同。学生干部登录后只能看到自己信息和自己参与的评选;辅导员能审核自己管辖班级的报名、能对干部打分;管理员管理所有基础数据和用户账号。这种按角色区分数据权限的模型,比单纯做个“管理员后台”含金量高出一大截。
2. 后端SpringBoot核心实现详解
2.1 项目初始化与分层设计
后端工程建议直接用Spring Initializr创建,注意几个关键依赖:Spring Web、MyBatis Framework、MySQL Driver、Lombok。如果你想让代码更简洁,加一个MyBatis-Plus的老版本依赖也可以,它在BaseMapper里预置了通用CRUD方法,写service层会舒服很多。
项目包结构我建议按功能模块分,而不是按技术层分。技术层分包(controller、service、mapper各建一个包把全部文件塞进去)在小项目里能跑,但只要哪怕多一个模块,改动起来就会非常痛苦。按模块分包更清晰:
com.student.cadre ├── controller # 接口层 ├── service # 业务逻辑层 ├── mapper # 数据访问层 ├── entity # 实体类 ├── dto # 前端交互对象 ├── config # 全局配置 ├── common # 通用工具、统一返回体、异常处理 └── security # 鉴权相关三层的核心逻辑是从Controller到Service到Mapper逐层调用。Controller只负责接收参数、校验参数格式、调用Service、返回结果给前端,不写任何业务代码;Service处理所有业务规则,比如判断当前用户是否有权限审核某个报名;Mapper只负责和数据库交互,一个方法对应一条SQL或MyBatis-Plus提供的内置查询。这条链路捋顺了,整个项目不管后面加多少功能都不会乱。
2.2 统一返回体与全局异常处理
前后端分离项目里,最忌讳的就是每个接口返回的数据格式还各不相同。前端拿到A接口返回{code: 200, data: [...]},B接口又返回{success: true, result: [...]},联调的时候光适配格式就够喝一壶。
统一返回体是我在项目里第一个落地的类。定义一个Result<T>类,包含三个字段:code表示业务状态码、message表示提示信息、data表示载荷数据。所有接口的Controller直接返回Result<T>,由框架自动转化为JSON。
提示:code不等于HTTP状态码。HTTP状态码是200表示请求成功,业务code是2000同样表示业务成功,两者各自独立。这样即使前端HTTP请求成功,也能根据业务code判断后端逻辑是否处理成功,比如登录接口返回业务码4001表示账号不存在。
全局异常处理也不能省。如果不做,代码里每遇到一个错误都要写try-catch,Controller会变得奇丑无比。我用@RestControllerAdvice统一拦截异常,再配一个自定义的BusinessException,业务代码遇到特殊情况直接throw new BusinessException("该班级已有评选活动在进行中"),异常处理器捕获后自动转成统一返回体返回到前端。
2.3 登录鉴权与JWT接入
学生干部管理系统这个场景特别适合用JWT。传统的Session方案在前后端分离架构下问题很明显:后端生成Session ID存到服务器内存,前端要用Cookie携带,这个过程很容易遇到跨域Cookie被拦截的情况。JWT的逻辑完全不同:用户登录成功后,后端生成一个带签名的JSON Web Token(其中包含了用户ID、角色、过期时间),前端把它存到localStorage,每次请求时放在请求头Authorization里带给后端,后端验证签名合法就直接放行。
JWT接入要做三件事:第一,登录接口生成Token;第二,写一个拦截器或Spring Security过滤器,拦截所有请求,对于白名单路径(比如登录、验证码)直接放行,其他路径必须校验Token;第三,从Token中解析出当前登录用户信息,放到ThreadLocal或上下文中,后面业务逻辑如果需要知道当前登录人是谁,直接从上下文取。
学生干部系统里有一个场景能把这个设计讲得很出彩:学生干部提交离职申请,后端服务拿到离职审批人ID时,需要校验“你能审批这个申请吗?”,而这个ID就来源于解析Token后拿到的当前用户信息。
2.4 核心业务CRUD接口实现思路
拿“考核评分管理”来说,这个模块涉及的数据表可能有三张:考核指标表、考核任务表、考核得分明细表。设计接口时不要只围绕单表做增删改查,要往业务方向想一步:
- 创建考核任务:管理员选择考核学期、填写考核指标和权重,后端一次性插入考核任务主表和得分明细表。
- 提交考核打分:辅导员给所辖班级的干部逐项打分,后端要在Service层判断当前辅导员是否有权限打分、打分范围是否合法(比如分数不能超过该项满分)。
- 查看考核结果:按干部ID聚合查询得分明细,算出总分和等级(优秀、良好、一般、待改进),这个查询要用SQL里的
SUM和CASE WHEN,直接展示聚合查询能力。 - 考核结果导出:用EasyExcel或POI生成Excel文件返回给前端下载,答辩时现场演示导出再配合表格数据,效果非常直观。
接口返回的还是一个Result<T>包装的JSON。但数据量大时建议加一个分页参数pageNum和pageSize,用MyBatis-Plus的Page对象做分页查询,前端配合表格分页组件,用户体验会好很多。
3. 前端Vue实现与前后端对接
3.1 前端项目环境与目录结构
动手写前端之前,先把Node环境和脚手架准备好。建议用Vue CLI或者Vite创建一个Vue 3项目,然后依次引入Vue Router、Pinia(或Vuex)、Axios、Element Plus。
前端项目目录也不要乱放,按模块组织,和后端接口对应:
src ├── api │ ├── cadre.js # 干部信息模块接口 │ ├── assessment.js # 考核模块接口 │ └── login.js # 登录模块接口 ├── router │ └── index.js # 路由配置 ├── store # 状态管理 ├── views # 页面组件 │ ├── Login.vue │ ├── cadre/CadreList.vue │ ├── assessment/AssessmentTask.vue │ └── dashboard/Dashboard.vue ├── components # 公共组件 ├── utils │ ├── request.js # Axios封装 │ └── auth.js # Token存储与读取看到api目录里每个模块一个文件的老规矩了吧,前端每个接口函数和后端Controller的方法一一对应。这样项目里多了几十个接口,前端代码也不会乱成一锅粥。
3.2 Axios统一封装与请求拦截
前后端对接的桥梁就是Axios。我建议封装一个request.js文件,统一配置基础路径和请求头,这样以后接口地址变了或者要加默认参数,只需要改一处。
Axios拦截器有两个方向:请求拦截器和响应拦截器。请求拦截器主要做一件事:从localStorage里取Token,存在就拼到请求头里。响应拦截器做的事更多一些——后端返回业务码2000,直接返回response.data.data给业务代码;后端返回业务码4001表示未登录或Token过期,直接前端跳转到登录页面;后端网络错误(HTTP 5xx),弹出一个统一的消息提示。核心思想是:把公共逻辑挡在业务代码之前,各页面组件里只关心成功和业务失败的两种情况,不重复处理Token过期、网络错误。
提示:在请求拦截器里设置
timeout为10秒,并加一个Loading开关。否则弱网测试时一个请求挂在那里,前端页面毫无反馈,用户会以为系统坏了。
3.3 路由配置与权限控制
前端路由按功能模块分:登录页、首页、干部信息管理、评选管理、考核评分、活动记录、数据看板。每个页面组件都对应的一个路由配置,使用component: () => import(...)懒加载方式,页面多时能减少首屏加载体积。
权限控制要结合后端角色来做。前端路由需要加一个meta字段,比如roles: ['ADMIN', 'TEACHER'],表示哪些角色能访问页面。配合路由守卫,在router.beforeEach里判断当前登录用户的角色是否在路由允许的列表里,不在就重定向到401页面。同时,前端菜单也要按角色动态展示:管理员看全部菜单,辅导员只看自己相关的评审菜单,学生干部看自己的信息和评分结果。这一步虽然只是“前端控制”,更多是用户体验层面的隐藏,真正的硬权限校验必须放在后端Service层。
3.4 页面组件化与关键页面实战
页面开发的核心思路是“一个页面一个视图组件,一个功能区一个公共组件”。拿干部信息列表页举例,这个页面至少由三个区域组成:
- 顶部是搜索筛选区:班级下拉框、职务下拉框、关键字输入框、查询按钮、重置按钮;
- 中间是工具按钮区:新增干部、批量导入、批量导出、删除选中;
- 主体是数据表格:分页表格展示干部信息,右侧操作列放“编辑”“详情”“考核记录”等按钮。
表格数据加载的流程是:组件mounted时调用getCadreList(pageNum, pageSize)接口,拿到列表数据和总数传给分页组件,分页组件current-change事件触发时重新调用接口。删除操作要弹确认框,Element Plus的ElMessageBox.confirm很好用,确认后调删除接口再刷新列表。
3.5 数据看板与图表可视化
数据看板用的图表库是ECharts。在我的经验里,你只需要在Vue 3里引入echarts,然后用ref绑定一个DOM容器,在mounted里初始化图表实例,设置option即可。常用图表场景包括:
- 各部门干部人数柱状图:后端返回部门名称和对应人数的二维数组,前端循环加工成ECharts的
xAxis和series。 - 考核等级占比饼图:后端用SQL统计合格、良好、优秀各多少人,一个
pie配置直接出效果。 - 组织活动数量趋势折线图:按月份统计活动数量,后端返回月份列表和数量列表,一条折线展示增长趋势。
图表页在ECharts里要加一条自适应处理:监听窗口resize事件,调用chart.resize()。否则浏览器拉大缩小时图表不会同步缩放,答辩现场演示如果正好碰上这个bug,会很影响观感。
4. SQL脚本设计与初始数据准备
4.1 数据表结构规划
SQL脚本是整套系统的地基,同样是答辩时容易被问到的点。学生干部管理系统的核心表大致有这么几张:
| 表名 | 功能说明 | 关键字段 |
|---|---|---|
| sys_user | 系统用户表 | user_id、username、password、role_id、real_name、status |
| sys_role | 角色表 | role_id、role_name、role_code |
| cadre_info | 干部信息表 | cadre_id、user_id、class_name、position、job_title、phone、political_status |
| election_activity | 评选活动表 | election_id、title、class_name、start_date、end_date、status |
| election_apply | 评选报名表 | apply_id、election_id、cadre_id、apply_reason、audit_status |
| assessment_task | 考核任务表 | task_id、title、semester、start_time、end_time |
| assessment_score | 考核得分表 | score_id、task_id、cadre_id、indicator_id、score、auditor_id |
| activity_record | 活动记录表 | activity_id、name、location、start_time、participant_count、summary、creator_id |
设计表时有一些通用经验可以直接抄:每个表都有主键id或xxx_id并自增;create_time和update_time统一用datetime类型;状态字段用tinyint或varchar加注释说明(0待审核、1通过、2驳回);文本字段(活动总结、报名理由)用text而非varchar,避免超长报错。
4.2 外键与关联字段设计
表关联字段是初学者最容易被问破防的地方。我建议遵循三条原则:能用逻辑外键就不用物理外键,使用user_id或cadre_id做逻辑关联;关联字段名要带上表名前缀;查询时用JOIN关联,而不是在代码里循环查库。
具体来说,报名表的cadre_id要和干部信息表的cadre_id对应,你不需要在数据库层面声明FOREIGN KEY,只要保证插入的数据是这个字段里存在的值,业务就能正常运转。答辩时如果老师问为什么不加外键,你可以从容回答:外键约束会让表的耦合度变高,插入删除数据时需要层层校验,对毕设场景的数据一致性来说逻辑控制已经足够,而且后期清理测试数据更简单。
4.3 初始化数据与测试数据
SQL脚本里除了建表语句,还应该预置一份初始数据。没有数据的空系统,前端页面空空荡荡,打不开任何页面,答辩直接冷场。初始数据至少包含:
- 默认管理员账号
admin,密码建议用BCrypt加密后的值写进脚本; - 两个辅导员账号、若干学生账号和对应的干部档案;
- 一个已结束的评选活动和3条报名审核数据、一个进行中的考核任务和几组模拟得分。
测试数据专门用来让考核结果图表和看板页面有东西可渲染。比如活动记录表里,可以从2024年1月到6月每月写两条活动,活动趋势图直接呈现出一条有高低的折线,画面感比空数据强太多了。
4.4 SQL内存中执行顺序与导入
MySQL导入SQL脚本要特别注意执行顺序:先创建数据库并指定字符集utf8mb4,再切到该库(USE database_name),然后建表,最后插入数据。
有一点容易翻车:考试系统、公司的服务器MySQL版本可能不同,建议脚本头写清楚MySQL版本要求,同时避免使用太新的语法(如CHECK约束、WITH递归查询)。在一个专门的SQL注释块里写明导入步骤,比如“使用Navicat运行整个脚本”或者“命令行执行source /path/to/init.sql”,对使用者极友好。
5. 接口文档组织与设计规范
5.1 为什么接口文档要和项目一起交付
很多人觉得反正前端和后端都是自己写的,接口文档有没有无所谓。这个想法在毕业设计场景里大错特错。接口文档是三合一项目包里的核心交付物,意义至少有三个方面:第一,答辩老师在检查项目时会翻接口文档,一份规范文档体现了你的工程素养;第二,如果项目后期被学弟学妹或其他人接手,接口文档是唯一能让接手人快速了解系统的图鉴;第三,接口文档是“前后端分离”这个架构概念最直观的证明——逻辑上的前置条件是可分离的,因为两者通过文档约定的接口通信。
5.2 接口文档应该包含的核心要素
一份合格的接口文档,每个接口都要包含以下信息:请求URL、请求方法(GET/POST/PUT/DELETE)、请求参数表格(参数名、类型、是否必填、说明)、返回响应示例(JSON)、可能出现的错误码说明。
拿“查询干部列表”举例,文档里要写明:请求GET /api/cadre/list?pageNum=1&pageSize=10,参数表里注明pageNum默认1、pageSize默认10;返回示例是一段JSON,包含total和records;错误码表里说明4001未登录、5000服务器内部错误。整个文档用Markdown或者在线文档工具现编排合并即可。
接口文档顺序建议按模块排列:登录认证模块、干部管理模块、评选管理模块、考核管理模块、活动模块、统计模块。每个模块下的接口按CRUD顺序排:新增、列表、详情、修改、删除。这样从头到尾读一遍文档,系统的全部功能就串起来了。
5.3 接口文档的编写工具与效率技巧
手写接口文档是最痛苦的,我建议用Swagger/OpenAPI这种自动化方案:后端引入springdoc-openapi依赖,在每个Controller方法上加几个描述注解(@Tag、@Operation、@Parameter),启动项目后访问/swagger-ui.html就能看到一个交互式API文档页面,每个接口可以直接在页面上点击测试。这对答辩来说非常加分,老师可以现场点击接口调用,界面比“甩一份静态文档”好看得多。
如果你不想依赖Swagger,也有更轻量的做法:把接口清单整理成一份Markdown表格,放在项目根目录的docs/接口文档.md里,维护起来也直观。两种方式建议并行:Swagger交互文档用于开发和演示,Markdown静态文档用于项目交付。
5.4 一套清晰的口径:统一URL命名与状态码
接口URL的命名要统一。有两条规范我执行了很多个项目,效果很好:资源名用复数名词(/api/cadres而不是/api/getCadreList);用HTTP方法表达动作含义(GET查、POST新增、PUT改、DELETE删)。这样做的好处是接口数量增多后,URL看起来非常规整,即“预算”透了每个路径的意义。
状态码定义也要在一开始就定好,别后面随手乱加。我常用的编码库如下:
| 状态码 | 含义 |
|---|---|
| 2000 | 操作成功 |
| 4001 | 未登录或Token过期 |
| 4002 | 权限不足 |
| 4003 | 参数校验失败 |
| 4004 | 业务逻辑错误(比如重复报名) |
| 5000 | 系统内部异常 |
6. 项目联调、部署与常见问题排查
6.1 本地开发联调完整流程
跑通一个前后端分离项目的顺序很重要,别一开始就又起前端又起后端,出问题时无从排查。我建议严格按以下顺序来:
- 先用Navicat或命令行执行SQL脚本,确认数据库表全部建立、初始数据成功插入。
- 启动后端SpringBoot项目,用Swagger或Postman先测试第一个登录接口,拿到Token。
- Token拿到后用Postman测带鉴权的“查询干部列表”接口,确保后端接口全部可用。
- 启动前端Vue项目(默认端口通常是5173或8080),浏览器打开登录页,用初始
admin账号登录。 - 登录成功后看干部列表页是否展示数据,如果空白,按F12打开浏览器控制台看请求路径和状态码,重点排查跨域和后端地址问题。
6.2 跨域问题的经典解法
前后端联调第一个大坑就是跨域。前端页面在localhost:5173,后端接口在localhost:8080,浏览器默认禁止跨源读取资源,于是前端的请求被拦下。解决跨域有两种标准姿势:
- 方式一:后端加
@CrossOrigin注解或全局CORS配置,允许指定源头(allowedOriginPatterns)访问。 - 方式二:前端在Vite或Vue CLI配置请求代理,把
/api前缀代理到http://localhost:8080,对于浏览器来说请求发的是同源地址,不触发跨域。
我个人的偏好是开发环境用方式二(代理),生产环境部署到Nginx后也配置反向代理,避免把后端端口暴露给外部。这样无论开发还是部署,前端请求的都是同一个地址,只是这个地址内部做了转发。
6.3 高频报错与排查速查表
做成一个表,直接收藏这套:
| 现象 | 可能原因 | 排查与解决 |
|---|---|---|
| 前端请求接口一直转圈 | 后端没启动、后端端口不一致、接口路径写错 | 先看后端控制台是否打印日志;再看前端请求URL,用Postman直接调同样URL测试 |
| 报错“Network Error” | 跨域被拦截,或后端服务崩溃 | F12控制台看具体报错,按上一步跨域方案处理 |
| 登录接口返回401 | Token过期或未带Token | 查看请求头Authorization是否存在,重新登录拿新Token |
| 页面能打开但数据全是空的 | 后端返回的数据字段名和前端渲染字段不一致 | 打印后端返回JSON和前端里实体字段,逐字段对比 |
| 导入SQL脚本时报错 | 脚本字符集不一致、表已存在、外键没检查 | 检查建表语句是否用了DROP TABLE IF EXISTS;确认数据库字符集utf8mb4,并先执行USE database |
| 前端启动提示端口被占用 | 之前启动过的进程没关 | 关闭占用进程;或修改vite.config.js里server.port |
| POST请求跨域失败,GET成功 | CORS配置里没允许对应方法或请求头 | 后端CORS配置追加allowedMethods(POST, GET, PUT, DELETE, OPTIONS),并允许Authorization请求头 |
6.4 部署上线经验
毕设通常不需要真正部署到云服务器,但只要做的项目能打包上线,和只会在本地跑是有本质区别的。后端打成Jar包:在pom.xml中配置打包插件,执行mvn clean package -DskipTests,生成target/*.jar,然后用java -jar xxx.jar运行,可加--server.port=8080指定端口。
前端打包:执行npm run build,生成dist静态文件目录。部署时让Nginx托管dist目录,并配置反向代理代理/api到后端8080端口。这里有两个细节:前端路由如果是history模式,Nginx需要配置try_files $uri $uri/ /index.html,否则刷新子路由会404;打包后的静态文件引用的接口地址不是localhost,而是Nginx的域名地址,打包前要确认环境变量。
6.5 二次开发与功能扩展指引
学生干部管理系统做完基础功能,如果时间充裕,我强烈建议往这两个方向扩展,会让系统档次明显上升:
- Excel导入导出增强:干部名单用Excel批量导入,考核结果和评选名单一键导出。用到EasyExcel库,核心代码量很小,但演示效果很出彩。
- 通知与待办提醒:用WebSocket或简单的拉取接口实现消息中心,当选评活动开始、考核发布后,相关人员登录系统能看到待办数量提醒。能给系统增加“实时性”的说服力。
再比如把密码改为BCrypt加密、增加登录验证码(用Hutool的图形验证码)、加入操作日志记录表——这三个扩展在系统安全维度上会让答辩老师挑不出太多毛病。
7. 个人实操体会与收尾建议
这一套项目流程走下来,我最大的体会是:毕业设计不是一个“编代码”的工程,而是一个“组合工程”的管理问题。能顺利答辩的项目,往往不是代码写得多花哨,而是它的业务逻辑闭合、数据能对上、页面能操作、文档能看懂。学生干部管理系统恰好能把这几项全部覆盖。
给你一个在实操层面非常实用的建议:拿到项目包以后,第一步不要急着打开IDE看代码,而是先执行SQL脚本,再用Swagger点击接口列表,一个一个把数据弄明白。数据通了,再打开前端页面,这样你很快就能在脑子里面形成一张“数据流地图”:数据库表对应后端接口,后端接口对应前端页面,前端页面又反过来操作数据库——这条链路就是你在答辩时用来回答几乎所有问题的底气。
如果时间允许,尽量把系统里的测试数据做得丰满一点:20个学生干部、3次评选活动、3个月的活动记录、每个干部至少一次考核成绩。数据一多,分页、搜索、统计图表、导出这些功能才真正有了被展示的机会。一个数据空空的系统,哪怕代码再完整,看起来也像没做完。
最后分享一个小技巧:把你的SQL脚本、接口文档、项目运行说明这三个文件放在项目根目录下一个叫docs的文件夹里,并在README里写清楚每一步启动步骤。等到答辩的时候你会发现,这一份README节省掉的口舌,远比再多写十个接口大得多。项目本身就是时间的沉淀,越规范越从容。