计算机毕业设计之springboot校园信息发布平台的设计与实现——这个题目在每年的毕设选题清单里几乎都能看见,看着平平无奇,但每年都有人做到一半推倒重来。带过几届毕设之后,我的感受是:这个题目的难点根本不在技术,而在需求理解、模块划分和细节打磨。校园信息发布平台本质是一个内容管理系统,核心就是校园公告的发布、审核、展示与检索。这篇文章会把架构设计、表结构、核心代码、部署答辩四个方向拆开讲,目标读者是正在做这个题目、或者准备选类似题目的本科同学,希望能帮你们少走几个月的弯路。
1. 项目定位与整体架构设计
1.1 毕业设计要交什么,评委到底看什么
先泼一盆冷水:这个题目不新,答辩老师年年都见,所以不要指望靠题目本身拿分。真正拉开差距的,是你能不能把一个偏传统的 CRUD 系统讲清楚、做完整、演示流畅。
计算机毕业设计通常要交付五样东西:开题报告、中期检查、毕业论文、系统源码和答辩演示。老师评判一个系统,优先级大概是这样的:
- 功能完整性:登录、发布、审核、展示、删除这些主线功能是不是都跑通了。
- 业务逻辑合理性:比如发布和审核是不是分离的、权限划分是不是符合真实场景。
- 代码质量:分层是否清晰,前端和后端是否规范,有没有明显的烂代码。
- 工作量:数据库设计是不是有足够多的表和关联,功能点是不是撑得起一篇论文。
明白了这四点,就不会在选题阶段浪费太多时间纠结"要不要用微服务"了。不要用微服务,也不要用 Docker K8s。毕业设计考察的是你对一个完整业务系统的理解,你把"谁能发、谁能审、谁能看、信息怎么存、怎么展示"这五件事理清楚,系统就立住了。体量和复杂度刚刚好能写出一篇一万字以上的论文,答辩也能讲清楚,这才是一个合格的毕设选题。
1.2 技术选型:为什么偏偏是SpringBoot
校园信息发布平台的技术选型,基本可以闭眼选择 SpringBoot + MyBatis Plus + MySQL。如果你再会一点 Vue,做前后端分离,那就是近几年评阅老师非常认可的标准搭配了。
SpringBoot 之所以能成为毕业设计主流,不在于它比 SSH 更"高级",而在于它把 Spring 的配置负担降到了最低。可以打一个生活化的比方:SpringBoot 是一套已经装好水电煤气的精装房,进门就能住;老 Spring 项目是毛坯房,住进去之前还得自己拉电线、铺水管、刷墙。SpringBoot 的自动装配帮我们把数据源配置、事务管理、Web 容器、参数校验这些东西全部通过 starter 自动搞定,你只需要专注于写业务逻辑。
选 MyBatis Plus 也类似。传统的 MyBatis 每个实体都要写一堆 XML 和 ResultMap,而 MyBatis Plus 提供了开箱即用的单表 CRUD 方法,分页查询也有现成插件,非常适合做管理后台。更重要的是,论文里可以明确写出"使用 MyBatis Plus 减少样板代码,提升开发效率",这样的一句话比盲目堆技术要实用得多。
版本上我会特别说一句:优先选 SpringBoot 2.7.x,不要用 SpringBoot 3.x。SpringBoot 3.0 之后强制要求 JDK 17,而且 javax 包名改成了 jakarta,很多老教程里的代码直接报错;学校机房和大多数同学的电脑上装的多是 JDK 8 或 JDK 11。为了一个"最新版本"去踩大量兼容性的坑,完全没必要。2.7.18 是 2.x 最后一个维护版本,稳定性和资料丰富度都是最好的。
pom.xml 的核心依赖可以这样写:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.18</version> <relativePath/> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</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> <scope>runtime</scope> </dependency> </dependencies>前端选 Vue 3 + Element Plus 是当前的主流做法。Vue 的组件化开发让页面代码比 JSP 清爽很多,而且打包之后可以直接丢进 SpringBoot 的 static 目录,一句话都不用改。这里不用纠结是不是要学 React,毕设场景下 Vue 完全够用,资料也最好找。
1.3 整体架构与目录规划
推荐使用前后端分离结构:后端 SpringBoot 提供 RESTful API,前端 Vue 独立开发。项目最终目录可以这样规划:
school-info-platform/ ├── src/main/java/com/example/schoolinfo/ │ ├── controller/ # 控制层,接收HTTP请求 │ ├── service/ # 业务逻辑层 │ │ └── impl/ # Service实现类 │ ├── mapper/ # MyBatis Plus 数据访问层 │ ├── entity/ # 实体类,对应数据库表 │ ├── dto/ # 请求参数对象,避免直接用实体接收 │ ├── config/ # 配置类:拦截器、跨域、MyBatis Plus分页 │ ├── common/ # 统一结果封装、全局异常处理、工具类 │ └── SchoolInfoApplication.java ├── src/main/resources/ │ ├── application.yml # 核心配置文件 │ └── mapper/ # 如果SQL逻辑复杂,可放Mapper XML ├── frontend/ # Vue3 前端工程(独立目录) │ ├── src/ │ │ ├── api/ # 封装axios请求 │ │ ├── router/ # 前端路由 │ │ ├── views/ # 页面组件 │ │ └── store/ # Pinia状态管理 │ └── package.json └── pom.xml很多同学喜欢把所有类都堆在一个包下面,比如 entity 和 dto 混着放、工具类散落各处。这在做项目的当下可能觉得没什么,但写论文的时候你会发现代码目录图根本没法画,老师问"这一层负责什么"你也会卡壳。分层这件事,越早规整越省心。
Controller 层只做参数接收和结果封装,Service 层写业务逻辑,Mapper 层只做数据库操作,这个铁律建议从第一天就遵守。项目不大,不需要过度设计成 DDD 那种模式,但一个清晰的经典三层结构,已经足够支撑你答辩时说出每一行代码为什么放在这个位置。
2. 核心功能模块拆解
2.1 用户角色与权限模型:别把权限做成摆设
校园信息发布平台的用户角色,常见的有三类:管理员、信息发布员、普通学生。这里的"发布员"可以是院系老师、学生会干部,也可以直接简化为"教师用户"。角色不同,能做的事情差异非常大。
| 角色 | 可以做什么 | 不能做什么 |
|---|---|---|
| 管理员 | 审核公告、管理分类、管理用户、删除任意内容、置顶公告 | 无 |
| 发布员 | 创建公告、编辑自己的草稿、提交审核 | 不能审核,不能修改别人的公告 |
| 普通学生 | 浏览公告、搜索公告、查看详情 | 不能发布,不能审核 |
这个划分对应着真实校园场景:学生在校发一条寻物启事是合理的,但是所有学生都能直接发公告就乱了,所以发布权限只给发布员;如果是学生也能提交信息,那就需要"待审核"环节,管理员确认无误之后再展示。
权限实现方式上,我建议不要用 Spring Security。不是说它不好,而是它配置复杂、概念多,对新手极其不友好——光是一个过滤器链和登录认证流程,就能耗掉两个星期。毕设场景下,用拦截器 + Token 校验就足够清晰了。
具体做法是:登录成功之后,后端生成一个 Token 字符串,一般里面存 userId 和角色,用 Redis 存一份做有效期控制;前端请求时放在请求头中,后端写一个拦截器拦截需要权限的接口,在拦截器里从 Redis 取出用户信息校验。这样实现简单、思路直观,还方便写进论文里。
拦截器的核心代码大致是这样:
public class LoginInterceptor implements HandlerInterceptor { @Autowired private StringRedisTemplate redisTemplate; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token = request.getHeader("Authorization"); if (token == null || !redisTemplate.hasKey("login:token:" + token)) { response.setStatus(401); response.setContentType("application/json;charset=UTF-8"); response.getWriter().write("{\"code\":401,\"message\":\"未登录或登录已过期\"}"); return false; } // 从Redis中获取用户ID,放入request上下文,供后续业务使用 Object userId = redisTemplate.opsForValue().get("login:token:" + token); request.setAttribute("userId", userId); return true; } }注册拦截器时重点注意放行规则。登录、注册接口、访问静态资源、跨域预检请求都必须在放行名单里,否则前端连页面都打不开。这个坑我见过太多次——报错信息五花八门,最后发现只是拦截器把静态资源管家了。
2.2 信息发布与审核流程:一个状态机的完整闭环
平台的主线业务是公告,但公告不是"点一下发布就完事"的。如果真做那么简单,答辩时老师一定会问:发错了怎么办?怎么追责?所以要设计一个完整的状态流。
公告状态可以这样设计:
| 状态值 | 状态名 | 说明 | 谁可以操作 |
|---|---|---|---|
| 0 | 草稿 | 发布员创建但未提交 | 发布员 |
| 1 | 待审核 | 发布员已提交,等待管理员审核 | 管理员 |
| 2 | 已发布 | 审核通过,前台可见 | 管理员 |
| 3 | 已下架 | 手动下架或定时过期,前台不可见 | 管理员、定时任务 |
| 4 | 已驳回 | 审核不通过,附驳回原因 | 管理员 |
这个状态机串起来就是完整闭环:发布员创建草稿 -> 提交审核 -> 管理员查看详情 -> 审核通过或驳回 -> 通过后平台前端展示 -> 到截止时间自动下架。写到论文里,一张流程图加一段文字说明就够了,工作量立刻显得扎实。
除了状态,公告本身还需要几个核心属性:置顶标识、浏览量、所属分类、发布时间、下架时间。置顶的处理不难,查询时按置顶降序、发布时间降序排序就行。如果置顶有时间限制,就加一个 top_expire_time 字段,到点之后定时任务自动把 is_top 改回 0。
浏览量统计不要用纯自增 UPDATE,这样每次访问都会写数据库,压力大且不优雅。可以先用 Redis 的 String 或 Hash 累加,比如用info:view:1001作为 key,每次访问执行increment,然后每分钟或每十分钟把增量写回数据库。这一段写进论文,又能占一块亮点内容。
公告内容建议直接用富文本。前端用 wangEditor 或 vue-quill-editor,编辑内容存 HTML 到longtext字段里。展示页面直接渲染后端返回的 HTML 字符串就好。
2.3 前端页面设计:管理后台和用户端分开做
前端是整个项目最容易被忽视但最能讨好感的部分。老师演示系统时,第一眼看到的就是页面长什么样。一个干净整洁的管理后台,能直接拉升系统印象分。
管理后台建议用 Vue3 + Element Plus,页面不太多,通常包括这些:
- 登录页:账号密码 + Token存储到 localStorage。
- 公告管理页:表格展示公告列表,支持模糊筛选、分页、置顶、审核操作。
- 审核页:待审核列表,点开能看完整内容,通过/驳回按钮。
- 分类管理页:公告分类的增删改查。
- 用户管理页:管理员查看用户列表、禁用账号。
而普通用户端可以做得轻量一些,不一定非要用 Vue,直接在后端 static 目录放几个 HTML 页面也可以。但要控制成本,更推荐的做法是:首页公告列表 + 详情页 + 搜索页,三个页面覆盖主要功能即可。
公告列表查询接口建议做成一体的:分页 + 分类筛选 + 关键词模糊搜索 + 置顶排序。前端表格组件配合 Element Plus 的el-pagination组件做分页,后端返回MyBatis Plus的Page对象。
页面设计上有两个小技巧:
- 默认数据要全:演示时要让别人看到列表不是空空如也,预置 15~20 条覆盖不同分类的公告。
- 操作按钮的权限控制:普通用户登录后不应该看到"审核"按钮。前端控制按钮的
v-if,同时后端接口也要拦截权限,双保险。
前端代码写完之后,执行npm run build,把生成的 dist 目录里的文件复制到 SpringBoot 的src/main/resources/static下面,再重新打包后端,前端页面就和后端打成一个 jar 包了。这个动作非常适合毕设现场演示,省得在答辩电脑上再装 Node 环境。
3. 关键代码与实现细节
3.1 数据库表设计:四张表撑起整个业务
数据库设计是论文系统设计章节的重头戏。校园信息发布平台建议设计四张核心表:用户表user、公告表info、分类表category、审核记录表audit_log。
用户表结构:
CREATE TABLE `user` ( `id` bigint NOT NULL AUTO_INCREMENT, `username` varchar(50) NOT NULL COMMENT '登录账号', `password` varchar(255) NOT NULL COMMENT '密码,BCrypt加密存储', `nickname` varchar(50) DEFAULT NULL COMMENT '姓名/昵称', `role` tinyint NOT NULL DEFAULT 0 COMMENT '角色:0学生 1发布员 2管理员', `status` tinyint NOT NULL DEFAULT 1 COMMENT '状态:1正常 0禁用', `create_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uk_username` (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';这里强调一点:密码绝对不要明文存储。答辩老师看到明文密码,印象分会直线下降。使用 Spring Security 自带的BCryptPasswordEncoder,或者 SpringBoot 里的org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder,注册时加密、登录时校验,代码只有两行,却是安全意识的直接体现。
公告表结构:
CREATE TABLE `info` ( `id` bigint NOT NULL AUTO_INCREMENT, `title` varchar(200) NOT NULL COMMENT '公告标题', `content` longtext COMMENT '公告正文,富文本HTML', `category_id` bigint DEFAULT NULL COMMENT '分类ID', `publisher_id` bigint DEFAULT NULL COMMENT '发布人ID', `status` tinyint NOT NULL DEFAULT 0 COMMENT '状态:0草稿 1待审核 2已发布 3已下架 4已驳回', `is_top` tinyint NOT NULL DEFAULT 0 COMMENT '是否置顶:0否 1是', `top_expire_time` datetime DEFAULT NULL COMMENT '置顶过期时间', `view_count` int NOT NULL DEFAULT 0 COMMENT '浏览量', `reject_reason` varchar(500) DEFAULT NULL COMMENT '驳回原因', `create_time` datetime DEFAULT CURRENT_TIMESTAMP, `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_category` (`category_id`), KEY `idx_status` (`status`), KEY `idx_publisher` (`publisher_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='公告信息表';content 用longtext是为了撑住富文本编辑器生成的 HTML 字符串,这类型最多能存 4GB 文本,实际场景绝对够用。索引加了三个,分别对应查询时最常用到的三个条件:按分类查、按状态查、按发布人查。测试数据量一大,索引带来的查询速度差异会非常明显,这一点也能写进论文的性能分析。
分类表和审核记录表相对简单:
CREATE TABLE `category` ( `id` bigint NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL COMMENT '分类名称', `sort_order` int NOT NULL DEFAULT 0 COMMENT '排序值,越小越靠前', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='公告分类表'; CREATE TABLE `audit_log` ( `id` bigint NOT NULL AUTO_INCREMENT, `info_id` bigint NOT NULL COMMENT '公告ID', `auditor_id` bigint NOT NULL COMMENT '审核人ID', `action` tinyint NOT NULL COMMENT '操作:1通过 2驳回', `reason` varchar(500) DEFAULT NULL COMMENT '审核意见', `create_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审核记录表';不要小看审核日志表。它解决的问题是"谁在什么时间对哪条公告做了什么操作"——一张日志表就把审计功能补齐了,答辩时这个设计是非常加分的点,因为大多数同学做毕业设计根本不会考虑可追溯性。
3.2 后端核心代码:登录、发布、审核怎么写出彩
登录接口是系统第一个入口,代码要干净。这里建议用 DTO 接收参数,不要直接把前端 JSON 绑到实体类上。一个 User 实体包含 id、role、status 等字段,登录请求只需要 username 和 password,直接绑实体反而会让未赋值字段产生歧义。
@PostMapping("/login") public Result login(@RequestBody @Validated LoginDTO dto) { User user = userService.login(dto.getUsername(), dto.getPassword()); String token = TokenUtil.generate(user.getId().toString()); redisTemplate.opsForValue().set("login:token:" + token, user.getId().toString(), 24, TimeUnit.HOURS); return Result.ok("登录成功") .put("token", token) .put("role", user.getRole()) .put("nickname", user.getNickname()); }登录密码校验逻辑放到 UserService 里,用BCryptPasswordEncoder.matches(明文, 加密密文)去判断。如果失败抛出 BizException,再由全局异常处理器转换成 JSON 返回。
发布公告的 Service 方法可以这样写:
@Transactional(rollbackFor = Exception.class) public Long createInfo(InfoPublishDTO dto, Long userId) { Info info = new Info(); info.setTitle(dto.getTitle()); info.setContent(dto.getContent()); info.setCategoryId(dto.getCategoryId()); info.setPublisherId(userId); // 学生提交默认进草稿,发布员直接提交进待审核 info.setStatus(dto.getSubmit() ? 1 : 0); infoMapper.insert(info); return info.getId(); }用@Transactional把多步数据库操作包裹起来,保证要么全成功、要么全回滚。这条命令写代码时看不出什么,但在答辩时被问"多表操作怎么保证数据一致性",你只需要回答"方法上加了事务注解,默认发生 RuntimeException 就会回滚",这就是标准的加分回答。
审核接口需要同时更新公告状态和写入审核日志,两步操作一起放进事务方法:
@Transactional(rollbackFor = Exception.class) public void audit(Long infoId, Long auditorId, int action, String reason) { Info info = infoMapper.selectById(infoId); if (info == null) { throw new BizException("公告不存在"); } if (action == 1) { info.setStatus(2); } else if (action == 2) { info.setStatus(4); info.setRejectReason(reason); } infoMapper.updateById(info); AuditLog log = new AuditLog(); log.setInfoId(infoId); log.setAuditorId(auditorId); log.setAction(action); log.setReason(reason); auditLogMapper.insert(log); }这里有一个容易被忽略的业务校验:审核人必须校验当前登录用户的角色是管理员。拦截器里只拿到了 userId,真正判断角色的动作放在 Service 层,从数据库查出用户之后检查 role 字段。前端隐藏按钮只是体验优化,后端鉴权才是真正的安全防线。
3.3 application.yml 和定时任务配置常见要点
配置文件是整个项目能不能跑起来的关键。我见过太多人卡在"改了密码还是连不上数据库"这种问题上。稳定的配置如下:
server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/school_info?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver servlet: multipart: max-file-size: 10MB max-request-size: 20MB redis: host: localhost port: 6379 mybatis-plus: configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl global-config: db-config: logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0useUnicode=true&characterEncoding=utf8是中文不乱码的前提,serverTimezone=Asia/Shanghai解决时区差八小时的问题。这两串参数看起来短,却是一个最经典又最容易被忽略的经验。如果你在本地日期总是跟数据库差 8 个小时,十有八九就是没写时区参数。
定时任务在 SpringBoot 里非常简单。启动类加@EnableScheduling,需要定时执行的方法加@Scheduled(cron = "0 0 1 * * ?")。校园信息发布平台最适合加两个定时任务:一个是每天凌晨扫描一下is_top = 1 且 top_expire_time < now的记录并自动取消置顶,另一个是每天晚上把 Redis 里的浏览量增量批量刷新到数据库。加完之后,项目里就有了"定时任务自动处理"的内容可写,论文也可以多一节功能描述。
4. 部署上线与踩坑实录
4.1 本地环境准备与打包部署
一个典型的毕设演示环境,需要准备这些东西:
| 软件 | 版本建议 | 说明 |
|---|---|---|
| JDK | 1.8 或 11 | 对应 SpringBoot 2.7.x |
| Maven | 3.6 以上 | 用 IDEA 内置的也行 |
| MySQL | 8.0 | 字符集选 utf8mb4 |
| Redis | 5.x 以上 | 做 Token 和浏览量缓存 |
| Node.js | 16+ | 只在前端开发时需要 |
打包发布阶段我反复验证过最省心的流程是:先在前端目录执行npm install和npm run build,把生成的dist内容复制到后端src/main/resources/static目录;然后执行 Maven 打包,命令是:
mvn clean package -DskipTests java -jar target/school-info-0.0.1-SNAPSHOT.jar这个步骤把前端静态资源和后端接口打成一个 jar 包,演示时只要目标电脑有 JDK 和 MySQL、Redis,直接java -jar就能启动,不需要装 Node,也不用额外起前端服务。这一个技巧就能解决答辩现场一半的崩溃问题。
数据库导入要注意的是:先建库、再导入 SQL。一般我会在项目源码里放一个db/init.sql,包含建库语句、建表语句和测试数据。这份文件本身也是交付物的一部分,老师问"数据从哪来的",你可以理直气壮地说"初始化脚本里的模拟数据,为了方便演示,我还准备了几个典型场景的测试数据"。
4.2 高频报错和排查思路速查表
这个项目我前后帮人排查过很多次,最常见的报错无外乎下面几类。我把对应关系整理成一个速查表:
| 报错现象 | 根本原因 | 解决办法 |
|---|---|---|
Cannot load driver class: com.mysql.cj.jdbc.Driver | MySQL 驱动依赖没引入或版本不匹配 | 确认 pom 里有 mysql-connector-java,且是 8.0.x |
Failed to configure a DataSource | application.yml 找不到数据源配置 | 检查 yml 文件位置和缩进,配置在 spring.datasource 下 |
| 启动后访问首页 404 | 前端 dist 没复制到 static 或路径不对 | 重新构建前端,确认资源打进 jar |
| 登录后接口全部 401 | 拦截器放行规则没配置 | 放行 /login、/register、静态资源、跨域预检 |
| 中文乱码,数据库存问号 | 连接串没指定字符集 | 在 url 中加 characterEncoding=utf8 |
| 上传图片超过大小限制 | 默认单文件 1MB | 配置 multipart maxFileSize |
| 控制台报跨域错误 | 前后端端口不同 | 配置 CorsFilter 或用 Nginx 代理 |
rcs: java.lang.NoSuchMethodError | 依赖版本冲突 | 检查 MyBatis Plus 和 SpringBoot 版本兼容性 |
除了表格,还有两个排查思路值得专门说。第一,遇到报错先把完整堆栈看清楚,别一看到红字就去搜索。有 80% 的启动问题都集中在数据源配置和依赖冲突上,堆栈里第一行就会指出问题位置。第二,前后端分离调试时打开浏览器 F12 的 Network 面板,看接口返回的真实状态码和响应内容,比盯控制台管用得多。
4.3 答辩演示流程和常见提问准备
演示环节的流畅程度直接决定最终成绩。我常用的演示顺序是这样:
- 从登录页开始,用管理员账号登录。
- 进入待审核列表,审核一条公告通过。
- 切到用户端首页,刷新后能看到刚审核通过的公告。
- 注册一个普通学生账号,演示发布一条寻物启事,状态变成待审核。
- 回到管理员端驳回这条寻物启事,填写驳回原因。
- 展示公告搜索、分页和置顶功能。
- 展示系统里预置的 15~20 条数据和统计亮点。
整个演示尽量控制在 5 到 8 分钟。说话语速放慢,点击动作清楚,页面能流畅展示自己的功能就够了。答辩老师通常不会深究算法,他们更喜欢问"为什么"。"为什么用 Redis 存 Token?""为什么审核和发布要分开?""MyBatis Plus 和 MyBatis 有什么区别?"这些问题在论文摘要和技术选型章节其实都有答案,提前准备一张口头表达的腹稿就好。
如果时间充裕,强烈建议在发布公告模块加一个"浏览量统计 + 热门公告排行"的功能。使用 Redis 的increment累加浏览量,再写一个接口按浏览量排序返回热门公告。这个功能工作量不大,但答辩时可以直接展示"热点排行"数据,系统从纯粹的 CRUD 里跳出来,体现了一定的业务思考。
最后再分享一个小经验
我踩过最大的坑,其实是"拿来主义"。每年都有同学拿着开源或学长学姐的源码改个名字就交,这样非常危险——答辩时老师随口问一个方法名是什么意思,当场就露馅。真正的做法是哪怕你把别人的代码跑通了,也要亲手把核心流程重写一遍,知道每一个表、每一个接口、每一段拦截器是干什么的。写完之后你会发现,SpringBoot 的自动装配、MyBatis Plus 的条件构造器、拦截器的执行顺序都有了一层实打实的理解,这些才是毕业设计真正留给你的东西。
像校园信息发布平台这种题目,做完的价值不在于题目本身有多惊艳,而在于你通过一个完整闭环证明了自己能独立完成一个软件系统。等这四件事都跑顺了,你会发现后面写简历、找工作面试,至少有故事可讲了。