☰
基于Spring Boot的古典舞在线交流平台设计与实现——涵盖视频课程与社区互动
2026/10/12 8:09:26 网站建设 项目流程

很多做Java毕设的同学,一到选题就头疼。管理系统太老套,电商项目又烂大街,最后答辩时老师看一眼标题就没兴趣了。今天分享这个古典舞在线交流平台,算是一条比较巧的思路——用Spring Boot做后端,把视频展示、课程管理、社区交流这些功能串起来,既贴合文化类热点,又覆盖了Spring Boot的核心知识点。我花了两周左右把完整项目跑通,代码、数据库脚本、部署文档都已整理完毕,免费分享出来,希望能给正在纠结毕设题目的同学一个参考。

1. 项目背景与核心需求拆解

1.1 为什么选“古典舞”这个垂直领域

做毕设选题,第一原则是“让老师觉得你有想法”。泛泛的“视频网站”或“在线教育平台”很难出彩,但加上“古典舞”这个垂直标签之后,整个项目的定位就变了:它是一个带有文化属性的垂直社区。这个定位带来的直接好处有三个:

  • 功能上天然需要视频播放、分类检索、用户互动、课程管理等多个模块,适合展示Spring Boot的综合能力。
  • 数据模型比普通博客或商城更有层次感,比如舞蹈视频需要按舞种、难度、适用人群分别归类。
  • 后续做扩展(比如直播教学、AI动作评分)时,叙事空间很大,答辩时有话可说。

当然,选什么垂直领域其实都可以,重点是要通过这个领域,把“为什么需要这个平台”讲清楚。古典舞在线交流平台的核心用户画像是舞蹈爱好者、培训班学员和独立舞蹈老师。他们的需求是:找优质教学视频、按水平筛选内容、互相交流练习心得、获取系统化课程。

1.2 核心功能模块梳理

从需求倒推,平台必须解决以下问题:

  • 用户体系:注册、登录、个人信息维护、角色区分(普通用户/管理员)。
  • 内容展示:古典舞视频的分类浏览、关键词搜索、热度排序。
  • 互动交流:视频评论、点赞、收藏。
  • 课程组织:按主题或难度组织的系列课程,用户可以查看课程详情和章节课时。
  • 后台管理:视频、课程、用户、评论的运营管理页面。

一句话概括:这是一个“内容 + 社区 + 管理后台”三位一体的典型业务系统。用Spring Boot实现这样的系统,技术路径成熟、参考资料丰富,非常适合作为毕设。

2. 技术选型与架构设计思路

2.1 后端技术栈:Spring Boot 2.x为核心

后端选择Spring Boot 2.7.x,搭配Spring MVC、Spring Data JPA、Spring Security。很多人纠结用MyBatis还是JPA,我的建议很直接:毕设项目,优先用Spring Data JPA。原因是实体关系映射写起来快,尤其在用户、视频、评论、课程这些表之间有关联查询时,JPA的@OneToMany、@ManyToOne能显著减少代码量。如果你对SQL更熟悉,用MyBatis-Plus也完全没问题,但要注意分页插件和LambdaQueryWrapper的版本兼容。

数据库选MySQL 8.0,ORM层用Hibernate自动建表策略(ddl-auto: update)开发期很方便,但最终交付时要记得改成validate或none,并附上完整的init.sql脚本,避免评审时被问“数据库表结构从哪来的”。

2.2 前端与交互方案

前端用Vue 2 + Element UI这套组合。为什么不是Vue 3?因为对毕设而言,Vue 2的生态最稳定,Element UI组件齐全,网上现成的后台管理模板也多,可以节省大量调样式的时间。页面结构如下:

  • 门户端(面向普通用户):首页视频流、视频详情页、课程列表页、个人中心。
  • 管理端(面向管理员):数据概览、视频管理、用户管理、评论审核。

如果你不想自己写前端,也可以直接使用开源的后台模板,比如vue-element-admin,只保留需要用的页面。但建议至少手写首页和视频详情页,这两个页面最能体现你对项目的理解。

2.3 整体架构与请求流转

项目采用前后端分离架构,通过RESTful API通信,JWT(JSON Web Token)做身份认证。整个请求流转过程是:

  • 前端发起请求,携带token(存储在localStorage中)。
  • 后端Spring Security过滤器链校验token,解析出用户ID和角色。
  • Controller接收参数,调用Service层处理业务逻辑。
  • Service层通过Repository与MySQL交互,返回数据。
  • 统一封装Result对象返回给前端,格式为{ code, message, data }。

