毕业设计里如果让我选一个“性价比最高”的项目类型,非遗文化宣传平台绝对排得上号。它不像算法类题目那样容易卡在理论上,也不像纯管理系统那样显得单薄,业务场景恰好落在“内容展示 + 后台管理”这个最经典、最容易讲清楚的组合上。/SpringBoot做后端,/Vue做前端,从数据库设计到接口开发,再到部署上线,整条链路都能覆盖到。这篇文章就是我当时带项目时的完整复盘,包含需求拆解思路、技术选型理由、核心模块实现和那些网上教程里不会明说的坑,给打算做同类系统的同学一个可直接参照的工程底线。
1. 这个题目为什么值得做:需求拆解比写代码更重要
1.1 选题的“稳妥值”:平台类项目为何性价比高
很多人选毕设题目时会陷入两个极端:要么选得太难,比如“基于深度学习的非遗图像识别系统”,结果模型训练那关就把人劝退;要么选得太简单,比如“非遗商品信息管理系统”,评委一句话就能问住——“你这个和课设有什么区别?”
非遗文化宣传平台恰好落在中间。它的业务名词接地气,非遗项目、传承人、资讯动态、展品展示这些概念,评委不需要你解释就能听懂。同时它又不是单纯的增删改查,还包含了前台展示、用户互动、内容发布、分类导航、搜索推荐这些真实平台才有的功能维度。论文好写、演示好看、技术选型有发挥空间,这是平台类项目最核心的优势。
1.2 面向谁、解决什么:游客、注册用户、管理员三端功能清单
我把需求拆成三个角色来梳理,后端的接口设计、前端的页面划分都围绕这三端展开。
- 游客:不用登录就能浏览非遗项目列表、按分类筛选、查看项目详情、阅读非遗资讯、观看传承人介绍。这一端解决的是“宣传”二字,核心是内容展示和传播。
- 注册用户:可以收藏感兴趣的非遗项目、发表评论、参与互动。这一端解决的是“平台”二字,让访问者从被动浏览变成主动参与。
- 管理员:负责非遗项目、传承人、资讯、轮播图的发布与维护,同时管理用户和评论。这一端解决的是内容的可持续运营,没有后台管理的宣传平台就是死站。
功能清单定下来之后,我再补上搜索和分类导航这两个容易被忽略的点。搜索不是简单的按名称查询,要支持按地区、按级别(世界级/国家级/省级/市级)组合筛选;分类导航则要求分类表支持层级关系,比如“传统技艺”下面还能继续分“陶瓷烧制技艺”“刺绣技艺”等子类。
1.3 需求边界:哪些功能坚决不做
这里要画一条线。很多学生做毕设容易把需求无限扩大,今天想加个在线视频点播,明天想加个VR展厅,后天又想加个预约报名系统。我的建议是:凡是需要接入第三方支付、即时通讯、高并发直播流的技术,全部砍掉。不是说这些不好,而是毕设的核心目标是证明你具备完整的软件工程能力,而不是打造一个商业产品。
我在最初设计这个系统时,主动砍掉了在线预约功能,因为预约涉及场地、时间、人员三个维度的状态机管理,复杂度会明显失控。保留“展示 + 搜索 + 互动 + 后台管理”四件事,已经是能支撑一篇合格论文的最小完整系统。
2. 技术选型:SpringBoot之外,还要把这几件事提前定下来
2.1 后端组合:SpringBoot 2.7 + MyBatis-Plus 的合理性
后端我推荐用 SpringBoot 2.7.x,而不是 3.x。原因很现实:很多学校的实验室和服务器还停留在 JDK 1.8,SpringBoot 3.x 强制要求 JDK 17,环境不匹配会导致项目在答辩演示现场直接跑不起来。SpringBoot 2.7 是 2.x 系列的最终版本,既能兼容 JDK 8,又有完善的生态资料,遇到问题搜解决方案最容易。
持久层选 MyBatis-Plus 而不是原生 MyBatis,省下的工作量是肉眼可见的。单表 CRUD 不用写 XML,内置的分页插件可以直接用,LambdaQueryWrapper 让条件构造变得很直观。这个选择不是偷懒,而是把人力从重复劳动中释放出来,放到业务逻辑上。再配上 MySQL 8.0,一套很标准的组合。
2.2 前端选型:为什么要走前后端分离
前端如果还沿用老一套的 Thymeleaf 模板渲染,代码写起来确实省事,但有两个问题:一是前后端代码耦合在同一个工程里,论文里“系统设计”部分很难画清楚架构;二是现在企业里前后端分离已经是主流,面试官看到你用模板渲染,会觉得你的技术视野停留在两三年前。
所以前端建议用 Vue 2 + Element UI + Axios,单独一个工程。如果你对 Vue 3 和 Vite 熟悉,用 Vue 3 也可以,但如果时间紧张,Vue 2 的教程和踩坑记录最丰富,Element UI 的表格、表单、弹窗、上传组件开箱即用,特别适合后台管理页面。我的经验是:页面交互的亮点放在前端,数据逻辑的严谨性放在后端,这样才能发挥分离架构的价值。
Node 版本建议用 14 到 16。太新的 Node 版本在装依赖时可能会报 OpenSSL 错误,旧项目还需要额外加NODE_OPTIONS=--openssl-legacy-provider才能跑起来,没必要折磨自己。
2.3 鉴权方案:JWT 而不是 Session
前后端分离之后,Session 方案会遇到一个天然问题:跨域请求默认不带 Cookie,即使配置了withCredentials,在本地开发和多域名部署时依然很麻烦。我用的是 JWT 方案,登录成功后后端签发一个带过期时间的 Token,前端存到localStorage,之后每次请求在请求头里携带,后端通过拦截器校验。
JWT 的好处是无状态,服务器不需要保存会话信息,后面前端要扩展小程序端时,同一套接口直接复用。对毕设来说还有一个隐藏优势:论文里“系统安全设计”章节有足够的素材可以写,从 Token 签发、过期策略、拦截器校验到加密算法选择,每一项都能展开讲。
2.4 几个“不加分”的技术,别往里塞
有同学喜欢往项目里堆技术,Redis 缓存、RabbitMQ 消息队列、ElasticSearch 搜索引擎全给配上。单个挑出来都有道理,但加在一个日访问量可能不到一百的宣传平台上,就变成了画蛇添足。评委一问“你这个场景下 Redis 缓存了什么数据?缓存失效怎么处理?”如果答不上来,反而暴露了知识短板。
我的做法是:在论文“系统展望”部分写清楚“后续可引入 Redis 缓存热门项目详情、用 ElasticSearch 替代数据库模糊查询”,但实际代码不实现。这样既体现了前瞻性,又不会在演示时给自己挖坑。技术和需求的匹配度,比技术数量的堆砌重要得多。
3. 数据库设计:非遗数据建模的两条主线与六张核心表
3.1 领域表:非遗项目、传承人、资讯的分工
数据库设计是系统设计的核心。非遗宣传平台的数据模型可以归纳成两条主线:一条是内容主线,承载非遗项目、传承人、资讯动态;另一条是用户行为主线,承载用户、收藏、评论。
先看内容主线。非遗项目表是最核心的表,字段不能只图方便。cover存封面图路径、level存项目级别、region存地域、intro存一句话简介、content存完整图文介绍、view_count存浏览量。传承人表和项目表之间是外键关联关系,一个项目可以有多位传承人。资讯表单独一张,和项目表解耦,因为资讯的负责人、发布时间和发布状态都有独立的生命周期管理需求。
3.2 用户行为表:评论、收藏、浏览量的落法
用户在平台上的行为主要有三个:收藏、评论和浏览。收藏表favorite结构很简单,就是user_id + project_id + create_time,唯一索引保证同一个用户不会重复收藏同一项目。评论表要注意的是target_type的设计,一个字段区分评论对象是项目还是资讯,避免为每一种评论对象建一张表。
浏览量我直接做成project表上的一个整型字段,每次访问详情接口时view_count + 1。对毕设规模来说这个方案足够可靠,不需要单独建浏览记录表。如果未来要分析用户行为路径,再拆独立日志表也不迟。
3.3 分类表:parent_id 不只是省一张表
分类表采用parent_id自关联设计,一级分类的parent_id为 0,二级分类指向一级分类的 ID。这个设计允许无限层级扩展,而且代码实现不复杂。前端展示时用递归组件渲染成树形菜单,后端返回时一次性查出所有分类,在 Java 内存里组装成树形结构返回即可。
这里有同学会问,为什么不直接枚举常量?非遗分类和新闻分类本质上都是业务主数据,管理员在后台需要能增删改,写死在枚举里就丧失灵活性了。分类表是数据建模里投入产出比最高的设计之一,值得单独写一小节。
3.4 关键建表语句示例
这里给出两张核心表的建表语句。为了控制篇幅,省略了次要字段的注释,实际做建议把所有中文字段注释都写全。
CREATE TABLE `t_project` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `name` varchar(100) NOT NULL COMMENT '项目名称', `category_id` bigint(20) DEFAULT NULL COMMENT '分类ID', `level` varchar(20) DEFAULT NULL COMMENT '级别:世界级/国家级/省级/市级', `region` varchar(100) DEFAULT NULL COMMENT '所属地区', `cover` varchar(255) DEFAULT NULL COMMENT '封面图路径', `intro` varchar(500) DEFAULT NULL COMMENT '项目简介', `content` text COMMENT '项目详细介绍', `view_count` int(11) DEFAULT '0' COMMENT '浏览量', `status` tinyint(4) DEFAULT '1' COMMENT '状态:1上架 0下架', `create_time` datetime DEFAULT NULL COMMENT '创建时间', `update_time` datetime DEFAULT NULL COMMENT '更新时间', PRIMARY KEY (`id`), KEY `idx_category_id` (`category_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='非遗项目表'; CREATE TABLE `t_user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `username` varchar(50) NOT NULL COMMENT '用户名', `password` varchar(100) NOT NULL COMMENT '加密后的密码', `nickname` varchar(50) DEFAULT NULL COMMENT '昵称', `avatar` varchar(255) DEFAULT NULL COMMENT '头像', `role` tinyint(4) DEFAULT '0' COMMENT '角色:0普通用户 1管理员', `create_time` datetime DEFAULT NULL COMMENT '注册时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_username` (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';数据表统一加create_time和update_time字段,列表接口按创建时间倒序排序,这在后台管理里是刚需。另外所有表名加t_前缀,在 MySQL 里避免和保留字冲突,搜索排查时也容易区分业务表。
4. 后端关键逻辑落地:统一返回、鉴权、上传与搜索
4.1 统一响应体与全局异常:后端接口的“门面”
后端接口如果每个方法都返回不同类型的结构,前端 Axios 封装会写得很痛苦。我建议一上来就定义统一返回体,这个习惯不仅在毕设里有价值,在公司项目里也是必须的。
public class Result<T> { private Integer code; private String message; private T data; public static <T> Result<T> ok(T data) { Result<T> r = new Result<>(); r.code = 200; r.message = "success"; r.data = data; return r; } public static <T> Result<T> error(String message) { Result<T> r = new Result<>(); r.code = 500; r.message = message; return r; } }配合@RestControllerAdvice做全局异常处理,业务代码里的异常只管往上抛,由统一入口捕获并转换成 Result 返回。这样前端处理错误只用看code,不用关心异常堆栈。
4.2 JWT 签发与拦截器校验
JWT 的签发逻辑放在登录接口里。使用 jjwt 库,密钥先写死在配置文件中,注释标明生产环境应从环境变量读取。签发时把用户 ID 和用户名放进 Token,有效期设置成 7 天。
String token = Jwts.builder() .setSubject(String.valueOf(user.getId())) .claim("username", user.getUsername()) .setExpiration(new Date(System.currentTimeMillis() + 7 * 24 * 3600 * 1000)) .signWith(SignatureAlgorithm.HS256, secretKey) .compact();拦截器负责校验 Token。自定义一个AuthInterceptor,实现HandlerInterceptor接口,在preHandle中从请求头取Authorization,解析失败直接返回 401 结果,不放行。注册拦截器时要注意:放行登录、注册、首页列表、项目详情、资讯列表这些游客也能访问的接口,其余接口都需要登录凭证。
这里有个容易被忽略的细节:SpringBoot 拦截器默认只拦截 Controller 层面的请求,对静态资源不生效,所以不用担心图片路径被拦截。
4.3 图片上传与静态资源映射
非遗项目的内容编辑器需要上传封面图和正文图片,读者头像也需要上传。这里不需要引入 OSS,本地磁盘存储就够用。上传接口接收MultipartFile,改名为 UUID 加扩展名,防止中文文件名乱码和重名覆盖。
String originalFilename = file.getOriginalFilename(); String ext = originalFilename.substring(originalFilename.lastIndexOf(".")); String fileName = UUID.randomUUID().toString().replace("-", "") + ext; File dir = new File(uploadPath); if (!dir.exists()) { dir.mkdirs(); } file.transferTo(new File(dir, fileName));上传完成后返回/upload/文件名这样的相对路径,前端拼接域名访问。关键一步是配置静态资源映射,让/upload/**的请求落到本地磁盘目录。这个配置有个经典坑:addResourceLocations的路径必须以/结尾,否则 Windows 和 Linux 上都会出现目录拼接错误,导致图片 404。
4.4 分页、搜索与排序组合拳
列表接口统一用 MyBatis-Plus 的分页插件,前端传pageNum和pageSize,后端返回总条数和当前页数据。搜索实现用LambdaQueryWrapper拼接模糊条件。
Page<Project> page = new Page<>(pageNum, pageSize); LambdaQueryWrapper<Project> wrapper = new LambdaQueryWrapper<>(); wrapper.like(StringUtils.hasText(keyword), Project::getName, keyword) .or(StringUtils.hasText(keyword), w -> w.like(Project::getIntro, keyword)); wrapper.eq(StringUtils.hasText(level), Project::getLevel, level); wrapper.eq(categoryId != null, Project::getCategoryId, categoryId); wrapper.orderByDesc(Project::getViewCount);查询条件的核心技巧是:每个条件的第一个参数传一个布尔表达式,比如StringUtils.hasText(keyword),参数为空时该条件自动忽略,这样上层只传一个 keyword,接口也能正确处理。需要注意的是or的写法,如果直接.like(...).or().like(...),会破坏前面 category 和 level 等条件的 AND 关系,用嵌套闭包w -> w.like(...)才能保持逻辑分组正确。
5. 前端页面与前后端联调:最容易翻车的五个细节
5.1 前后端分离的 Axios 封装与 Token 传递
前端工程建议保持简单清晰:/api目录放接口定义,/views目录放页面组件,/router配置路由,/store管理用户状态。Element UI 负责后台管理的表格和表单,首页和列表页根据需求自定义布局。
Axios 实例要统一封装。请求拦截器里从localStorage取 Token 放到请求头,保证所有需要登录的接口自动携带凭证。响应拦截器里统一解析 Result 结构,code不为 200 时弹出错误提示,遇到 401 时清掉本地用户信息并跳回登录页。
service.interceptors.request.use(config => { const token = localStorage.getItem('token') if (token) { config.headers['Authorization'] = token } return config })5.2 跨域问题:代理与 CORS 选哪个
前后端分离开发时跨域是最先遇到的拦路虎。开发环境推荐用 vue.config.js 里的代理,而不是在后端开 CORS。代理只在开发服务器上生效,后端代码不需要为跨域写任何特殊配置,生产环境部署到同域名下时天然同源。
module.exports = { devServer: { port: 3000, proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true, pathRewrite: { '^/api': '' } } } } }这条配置意味着前端请求/api/project/list会被代理转发到http://localhost:8080/project/list。同时后端所有 Controller 统一定义在/api前缀下,生产环境 Nginx 直接把这个前缀反向代理到后端端口,一套配置两头复用。
5.3 刷新404与路由模式
前端路由如果使用 history 模式,刷新页面时会以当前地址去请求后端,而后端没有这个路由,就会返回 404。这是单页应用部署时最经典的问题。
本地开发时 vue-router 会用开发服务器的 fallback 机制自动处理,但生产环境 Nginx 必须显式配置。一个简单可靠的方案是在 Nginx 的location /里加try_files $uri $uri/ /index.html;,所有找不到文件的请求都落到前端入口。
如果生产环境不使用 Nginx,由 SpringBoot 直接托管前端静态资源,那要写一个转发 Controller 处理非/api开头的页面路由。我实际使用中倾向 Nginx 方案,配置直观且便于后续调整反向代理。
5.4 时间显示成时间戳的真相
后端返回的Date类型字段,默认会序列化成时间戳,前端拿到的是一个纯数字,展示到表格里就是一堆难以阅读的长串。这个问题排查了很久才定位到,根因在后端接口返回前没有对时间格式做统一序列化配置。
解决方案是在application.yml里配置 Jackson 的日期格式,或给时间字段加@JsonFormat注解。前者是全局生效,适合系统中所有时间字段统一格式的场景,但注意某些格式化后的字段前端直接拿来传给后端做时间比较时,可能因字符串格式问题报异常,所以接口入参的时间字段保持原生格式更稳。
5.5 图片回显路径三段坑
图片上传成功后,前端拿到相对路径并拼接记录展示。这个流程看着简单,实际会踩三个坑。第一,后端保存到数据库的路径和实际磁盘路径不一致,导致前端按数据库路径访问 404;第二,Windows 本地测试时一切正常,部署到 Linux 服务器后路径分隔符不对,Windows 用的反斜杠在 Linux 上无效;第三,Nginx 静态资源目录没有给运行用户读权限,图片请求返回 403。
第一条靠约定避免:数据库一律存相对路径,访问时由前端拼接 URL。第二条靠开发时就把路径生成逻辑统一写好,不依赖系统分隔符。第三条则在部署文档中明确要执行chmod -R 755授权目录。
6. 打包部署与远程调试:从本地能跑到导师能看懂的完整链路
6.1 环境差异:本地能跑,服务器不行,问题清单
毕设项目最常见的翻车场景是:本地 IDEA 里跑得顺顺的,打包发给导师或部署到服务器,结果各种问题。我把这些问题归纳成一张排查清单,照着捋基本能定位:
- 版本不一致:本地 MySQL 5.7,服务器 MySQL 8.0,连接驱动、SQL 写法差异导致启动失败。
- 端口不开放:云服务器安全组没有放行 80 和 8080 端口,外部访问不到。
- 数据库密码含特殊字符:
application.yml里写123456没问题,写成123@456没加引号,YAML 解析直接报错。 - 打包产物不包含前端:前后端分离后,后端 jar 包里没有页面文件,访问根路径返回 404。
- 时区问题:服务器默认 UTC 时区,数据库时间比北京时间早了 8 小时,新增记录的时间全部错位。
6.2 Maven 打包与生产配置分离
后端打包前先在本地执行mvn clean package -DskipTests,确认 jar 包能正常生成。如果打包报测试失败,在跳过测试参数下多半能解决。
生产环境配置建议单独拆一个application-prod.yml,覆盖数据源地址、上传路径和日志级别。启动时通过--spring.profiles.active=prod指定环境,这样本地开发用dev配置,服务器用prod配置,互不干扰。配置文件的分离管理是项目交付里最容易体现专业度的地方。
6.3 服务器部署流程:MySQL、JDK、Nginx
服务器部署整体链路不复杂,但每个环节都有对应的坑。
后端启动用nohup java -jar app.jar --spring.profiles.active=prod > app.log 2>&1 &,日志重定向到文件,后续排查全靠它。第一次启动失败时,优先tail -n 100 app.log看日志,大多数启动问题在日志里都有明确原因。
前端部署先本地npm run build生成 dist 目录,上传到服务器后用 Nginx 托管。Nginx 配置要同时处理两件事:页面的 history 路由回退,以及/api前缀请求的反向代理到后端端口。还有一个经常被忽略的点:proxy_pass末尾的斜杠不同,转发的路径拼接结果不同,用proxy_pass http://127.0.0.1:8080;不带斜杠,保留完整/api前缀交给后端路由处理,配合后端的server.servlet.context-path或统一/api设计,是最省心的组合。
6.4 远程调试五步法
标题里提到远程调试,这里展开讲。做毕业设计交付时,很多同学是远程帮别人部署,没法坐在对方屏幕前操作。这种情况下,我的排查顺序是固定的五步:
- 看启动日志:确认 jar 是否正常启动、端口是否被占用、数据库连接是否成功。这一步能过滤掉 80% 的环境类问题。
- 看接口日志:在关键接口入口打日志,确认请求确实到了后端、参数是否为空、返回值是否符合预期。没有日志的排查都是瞎猜。
- 看数据库 SQL:临时开启 MySQL 的
general_log,把每条 SQL 都打印出来,检查查询条件是否正确、是否报语法错误。排查完记得关闭,否则日志文件会迅速膨胀。 - 看前端 Network:让对方面前打开浏览器 F12,看请求的 URL、状态码、响应体。跨域、404、500 在这里一目了然。
- 看资源文件:图片 404、前端静态文件加载失败,检查 Nginx 静态目录权限和路径映射。
如果确实需要远程断点调试,可以在启动参数中加-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005,然后在 IDEA 里配置 Remote JVM Debug 连接到 5005 端口。但这只建议在内网环境使用,公网开放调试端口等于把服务器控制权交出去,安全风险很高。对毕设交付来说,绝大多数问题用上面五步就能解决,调试端口是最后的手段。
后端日志配置也要花点心思。用 logback 把 ERROR 级别单独输出到error.log,排查问题时直接看这个文件,比在满屏的 INFO 日志里翻找高效得多。
7. 文档与答辩演示:别让代码在最后一公里掉链子
7.1 论文结构怎么跟代码对齐
代码写完了,文档跟不上是常见问题。论文结构要严格遵循学校模板,但章节内容要和实际代码一一对应,不能出现论文写的是“系统采用 Redis 缓存”,而代码里根本没有 Redis 这种低级错误。
论文核心章节建议这样安排:绪论里写非遗传播的背景意义,相关技术章节提 SpringBoot、Vue、MyBatis-Plus 的核心特性;需求分析章节画用例图,把游客、注册用户、管理员三端的用例边界画清楚;系统设计章节贴 E-R 图和数据表结构,字段注释要和数据库里的一致;系统实现章节按模块截图配简要说明,重点是突出页面和功能,不是贴大段代码。
数据库设计章节有一个加分的细节:画出核心表的关联关系 E-R 图。答辩时评审老师通常会扫一眼数据模型是否合理,外键关联、字段冗余、索引设计都是可能的提问点。提前在图里理清这些关系,比自己现场临场解释强很多。
7.2 答辩演示顺序与高频问题
答辩演示的顺序要有剧本。我的习惯是:先展示首页——突出非遗项目的分类展示和搜索功能;然后现场注册或登录一个账号——演示收藏和评论;再切换到管理员视角——发布一条非遗项目数据,其中包含图片上传环节;最后切回前端刷新,展示新数据出现在列表里。这个流程覆盖了系统最主要的链路,时间控制在 8 到 10 分钟。
演示一定要提前录一遍视频,避免现场网络抖动、浏览器兼容性问题,视频是备份方案,但通常用不上。演示前先把系统重启一遍,确认没有把“刚刚能用”的旧状态误当成系统正常状态。数据清理也很重要,把测试产生的垃圾数据全部删掉,让界面以整洁的姿态呈现在评委面前。
答辩时高频被问到的问题,可以提前准备标准答案:
- 为什么用 JWT 不用 Session?答:前后端分离场景下 Session 跨域管理麻烦,JWT 无状态、支持多端扩展,适合当前架构。
- 图片存在本地磁盘,生产环境怎么做?答:毕设场景数据量小,本地磁盘够用;生产环境可替换为 OSS,把存储路径配置化,核心代码改动小。
- 分类表为什么用 parent_id?答:支持无限层级扩展,树形查询逻辑统一,满足非遗项目按多级分类组织的需求。
- 浏览量字段直接加在项目表,并发会不准?答:毕设级数据量下足够;未来可拆独立浏览表并用 Redis 做计数缓存。
我个人的体会是,毕业设计真正难的不是某段代码,而是“从需求到设计再到实现交付”这整条线的完整走通。很多人栽在最后一个环节——代码能跑但讲不清楚,或者文档写得漂亮但代码对不上。如果你能把这篇博客里涉及的模块逐个落地,把每个“为什么这样设计”的理由在答辩前顺一遍,这个项目的完成度已经能超过大多数同组同学。最后再分享一个小建议:项目做完后,把启动脚本、部署文档、演示账号密码这三样东西整理成一个 README,发给导师或接手的人,你会感谢当时的自己。