最近把一个基于 Spring Boot 的游戏分享网站从零到一完整做完了,包括前端页面、后端接口、MySQL 数据库脚本,以及配套的设计文档。这个选题在课程设计和毕业设计里属于常年都在出现的经典题目,功能不复杂,但胜在业务闭环非常完整——用户注册登录、游戏资讯浏览、攻略文章发布、评论收藏、后台管理,一趟走下来,几乎把 Spring Boot 最基础也最常用的技术点全部覆盖了。
这篇文章我打算把整个项目的完整脉络讲清楚,从需求拆解、技术选型、数据库设计、核心代码实现,到环境搭建、部署运行、常见问题排查,再到源码、数据库脚本和万字文档怎么配合使用,尽量做到每一步都能直接参考复刻。不管你现在是刚开始准备选题,还是已经写了几千行代码卡在某个问题上,这篇文章都能提供一些可落地的思路。
1. 项目整体设计思路与功能拆解
1.1 为什么说游戏分享网站是课程设计的“黄金选题”
每次有学弟学妹问我课程设计选什么题好,我都会先反问一句:你想不想在答辩的时候被老师追着问“这个功能为什么要这么设计”。如果不想,那游戏分享网站这个方向就是一个非常稳妥的选择。
原因很直接。第一,它的功能足够常规,常规意味着参考资料多、实现路线清晰,哪怕中间遇到问题也能快速找到解决方案。第二,它的功能边界又足够撑起一篇完整的设计文档,从需求分析、概要设计、数据库设计到系统测试,每一个环节都有东西可以写。第三,它天然具备“用户端 + 管理端”的双角色模型,这在答辩时是一个明显的得分点,因为权限控制、会话管理这些内容都属于 Spring Boot 项目的核心知识。
技术栈方面,整个项目没有炫技成分,就是 Spring Boot + MyBatis-Plus + MySQL + Thymeleaf/Vue 这种最常见组合。正因为常见,才适合课程设计。你想想,如果选题用了微服务、分布式、消息队列这些,代码写起来吃力不说,答辩时老师随便追问一个底层原理就可能答不上来。游戏分享网站这种“麻雀虽小五脏俱全”的规模,恰恰是把基础知识点吃透的最佳载体。
1.2 用户端与管理端的核心功能模块
这个项目从功能上可以分成两大块:前台用户使用、后台管理员维护。两块共用同一套数据库,通过不同角色权限来区分访问范围。
前台用户端包括:
| 功能模块 | 具体说明 |
|---|---|
| 注册登录 | 用户名/邮箱注册,BCrypt 加密存储,登录后 Session 保存用户状态 |
| 游戏资讯浏览 | 首页展示游戏推荐、最新资讯列表,支持按分类过滤 |
| 游戏详情页 | 展示游戏封面、简介、开发商、发布时间、热度等信息 |
| 文章分享 | 用户可以发布游戏攻略、评测文章,支持富文本编辑 |
| 评论互动 | 对文章和游戏发表评论,支持评论列表分页展示 |
| 收藏功能 | 用户可以收藏喜欢的游戏或文章,方便后续查看 |
| 个人中心 | 修改个人资料、查看自己发布的内容、管理收藏夹 |
后台管理端包括:
| 功能模块 | 具体说明 |
|---|---|
| 管理员登录 | 独立登录入口,只有管理员账号可以进入 |
| 用户管理 | 查看注册用户列表,禁用/启用账号 |
| 分类管理 | 维护游戏分类,比如动作、角色扮演、策略等 |
| 游戏信息管理 | 增删改查游戏数据,上传封面图 |
| 文章审核管理 | 审核用户发布的文章,支持通过/驳回 |
| 评论管理 | 删除违规评论 |
| 轮播图管理 | 编辑首页轮播图内容 |
| 数据概览 | 统计用户数量、游戏数量、文章数量等基础数据 |
这个功能列表不是凭空想出来的,而是根据大部分游戏分享类站点的通用模型提炼出来的。对于课程设计来说,做到这个程度已经完全足够,而且每个模块背后都能对应到 Spring Boot 的分层结构:Controller 接收请求、Service 处理业务逻辑、Mapper 操作数据库。
1.3 角色权限与页面流程
项目采用单一入口方式,登录后根据用户角色跳转不同界面。普通用户登录后进入前台首页,管理员登录后进入后台管理页。页面流转大致是这样的:
游客访问首页 -> 能浏览游戏和文章,但点击“发布文章”“评论”“收藏”时会跳转到登录页;登录成功后自动跳回之前的页面;普通用户进入个人中心;管理员访问固定的后台地址,通过拦截器校验角色身份。
权限控制这部分,我没有选择引入 Spring Security,因为这个项目的安全需求并没有那么重,自己基于拦截器实现反而更简洁直观,也更容易在答辩时讲清楚。实现思路是在 Spring MVC 中注册一个 HandlerInterceptor,拦截所有/admin/**和/user/**请求,检查 Session 中是否存在登录用户;对于后台请求还要额外检查用户角色是否为管理员。代码量不大,但能有效保护接口安全。
2. 核心技术点拆解:Spring Boot 项目里最容易拿分的地方
2.1 版本选型:JDK 8 + Spring Boot 2.7 是课程设计的最稳组合
项目在版本选择上走的是保守路线。看到很多同学在网上搜项目源码时经常遇到一个问题——下载下来的项目版本太高,本地 JDK 版本跟不上,一启动就报错。网上搜“springboot版本太高”居然有那么多人踩坑,说明这个问题确实普遍。
我这里用的是 Spring Boot 2.7.18 + JDK 8。为什么不用 Spring Boot 3.x?因为 Spring Boot 3 强制要求 JDK 17 及以上,而且很多老版本的依赖不兼容。课程设计场景下,大多数同学的开发环境还是 JDK 8,学校机房提供的也往往是老版本 JDK。选择 Spring Boot 2.7 可以最大限度避免环境不匹配的问题。
当然,如果你本机已经安装了 JDK 17,直接用 Spring Boot 3.x 也没问题。但要注意两个差异:第一,javax.servlet相关的依赖要改成jakarta.servlet,包名会变;第二,MyBatis-Plus 需要引入支持 Spring Boot 3 的专门版本。这些细节在移植项目时非常容易踩坑,所以我会更推荐先统一到 JDK 8 + Spring Boot 2.7。
另外还要注意 Spring Boot 2.7 版本中,springfox这种 Swagger 依赖已经不兼容了,如果你是做接口文档展示,建议用springdoc-openapi替代,但这部分在课程设计里不是必须的,可以不做。
2.2 持久层选型:MyBatis-Plus 能把增删改查效率翻倍
持久层框架我选的是 MyBatis-Plus。它本质上是对 MyBatis 的增强,最大的优势是单表 CRUD 不需要手写 SQL,直接继承BaseMapper<T>就能调用selectById、insert、updateById、deleteById这些现成方法。对于游戏分享网站这种以单表操作为主的业务模型,能省下大量模板代码。
举个例子,用户表操作只需要这样:
public interface UserMapper extends BaseMapper<User> { }业务层注入后直接就能用:
@Autowired private UserMapper userMapper; public User findUserById(Long id) { return userMapper.selectById(id); }MyBatis-Plus 的分页插件也做了封装,配置一个拦截器就能使用Page<>分页查询:
@Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }使用分页查询文章列表时只需要:
Page<Article> page = new Page<>(current, size); LambdaQueryWrapper<Article> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(Article::getStatus, 1).orderByDesc(Article::getCreateTime); articleMapper.selectPage(page, wrapper);这段代码底层会自动拼接LIMIT,不用自己担心 SQL 语法问题。在课程设计中,如果能熟练说出LambdaQueryWrapper的条件构造原理,这在答辩时是很加分的。
2.3 登录认证与权限控制:不用 Spring Security 也能做得很完整
很多课程设计项目一上来就引入 Spring Security,结果配置一堆过滤器链,最后自己都没完全搞懂。游戏分享网站这个体量,基于 Session + 拦截器完全够用。
密码存储用的是 BCrypt 加密。为什么不用 MD5?因为 MD5 是摘要算法,虽然不可逆但存在彩虹表风险,相同密码加密结果永远相同。BCrypt 每次加密都会生成随机盐,相同密码两次加密结果都不一样,安全性高一个量级。引入 Spring Security 的 crypto 模块就能使用这个加密,或者直接用hutool工具类也可以。
登录核心逻辑:
public User login(String username, String password) { User user = userMapper.selectOne( new LambdaQueryWrapper<User>() .eq(User::getUsername, username) .eq(User::getStatus, 1) ); if (user == null) { throw new RuntimeException("用户不存在或已被禁用"); } if (!BCrypt.checkpw(password, user.getPassword())) { throw new RuntimeException("密码错误"); } return user; }登录成功后在 Controller 中把用户对象放入 Session:
session.setAttribute(Constants.LOGIN_USER_KEY, user);定义拦截器校验登录状态:
public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(); Object user = session.getAttribute(Constants.LOGIN_USER_KEY); if (user == null) { response.sendRedirect("/login"); return false; } return true; } }对于后台管理接口,再加一个管理员拦截器,检查 Session 中用户对象的role字段是否为管理员。整套逻辑不依赖第三方安全框架,原理更容易讲透。
2.4 文件上传与富文本处理
游戏封面、文章配图都需要文件上传功能。项目里我用的是本地磁盘存储,上传的图片保存到服务器的指定目录,然后通过一个配置好的虚拟路径映射到静态资源。
在application.yml中配置上传文件大小限制:
spring: servlet: multipart: max-file-size: 10MB max-request-size: 20MB静态资源映射配置:
spring: web: resources: static-locations: classpath:/static/, file:${upload.path}其中upload.path是指向本地图片存储目录的路径,使用file:前缀是因为要读取磁盘上的真实文件。
文件上传 Controller 核心方法:
@PostMapping("/upload") public Result upload(@RequestParam("file") MultipartFile file) { if (file.isEmpty()) { return Result.error("请选择文件"); } String originalFilename = file.getOriginalFilename(); String suffix = originalFilename.substring(originalFilename.lastIndexOf(".")); String fileName = UUID.randomUUID() + suffix; File dir = new File(uploadPath); if (!dir.exists()) { dir.mkdirs(); } file.transferTo(new File(uploadPath + fileName)); return Result.success("/files/" + fileName); }富文本编辑器方面,前端可以选 wangEditor 或者 quill,后台控件只需把上传接口返回的 URL 插入到编辑器的内容中。课程设计里能实现图片上传到服务器并在富文本中展示,已经是功能上的一个小亮点。
3. 数据库表设计与关键字段说明
3.1 核心表设计与关联关系
数据库设计是整个系统的基础,表结构设计得合理,后面写业务代码会非常顺畅。项目一共设计了七张核心表,覆盖用户、内容、互动三个维度:
| 表名 | 中文说明 | 关键字段 |
|---|---|---|
| tb_user | 用户表 | id, username, password, nickname, avatar, email, role, status, create_time |
| tb_category | 游戏分类表 | id, name, sort, status |
| tb_game | 游戏资料表 | id, category_id, name, cover, intro, developer, publisher, publish_date, hot, status |
| tb_article | 文章表 | id, user_id, game_id, title, cover, content, view_count, like_count, status, create_time |
| tb_comment | 评论表 | id, user_id, article_id, content, parent_id, create_time |
| tb_favorite | 收藏表 | id, user_id, target_type, target_id, create_time |
| tb_banner | 轮播图表 | id, image, title, url, sort, status |
tb_article中的game_id外键关联tb_game,用来标识这篇文章是围绕哪款游戏写的。tb_favorite通过target_type字段区分收藏对象是游戏还是文章,这样一张表就能承载两种收藏场景,避免建两张收藏表。tb_comment中的parent_id支持回复功能,parent_id为 0 表示顶级评论,不为 0 则指向某条评论的 ID。
用户表和管理员共用一张表,通过role字段区分,普通用户为0,管理员为1。这样设计减少了表数量,管理员的账号管理也直接复用用户模块的逻辑。
3.2 关键 SQL 与索引设计
虽然 MyBatis-Plus 能减少手写 SQL 的频率,但项目中确实有一些场景适合自己写 SQL,比如多表联查和统计类查询。
查询文章信息并展示发布者昵称:
SELECT a.id, a.title, a.cover, a.content, a.view_count, a.create_time, u.nickname AS author_name, g.name AS game_name FROM tb_article a LEFT JOIN tb_user u ON a.user_id = u.id LEFT JOIN tb_game g ON a.game_id = g.id WHERE a.status = 1 ORDER BY a.create_time DESC这种查询在首页文章列表和文章详情页都会用到。索引方面,建议在tb_article的status和create_time上建立索引,因为文章列表页经常按这两个字段过滤和排序。tb_favorite上对user_id建索引,因为个人中心查询“我的收藏”是高频操作。
还有几个常用的统计 SQL:
-- 统计各分类下的游戏数量 SELECT c.name, COUNT(g.id) AS total FROM tb_category c LEFT JOIN tb_game g ON c.id = g.category_id GROUP BY c.id ORDER BY total DESC这个 SQL 用来做后台数据概览中的分类统计。
3.3 初始化数据与演示账号
课程设计要面临一个非常现实的问题:老师打开系统的时候,页面上必须有内容可以看。一个空数据库会给演示带来很大的尴尬,所以数据库脚本里必须预置合理的演示数据。
项目 SQL 脚本中包含一个默认管理员账号admin,密码是admin123。注意这里不是明文存储,而是 BCrypt 加密过的一串哈希值。同时还有若干个普通用户账号,方便演示注册登录以外的用户操作。
游戏分类预置了五个常见分类:动作游戏、角色扮演、射击游戏、策略游戏、休闲益智。每个分类下放 2-3 条游戏数据,游戏封面使用本地静态图片路径。文章区域预置了几篇图文并茂的攻略和评测内容,评论和收藏数据也适当填充了一些。
实测下来,演示时数据充分的话,老师更容易把关注点放在系统功能上,而不是反复问“为什么这里没有内容”。
4. 环境搭建与从零初始化运行
4.1 本地环境清单:别在版本上翻车
开篇提到过一个高频热搜词“springboot版本太高”,要避免这个问题,环境版本必须提前统一。这里整理了一份我实际跑通的环境清单:
| 软件 | 版本建议 | 说明 |
|---|---|---|
| JDK | 1.8 | 课程设计最稳妥的版本 |
| Maven | 3.6.3 及以上 | 用来管理依赖和打包 |
| MySQL | 5.7 或 8.0 | 两种版本都可以,注意驱动配置略有区别 |
| IDEA | 2021.2 及以上 | 社区版也能跑,但旗舰版更方便 |
| Spring Boot | 2.7.18 | 项目核心依赖版本 |
| MyBatis-Plus | 3.5.3.1 | 兼容 Spring Boot 2.x |
如果你用的是 MySQL 8.0,application.yml中的驱动类需要写成com.mysql.cj.jdbc.Driver,并且数据源 URL 中要加上时区参数:
spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/game_share?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 123456这里不写serverTimezone参数的话,高版本 MySQL 会报时区错误,这是新手最容易遇到的问题。
4.2 创建项目与核心依赖配置
项目创建可以直接在 IDEA 中通过 Spring Initializr 完成,选择 Java 8 版本,然后引入 Web、MySQL、Lombok 等基础依赖。如果初始化时网络下载依赖慢,建议将 Maven 仓库切换到国内镜像源。
pom.xml中的核心依赖如下:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>最后这个spring-boot-starter-security仅用于使用其中的 BCrypt 加密工具类,不需要配置 Spring Security 的过滤链。如果不想引入这个依赖,也可以把工具类单独提取出来,用其他加密工具替换。
4.3 application.yml 配置与数据库导入
完整的application.yml还包含 MyBatis-Plus 的配置和文件上传路径:
mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl map-underscore-to-camel-case: true global-config: db-config: logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0map-underscore-to-camel-case非常重要,它能让数据库的create_time字段自动映射到 Java 实体的createTime属性,避免大量手写 resultMap。
数据库导入时,先用 Navicat 或命令行创建名为game_share的数据库,然后将项目中的sql/game_share.sql文件直接执行。脚本里包含建表语句和预置数据,执行后项目就能直接连接使用。
4.4 启动项目与第一次登录
以上配置完成后,找到主启动类,运行main方法,控制台出现 Spring Boot 的启动日志后,访问http://localhost:8080就能看到首页。
第一次登录建议用管理员账号,在页面右上角找到后台入口,输入admin / admin123进入后台管理界面。正常登录后,可以在后台看到用户列表、游戏分类、文章审核等菜单。
如果启动时报端口被占用,在application.yml中修改server.port或者找到占用进程关闭即可:
# Linux/Mac lsof -i:8080 kill -9 PID5. 部署打包与运行环境排查
5.1 Maven 打包并发布到服务器
项目在本地跑通之后,需要打成可执行 JAR 包部署到服务器。在 IDEA 的 Terminal 中执行:
mvn clean package -DskipTests打包完成后,target目录下会生成game-share-0.0.1-SNAPSHOT.jar。上传到服务器后,用以下命令启动:
nohup java -jar game-share-0.0.1-SNAPSHOT.jar > app.log 2>&1 &这里做几点说明。-DskipTests是为了跳过测试用例加快打包;nohup是为了让进程在退出终端后继续运行;app.log保存运行日志,排查问题时会用到。
如果使用云服务器,需要确认安全组和防火墙放行 8080 端口。部署后通过http://服务器IP:8080访问。
5.2 本地能跑服务器上崩了:环境差异怎么排查
很多项目本地运行完全正常,一到服务器就各种报错,这种情况绝大部分是环境差异导致的。
第一,数据库地址问题。服务器上连接数据库不能再用localhost,要改成 MySQL 所在机器的 IP,并且保证数据库用户的host配置允许远程连接。用root账号远程连接时,经常报“Host is not allowed to connect”,需要执行授权 SQL。
第二,文件路径问题。项目里如果用绝对路径存储上传文件,例如D:/upload,在 Linux 服务器上肯定找不到这个目录。建议上传路径做成可配置,在application.yml中配置绝对路径,部署时再根据服务器环境修改。
第三,时区和日志问题。Java 进程默认时区可能和服务器时区不一致,建议启动时加上-Duser.timezone=Asia/Shanghai参数。
5.3 课程设计演示时的注意事项
课程设计答辩现场本身就是一种“部署环境”,如果临时打开项目加载数据,很可能因为启动太慢或者数据库配置问题卡住。我个人的建议是:提前一天在演示用的电脑上完整跑一遍,浏览器打开页面,所有功能点都点一遍,确认没有报错再关闭。
另外,页面上的演示数据一定要提前准备充分。比如在轮播图位置放几张好看的推荐图,在游戏详情页保证封面加载正常,在评论区预置几条正常评论。这些东西会让答辩展示的观感好很多。
6. 常见问题与排查技巧实录
6.1 启动失败:先看报错的前三行
Spring Boot 启动失败时,控制台会刷出来一大段错误日志。不要从头到尾看,重点看最前面的几行异常信息。最常见的启动报错不外乎三种:端口被占用、数据库连接失败、依赖下载不完整。
数据库连接失败的典型报错是:
Cannot create PoolableConnectionFactory (Access denied for user 'root'@'localhost')这时候先检查application.yml中的用户名密码是否正确,再确认 MySQL 服务有没有启动。如果报的是:
Access denied for user 'root'@'localhost' (using password: YES)说明密码错误,需要修改配置文件或重置数据库密码。
6.2 中文乱码与时区问题
数据库里中文乱码通常是字符集设置问题。创建数据库时指定 UTF-8 编码:
CREATE DATABASE game_share DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;同时,连接 URL 中也要加上characterEncoding=utf8参数。只要这两个地方统一为 UTF-8,中文基本不会乱码。
6.3 文件上传失败与静态资源404
文件上传失败先检查max-file-size配置,默认只有 1MB,大图片会超过限制。检查上传目录是否存在,程序里如果目录不存在会抛IOException。
图片上传后访问出现 404,十有八九是静态资源映射配置没生效。检查static-locations配置是否包含file:前缀,注意路径末尾的斜杠。
6.4 项目常见问题速查表
| 问题现象 | 可能原因 | 解决办法 |
|---|---|---|
| 启动后访问空白 | 端口被占用或静态资源未加载 | 修改端口,清理项目缓存 |
| 登录提示密码错误 | 数据库中密码明文存贮 | 改用 BCrypt 加密存储 |
| 页面中文乱码 | 数据库字符集不是 UTF-8 | 重建数据库并指定 utf8mb4 |
| 上传图片 404 | 静态资源映射路径不对 | 检查 yml 中 static-locations 配置 |
| 评论出现 SQL 错误 | 表字段名与实体属性不一致 | 开启驼峰映射或加 resultMap |
| 后台功能访问无权限 | Session 校验失败 | 检查拦截器放行路径配置 |
7. 源码、数据库与万字文档:项目交付物怎么用
7.1 源码目录结构与关键文件定位
完整项目源码按照 Spring Boot 标准结构组织,拿到手之后不要急着跑,先看目录结构,知道每个文件是干什么用的。
controller包里存放所有接口,按业务模块拆分成 UserController、ArticleController、GameController、CommentController、AdminController 等;service包存放业务逻辑,接口和实现分离;mapper包存放 MyBatis-Plus 的 Mapper 接口;entity包存放数据库实体类;config包存放拦截器、MyBatis-Plus 分页配置;interceptor包存放权限校验拦截器;common包存放统一返回结果类、常量类、异常处理类。
看懂这个结构以后,改功能就有方向了。比如想改注册逻辑,去 UserController 里找注册接口,然后调 UserService 里的对应方法。
7.2 数据库脚本与演示数据怎么导入
项目附带的数据库脚本位于sql/game_share.sql,包含完整的建库、建表、预置数据语句。导入步骤非常固定:
- 打开 Navicat 或 MySQL 命令行,新建数据库
game_share,字符集选utf8mb4 - 右键选择“运行 SQL 文件”,选择
game_share.sql - 执行完成后刷新表列表,应该能看到 7 张表以及每张表的演示数据
强烈建议不要修改数据库名称,因为配置文件里已经写死了数据库连接地址,如果你改了库名,同步要修改application.yml中的数据源配置。
7.3 万字文档怎么写不显得“灌水”
课程设计文档写到一万字并不难,难的是写满一万字还能让老师觉得有内容。这里分享我组织文档章节的一个实际结构,这套结构可以直接套用:
第一章绪论,包括背景意义、国内外研究现状、研究内容。第二章需求分析,包括可行性分析、功能需求分析、非功能需求分析、用例图。第三章系统设计,包括总体架构设计、功能模块设计、数据库设计,数据库设计部分附上 E-R 图和每张表的字段说明。第四章系统实现,按模块逐个描述实现方式,每个模块先放核心代码片段,再解释代码逻辑。第五章系统测试,整理测试用例表格,包含测试项、测试步骤、预期结果、实际结果。最后是总结与展望。
写文档的核心技巧是:代码贴关键片段而不是全部粘贴;每个模块的文字描述要和代码对得上;测试部分最好真实跑一遍系统,把界面截图放上去,这些都是实打实的内容,不容易被判定为拿来主义。
最后说一个我自己的感受:做课程设计最忌讳的是把文档和代码分开写,很多同学代码跑完才回头编文档,最后文档和代码完全对不上,答辩时一问就露馅。我习惯在做每个功能的时候,顺手把这块的设计思路、表结构变化、测试结果记在文档草稿里,这样做完项目文档也基本成型了。另外,功能可以适当加一两个小亮点,比如图片上传支持拖拽、评论支持二级回复,这些改动不大,但在答辩时很容易让老师觉得你确实深入思考过。