这个架构清晰、扩展性好,而且答辩时可以顺势讲出“为什么用JWT而不是Session”——因为前后端分离后,Session跨域处理麻烦,JWT无状态、天然适合分布式部署。虽然毕设不要求分布式,但这个回答显得有深度。

3. 数据库设计与核心表结构

3.1 表设计概览

数据库是整个项目的地基。这里共设计6张核心表,表结构如下:

表名用途关键字段
user用户表id, username, password, nickname, avatar, role, create_time
video视频表id, title, cover_url, video_url, category, difficulty, description, play_count, like_count, status, create_time
comment评论表id, video_id, user_id, content, parent_id, create_time
course课程表id, title, description, cover_url, teacher, difficulty, status
course_section课节表id, course_id, title, video_url, duration
user_favorite收藏表id, user_id, video_id, create_time

这里有个设计细节容易被忽略:comment表中加parent_id字段,是为了支持“回复某条评论”的二级评论功能。相比把所有评论平铺,这种设计更接近真实社区产品。

视频表中加status字段(0下架 1上架)也很有必要。后台审核后上架,前台只展示上架内容,既符合内容管理需求,又能在答辩时体现你考虑过“内容安全”的问题。

3.2 索引与关联关系设计

单表数据量大了之后,索引就很重要了。video表的category和difficulty字段要建普通索引,因为前台会频繁按这两个条件筛选;create_time字段建议建索引,用于按最新排序。comment表的video_id也一定要建索引,否则详情页加载评论时会全表扫描。

实体关联关系上,用户和视频是@OneToMany(一个用户可上传多个视频);视频和评论是@OneToMany(一个视频有多条评论);课程和课节是@OneToMany(一个课程包含多个课时)。在JPA中,这些关系用注解声明后,查询时通过join fetch或实体导航方法就能拿到关联数据。

3.3 用户密码安全处理

用户表的password字段存储的必须是加密后的密文,绝对不能明文保存。使用BCrypt加密,Spring Security内置支持。注册时调用BCryptPasswordEncoder.encode(),登录时用matches()校验。

// 注册时加密 String encryptedPwd = passwordEncoder.encode(user.getPassword()); user.setPassword(encryptedPwd); // 登录时校验 boolean isMatched = passwordEncoder.matches(rawPassword, user.getPassword());

这里有一个常见错误:很多同学把password字段长度设置为50,但BCrypt加密后的字符串长度是60,导致插入数据库时报错。字段长度建议直接设为varchar(100),留足余量。

4. 核心功能模块实现详解

4.1 用户注册登录与JWT认证

用户模块的代码结构并不复杂,但它是整个项目的入口。核心流程是:

  • 注册接口:接收用户名、密码、昵称等参数,检查用户名是否唯一,加密密码,保存用户。
  • 登录接口:校验用户名密码,成功后生成JWT返回前端。
  • 获取当前用户接口:前端携带token访问,后端解析出用户信息。

JWT工具类通常包含三个方法:生成token、解析token、校验token。token中存放用户ID和用户名,设置7天有效期。

public String generateToken(Long userId, String username) { Date now = new Date(); Date expireDate = new Date(now.getTime() + 7 * 24 * 3600 * 1000); return Jwts.builder() .setSubject(username) .claim("userId", userId) .setIssuedAt(now) .setExpiration(expireDate) .signWith(SignatureAlgorithm.HS256, secretKey) .compact(); }

Spring Security配置类中,需要放行/api/auth/login和/api/auth/register接口,其余接口都要认证。前后端联调时,前端需要在Axios请求拦截器中统一加上Authorization: Bearer <token>头。

4.2 视频模块与分页搜索

视频列表页是用户进入平台后看到的第一个页面,性能直接关系到体验。使用Spring Data JPA的分页查询,接收page、size、category、difficulty、keyword参数。

