校园网毕设入门实战:从零搭建高可用学生信息管理系统
摘要:许多计算机专业学生在完成校园网毕设时,常因缺乏工程经验而陷入架构混乱、部署困难或安全漏洞等问题。本文面向新手,基于 Spring Boot + MyBatis + Vue 技术栈,提供一套可落地的全栈开发方案,涵盖前后端分离设计、RESTful API 规范、基础权限控制及 Docker 容器化部署。读者将掌握模块化开发流程,避免常见安全与性能陷阱,快速交付一个结构清晰、易于维护的毕业设计项目。
1. 校园毕设常见痛点
- 技术选型盲目:听说“Spring 流行”就一窝蜂上,结果连 IoC 都说不清;写到一半发现 Django 生态更省代码,却已骑虎难下。
- 前后端耦合:JSP 里写 SQL、HTML 里嵌 JavaScript,调试时浏览器、IDE、控制台三线刷屏,报错定位全靠猜。
- 无日志监控:服务器 500 了只能
System.out.println,老师问“为什么崩”——答“不知道,重启试试”。 - 部署差异:本地 Windows 跑得好好的,上到 CentOS 7 全 404;路径大小写、JDK 版本、MySQL 字段编码集体翻车。
- 安全盲区:密码明文、SQL 拼接、CORS 全开,答辩现场被老师当场注入,社死程度直接拉满。
2. 主流技术栈对比(毕业设计够用维度)
| 维度 | Django | Spring Boot | Laravel |
|---|---|---|---|
| 学习曲线 | 低,自带 admin | 中,注解多 | 低,文档丰富 |
| 生态插件 | 多,但 Python 主机少 | 多,云厂商支持好 | 多,PHP 主机便宜 |
| 就业关联 | 算法/爬虫加分 | 企业级刚需 | Web 中小厂 |
| 打包部署 | 简单,uwsgi | 需理解 JVM | 简单,php-fpm |
结论:
- 想快速出活、以后可能走算法路线 → Django
- 想贴合企业技术栈、简历加分 → Spring Boot
- 想低成本虚拟主机上线 → Laravel
本文选Spring Boot + MyBatis + Vue,理由:校园网服务器多为 CentOS,Java 系教程最多,方便抄作业。
3. 核心实现细节
3.1 数据库表结构(MySQL 8)
CREATE TABLE student ( id BIGINT PRIMARY KEY AUTO_INCREMENT, stu_num VARCHAR(20) NOT NULL UNIQUE COMMENT '学号', name VARCHAR(30) NOT NULL, gender TINYINT NOT NULL DEFAULT 1 COMMENT '1男 2女', mobile VARCHAR(11), email VARCHAR(50), password CHAR(60) NOT NULL COMMENT 'BCrypt 密文', role TINYINT NOT NULL DEFAULT 1 COMMENT '1学生 2管理员', gmt_create DATETIME DEFAULT CURRENT_TIMESTAMP, gmt_modified DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;3.2 RESTful API 规范
- 统一前缀
/api/v1 - 资源名复数
/students - 动作由 HTTP 动词表达
- 返回统一包装类
Result<T>
3.3 用户认证思路
- 登录成功后生成 JWT(过期 2h),返回前端
- 前端每次在
Authorization: Bearer <token>带过来 - 后端
HandlerInterceptor统一验签,线程局部变量保存userId - 权限:方法级
@RequireRole("ADMIN")自定义注解,搭配 AOP 切面
4. 代码示例(Clean Code 版)
4.1 Controller 层
@RestController @RequestMapping("/api/v1/students") @RequiredArgsConstructor public class StudentController { private final StudentService studentService; /** * 分页查询学生列表 * GET /api/v1/students?page=1&size=10 */ @GetMapping public Result<PageInfo<StudentDTO>> list(@RequestParam PageParam pageParam) { return Result.success(studentService.pageStudents(pageParam)); } /** * 新增学生 * POST /api/v1/students */ @PostMapping @RequireRole("ADMIN") public Result<Long> create(@Valid @RequestBody StudentCreateReq req) { Long id = studentService.createStudent(req); return Result.success(id); } /** * 修改学生 * PUT /api/v1/students/{id} */ @PutMapping("/{id}") @RequireRole("ADMIN") public Result<Void> update(@PathVariable Long id, @Valid @RequestBody StudentUpdateReq req) { studentService.updateStudent(id, req); return Result.success(); } /** * 删除学生 * DELETE /api/v1/students/{id} */ @DeleteMapping("/{id}") @RequireRole("ADMIN") public Result<Void> delete(@PathVariable Long id) { studentService.deleteStudent(id); return Result.success(); } }4.2 Service 层
@Service @RequiredArgsConstructor public class StudentService { private final StudentMapper studentMapper; private final PasswordEncoder passwordEncoder; @Transactional public Long createStudent(StudentCreateReq req) { // 1. 学号唯一校验 if (studentMapper.existsByStuNum(req.getStuNum())) { throw new BizException("学号已存在"); } // 2. 实体转换 Student entity = Student.builder() .stuNum(req.getStuNum()) .name(req.getName()) .gender(req.getGender()) .mobile(req.getMobile()) .email(req.getEmail()) .password(passwordEncoder.encode(req.getPassword())) .role(StudentRole.STUDENT) .build(); // 3. 落库 studentMapper.insert(entity); return entity.getId(); } public PageInfo<StudentDTO> pageStudents(PageParam pageParam) { PageHelper.startPage(pageParam.getPage(), pageParam.getSize()); List<Student> list = studentMapper.selectAll(); return PageInfo.of(list).map(s -> convertDTO(s)); } private StudentDTO convertDTO(Student s) { return StudentDTO.builder() .id(s.getId()) .stuNum(s.getStuNum()) .name(s.getName()) .gender(s.getGender()) .build(); } }要点:
- 所有业务异常抛出自定义
BizException,由全局异常处理器统一转 JSON - 用
PageHelper做物理分页,别select *再内存分页 - 实体与 DTO 严格分层,避免把密码字段传到前端
5. 基础安全 & 性能
5.1 SQL 注入
MyBatis 用#{}占位符即可,勿用${}拼接;额外打开 MySQL 日志,观察实际 SQL。
5.2 密码加密
Spring Security 的BCryptPasswordEncoder已足够,自带盐值,毕业设计无需自己写算法。
5.3 连接池
默认 HikariCP 已很好,参数可按校园网并发微调:
spring: datasource: hikari: max-pool-size: 20 min-idle: 5 connection-timeout: 10005.4 前端 CORS
Vue 开发时vite.config.js配代理即可,生产环境由 Nginx 统一转发,禁止后端@CrossOrigin("*")放飞。
6. 生产环境避坑指南
- 本地开发用 Windows 不区分大小写,Linux 区分。统一小写路径、数据库名。
- 服务器内存 2G 时,
-Xmx512m足够,别照搬博客 4G 参数。 - Nginx 反向代理后一定加
proxy_set_header Host $host;否则 Swagger 会 404。 - Git 提交写中文,方便回滚;但千万别把
.env密钥文件 push 到 GitHub。 - 数据库时区:服务器
CST与UTC混用会导致时间对不上,连接串加serverTimezone=Asia/Shanghai。 - 备份:写个
mysqldump脚本 +crontab,每天凌晨 3 点打包,答辩前误删能救命。
7. 快速容器化部署(Docker 三件套)
Dockerfile把 Spring Boot 打成镜像docker-compose.yml一次拉起 MySQL、Redis、App- 校园网服务器若端口 80/443 被封,可改 8443,Nginx 配 SSL 自签证书,浏览器导入根证书即可
示例片段:
version: "3" services: mysql: image: mysql:8 environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: campus volumes: - ./sql:/docker-entrypoint-initdb.d ports: - "3306:3306" app: build: . depends_on: - mysql environment: SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/campus ports: - "8080:8080"8. 可扩展方向
- 每日签到:Redis Bitmap 存 90 天记录,占内存 < 1 KB/系
- 报表导出:用 EasyExcel 写
.xlsx,百万行以内校园网无压力 - 文件上传:OSS 学生价 9 元/年,比存在服务器省心
- 移动端:Uni-app 直接复用 REST,打包成微信小程序,答辩加分
9. 小结 & 动手建议
把本文代码拉下来,先跑通登录→分页→新增三步,再逐步加角色、日志、Docker。每完成一个功能就git tag v0.1打标签,回滚不心慌。毕业设计不是写“宇宙级”系统,而是让评委看到你思路清晰、能跑起来、敢讲细节。现在就git clone开干,答辩那天你会感谢今天踩过的坑。