public Page<Video> getVideoList(int page, int size, String category, String difficulty, String keyword) { Pageable pageable = PageRequest.of(page - 1, size, Sort.by(Sort.Direction.DESC, "createTime")); // 动态拼接查询条件 Specification<Video> spec = (root, query, cb) -> { List<Predicate> predicates = new ArrayList<>(); if (StringUtils.hasText(category)) { predicates.add(cb.equal(root.get("category"), category)); } if (StringUtils.hasText(difficulty)) { predicates.add(cb.equal(root.get("difficulty"), difficulty)); } if (StringUtils.hasText(keyword)) { predicates.add(cb.like(root.get("title"), "%" + keyword + "%")); } return cb.and(predicates.toArray(new Predicate[0])); }; return videoRepository.findAll(spec, pageable); }

注意一个细节:PageRequest.of的页码是从0开始的,而前端传过来的page通常从1开始,所以后端要page - 1。这个偏移量问题非常经典,调试接口时很容易忽略,一不注意就会导致前端第一页数据为空。

视频详情页的逻辑是:查询视频基本信息 + 查询该视频下的评论列表 + 播放数加1。播放数加1是典型的“写操作”,直接用UPDATE video SET play_count = play_count + 1 WHERE id = ?,不要先查出来再加再保存,避免并发丢失更新。

4.3 评论与点赞功能

评论功能是“交流平台”的核心。评论列表要按时间倒序,展示评论者昵称、头像、评论内容、评论时间。前端传入videoId和content,后端从token中解析出userId,组装评论实体保存。

二级评论的处理:如果parentId不为空,说明这是一条回复。在DTO中加一个replyCount字段,统计每条一级评论下的回复数量。这部分实现用的是@OneToMany映射,评论实体中增加@ManyToOne关联用户,查询时用join fetch一次性查出评论者信息,避免N+1查询问题。

点赞和收藏的功能逻辑类似:先判断是否存在记录,存在则取消,不存在则新增。通过user_favorite表中user_id和video_id的唯一约束保证数据一致性。点赞数变化时,同步更新video表中的like_count字段。

4.4 课程模块与课时组织

课程模块体现的是“系统化学习”的场景。课程实体包含标题、简介、封面、讲师、难度,课程下挂多个课时。前端课程详情页展示课时列表,每个课时是一个视频。

课程列表页的筛选条件通常包含难度和分类,课时数可以冗余存储在course表中的一个section_count字段,避免每次都要count子查询。这种“冗余字段”的设计在真实项目中很常见,答辩时提一句“用空间换查询效率”,会显得你理解业务。

后台的课程管理就是简单的CRUD,使用Element UI的表格组件展示课程列表,支持新增、编辑、上下架、删除操作。删除课程时要同时删除关联的课节记录,所以Service层要标注@Transactional,保证事务一致性。

5. 关键问题与踩坑记录

5.1 跨域问题导致前端请求失败

前后端分离项目最常见的坑就是跨域。Vue前端跑在8080端口,Spring Boot跑在8081端口,浏览器会拦截非同源的Ajax请求。解决方法是配置CORS(跨域资源共享)过滤器。

@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOriginPatterns("*") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("*") .allowCredentials(true) .maxAge(3600); } }

注意,allowCredentials(true)和allowedOriginPatterns("*")必须配套使用。如果用旧版的allowedOrigins("*"),会出现“origin cannot be null”的报错。

5.2 JWT token失效后前端无感知

token有效期为7天,但用户登录后如果一直不操作,7天后token过期,前端请求会返回401。最直接的处理方式是在前端Axios响应拦截器中判断HTTP状态码,遇到401就清除本地存储的token,跳转登录页。

如果想让体验更好,可以引入Refresh Token机制:在登录时返回两个token(访问token短时效、刷新token长时效),访问token过期后用刷新token去换取新token。毕设做到这个程度,属于加分项。

5.3 数据库方言问题导致分页SQL异常

切换MySQL版本后,有时Hibernate生成的SQL会带上limit ?,但方言配置不正确时,分页查询会报错。确保application.yml中配置的dialect为org.hibernate.dialect.MySQL8Dialect。如果你用的是MySQL 5.7,则改为MySQL5InnoDBDialect。

5.4 上传视频文件到服务器时的配置问题

课程管理或视频管理中,需要上传视频文件。Spring Boot默认单次请求最大文件大小是1MB,显然不够用。需要在配置文件中放大限制:

spring: servlet: multipart: max-file-size: 1024MB max-request-size: 1024MB

同时建议把视频文件存储到本地磁盘某个固定目录(如/data/upload/),数据库中保存访问URL,通过自定义静态资源映射暴露出去。

@Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/upload/**") .addResourceLocations("file:/data/upload/"); }

很多同学在答辩时演示上传功能,视频一大就报错,基本都是这个配置没改。

5.5 前后端时间格式不一致

后端返回的LocalDateTime默认格式是2025-01-15T10:30:00,前端显示时很丑。在application.yml中统一配置:

spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8

实体中的日期字段用@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")也可以,但建议以全局配置为主,注解只处理特殊字段。

5.6 懒加载异常LazyInitializationException

使用JPA的@ManyToOne关联查询时,如果在Controller层直接返回实体,Session已经关闭,关联对象为null,就会报LazyInitializationException。三种解决方案:

  • 在Service层事务内完成关联对象的初始化,把实体转为DTO再返回。
  • 查询时使用@EntityGraph或join fetch,预加载关联对象。
  • 配置spring.jpa.open-in-view: false,并在Service中封装好VO。

最推荐第一种,因为DTO封装还能隐藏掉密码等敏感字段。很多初学者偷懒直接把实体返回前端,虽然能跑,但密码字段也会被序列化出去,这是严重的低级错误。

6. 项目部署与演示要点

6.1 本地开发环境启动流程

整个项目的启动流程,需要按顺序操作:

  1. 启动MySQL,导入init.sql脚本,创建数据库和表。
  2. 修改application.yml中的数据库用户名密码。
  3. 启动Redis(如果项目中用到了缓存),这里没有依赖Redis,可以跳过。
  4. 启动Spring Boot应用,检查控制台日志,确认端口启动成功。
  5. 启动Vue前端,执行npm install安装依赖,再执行npm run serve。
  6. 浏览器访问前端地址,完成注册登录,浏览功能。

前端依赖安装失败是很常见的坑。如果npm install特别慢或报错,可以切换npm镜像源:

npm config set registry https://registry.npmmirror.com

6.2 云服务器部署的简易方案

如果想让老师通过外网访问你的项目,最简单的方式是买一台轻量云服务器,部署流程如下:

  • 安装JDK 1.8和MySQL。
  • 上传后端jar包,使用nohup java -jar app.jar &后台运行。
  • 安装Nginx,配置前端静态文件,并反向代理后端接口。
  • 配置安全组规则,开放80端口。

Nginx配置中,核心是处理前端路由的history模式和API代理:

server { listen 80; server_name your_server_ip; location / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://localhost:8081; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }

后端接口路径统一以/api开头,这样反向代理的规则写起来非常顺手。接口前缀统一这件事,在项目开发第一天就要约定好,不然后面改起来很麻烦。

6.3 答辩演示的技巧性准备

答辩演示时,不要光点页面,要一边操作一边解说。建议按以下顺序演示:

  • 从注册登录讲起,展示JWT认证的效果(比如未登录时访问个人中心会跳转)。
  • 进入首页,演示按分类筛选和关键词搜索。
  • 打开视频详情页,展示评论和点赞交互,强调数据实时刷新。
  • 进入后台管理,演示添加一个新视频或课程,再回前台刷新确认展示。
  • 打开数据库工具,展示数据变化情况,印证前后端联调的真实性。

老师通常会问“你这个项目最大的难点是什么”或“有哪些地方自己思考得比较多”。这时候可以重点讲两个点:一是视频播放数在多用户并发下的更新策略(用SQL自增而非读改写);二是JWT无状态认证相比Session的优势。只要能把这两个点讲清楚,项目的技术深度评价就不会低。

7. 经验总结与扩展方向

开发这个项目踩了不少坑,有几条经验非常值得分享:

  • 规划阶段先梳理核心流程再写代码。代码写了一半再改表结构,代价是巨大的。我先画出模块图和数据表关系,再动手写代码,整体推进非常顺。
  • 统一返回结构Result一定要从第一天就定好。如果一开始直接返回实体或Map,后面所有方法都要改,改动量会指数级上升。
  • 前端联调时要学会看Network面板和接口返回。很多问题不在代码而在网络请求,学会用浏览器开发者工具排查问题,是每个Java开发者必备的基本功。
  • 多写注释和多用日志。毕业设计的代码是可以被翻阅的,注释清晰是一个隐性加分项。

如果学有余力,可以在现有基础上扩展以下方向:

  • 引入ElasticSearch实现全文搜索,替代MySQL的like模糊查询,搜索体验会有明显提升。
  • 引入Redis缓存热门视频列表,降低数据库压力。这个点答辩时往“高并发优化”方向讲,很有说服力。
  • 引入WebSocket实现在线聊天,把“交流平台”的属性再强化一步。
  • 集成阿里云OSS保存视频文件,避免本地存储的磁盘空间限制。

最后回到实用层面:这个古典舞在线交流平台的完整源码、数据库脚本以及部署说明文档,我已经整理打包好了。代码可以直接导入IDEA运行,前端npm install后也能直接启动。有需要的同学可以关注获取下载方式。项目中还有不完善的地方,比如视频转码、评论敏感词过滤等,这些留给你自己发挥。写完这个项目,你不仅能交出一份合格的毕设,对Spring Boot的整体掌握也会上一个台阶。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询