SpringBoot+Vue视频网站系统:从零到一构建与核心模块解析

张开发
2026/4/22 20:57:17 15 分钟阅读

分享文章

SpringBoot+Vue视频网站系统:从零到一构建与核心模块解析
1. 技术选型与项目初始化在开始构建SpringBootVue视频网站系统之前我们需要明确技术栈的选择。后端采用SpringBoot框架这是目前Java领域最流行的微服务框架之一。它内置了Tomcat服务器简化了配置流程通过starter依赖可以快速集成各种功能模块。我实际项目中测试过用SpringBoot开发RESTful API的效率比传统Spring MVC提升约40%。前端选择Vue.js 3.x版本其组合式API让代码组织更灵活。搭配Vite构建工具热更新速度比Webpack快3-5倍这对需要频繁调试前端界面的场景特别友好。数据库选用MySQL 8.0主要看中其JSON数据类型支持和对事务的完善处理能力。开发环境配置建议JDK 17LTS版本Node.js 18.xMySQL 8.0IDE推荐IntelliJ IDEA VS Code组合初始化SpringBoot项目时这几个依赖必不可少dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter/artifactId version2.2.2/version /dependency dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId scoperuntime/scope /dependency /dependencies2. 用户认证模块实现用户系统是视频网站的基础我采用JWTSpring Security的方案。踩过几个坑后发现单纯用Session在分布式环境下会有问题而JWT的无状态特性更适合前后端分离架构。核心实现步骤设计用户表时一定要加盐加密存储密码CREATE TABLE user ( user_id bigint NOT NULL AUTO_INCREMENT, username varchar(50) NOT NULL, password varchar(100) NOT NULL COMMENT SHA256加盐加密, salt varchar(20) NOT NULL, avatar varchar(255) DEFAULT NULL, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (user_id), UNIQUE KEY idx_username (username) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;密码加密工具类实现public class PasswordUtil { private static final SecureRandom random new SecureRandom(); public static String generateSalt() { byte[] salt new byte[16]; random.nextBytes(salt); return Hex.encodeHexString(salt); } public static String encrypt(String password, String salt) { return DigestUtils.sha256Hex(password salt); } }Spring Security配置关键代码Configuration EnableWebSecurity public class SecurityConfig { Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() .antMatchers(/api/auth/**).permitAll() .anyRequest().authenticated() .and() .addFilter(new JwtAuthenticationFilter(authenticationManager())) .addFilter(new JwtAuthorizationFilter(authenticationManager())); return http.build(); } }3. 视频管理模块开发视频处理是系统的核心功能需要考虑文件上传、转码、封面生成等复杂场景。我的经验是使用FFmpeg进行视频处理配合MinIO作为对象存储。上传接口实现要点PostMapping(/upload) public Result uploadVideo(RequestParam(file) MultipartFile file, RequestHeader(X-Token) String token) { // 验证用户权限 Long userId jwtUtil.getUserId(token); if(userId null) { return Result.error(403, 未授权访问); } // 校验文件类型 String contentType file.getContentType(); if(!Arrays.asList(video/mp4, video/quicktime).contains(contentType)) { return Result.error(400, 不支持的视频格式); } // 生成唯一文件名 String filename UUID.randomUUID() getFileExtension(file.getOriginalFilename()); // 上传到MinIO try { minioClient.putObject( PutObjectArgs.builder() .bucket(videos) .object(filename) .stream(file.getInputStream(), file.getSize(), -1) .contentType(contentType) .build()); } catch (Exception e) { log.error(视频上传失败, e); return Result.error(500, 上传失败); } // 保存到数据库 Video video new Video(); video.setUserId(userId); video.setTitle(file.getOriginalFilename()); video.setUrl(filename); videoService.save(video); // 异步处理视频转码 videoProcessingService.processVideoAsync(video.getId()); return Result.success(video); }视频转码的异步处理方案使用Spring的Async注解实现异步方法通过Redis队列管理转码任务FFmpeg命令行参数示例ffmpeg -i input.mp4 -c:v libx264 -crf 23 -preset fast -c:a aac -b:a 128k -movflags faststart output.mp44. 前端Vue实现技巧前端架构采用Vue3 Pinia Element Plus组合。在开发视频列表页时需要注意以下几点性能优化虚拟滚动优化长列表template el-table-v2 :columnscolumns :datavideos :width800 :height600 :row-height80 fixed / /template script setup import { ref, onMounted } from vue import { getVideoList } from /api/video const columns [ { key: title, title: 标题, width: 200 }, { key: author, title: 作者, width: 150 }, { key: views, title: 播放量, width: 100 } ] const videos ref([]) onMounted(async () { const res await getVideoList() videos.value res.data }) /script视频播放器集成方案使用video.js实现跨浏览器兼容添加清晰度切换功能实现记忆播放功能// 播放器初始化 import videojs from video.js const player videojs(my-video, { controls: true, autoplay: false, preload: auto }) // 记录播放进度 player.on(timeupdate, () { localStorage.setItem(video_${videoId}, player.currentTime()) })5. 论坛互动功能实现社区互动是提升用户粘性的关键。我采用WebSocket实现实时消息通知结合敏感词过滤机制保证内容安全。评论系统数据库设计CREATE TABLE comment ( id bigint NOT NULL AUTO_INCREMENT, content text NOT NULL, user_id bigint NOT NULL, video_id bigint NOT NULL, parent_id bigint DEFAULT NULL COMMENT 回复的评论ID, create_time datetime DEFAULT CURRENT_TIMESTAMP, status tinyint DEFAULT 1 COMMENT 1-正常 0-删除, PRIMARY KEY (id), KEY idx_video (video_id), KEY idx_user (user_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;WebSocket配置核心代码Configuration EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { Override public void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker(/topic); config.setApplicationDestinationPrefixes(/app); } Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint(/ws) .setAllowedOrigins(*) .withSockJS(); } }敏感词过滤实现public class SensitiveFilter { private static final TrieNode root new TrieNode(); static { // 初始化敏感词字典 ListString words Arrays.asList(敏感词1, 敏感词2); for (String word : words) { addWord(word); } } public static String filter(String text) { if (StringUtils.isEmpty(text)) return text; StringBuilder result new StringBuilder(); TrieNode tempNode root; int begin 0; int position 0; while (position text.length()) { char c text.charAt(position); tempNode tempNode.getSubNode(c); if (tempNode null) { result.append(text.charAt(begin)); begin; position begin; tempNode root; } else if (tempNode.isKeywordEnd()) { result.append(***); begin position; tempNode root; } else { position; } } result.append(text.substring(begin)); return result.toString(); } }6. 性能优化实战在高并发场景下我通过以下手段提升系统性能多级缓存策略本地缓存(Caffeine) Redis分布式缓存视频元数据缓存示例Cacheable(value video, key #id) public Video getById(Long id) { return videoMapper.selectById(id); }数据库优化为常用查询字段添加索引大表分库分表策略读写分离配置前端资源优化视频文件CDN加速Webpack分包加载图片懒加载实现Nginx配置示例server { listen 80; server_name example.com; location /videos/ { proxy_pass http://minio-server; proxy_set_header Host $host; proxy_cache my_cache; proxy_cache_valid 200 302 24h; } location / { proxy_pass http://vue-server; proxy_set_header Host $host; } }7. 项目部署方案推荐使用Docker Compose进行容器化部署这是我验证过的高效方案docker-compose.yml关键配置version: 3.8 services: backend: build: ./backend ports: - 8080:8080 environment: - SPRING_PROFILES_ACTIVEprod - DB_URLjdbc:mysql://mysql:3306/video_db depends_on: - mysql - redis frontend: build: ./frontend ports: - 80:80 mysql: image: mysql:8.0 environment: - MYSQL_ROOT_PASSWORDyourpassword - MYSQL_DATABASEvideo_db volumes: - mysql_data:/var/lib/mysql redis: image: redis:6 ports: - 6379:6379 volumes: mysql_data:部署流程注意事项先启动基础设施服务MySQL、Redis构建SpringBoot应用镜像时要包含Maven打包步骤Vue项目需要先执行npm build建议使用Nginx作为前端静态资源服务器8. 常见问题排查在开发过程中我遇到过几个典型问题及解决方案跨域问题后端配置CORS前端开发环境配置代理Nginx反向代理方案文件上传大小限制# SpringBoot配置 spring.servlet.multipart.max-file-size100MB spring.servlet.multipart.max-request-size100MB视频播放卡顿检查CDN加速是否生效使用HLS分片传输前端预加载策略数据库连接池耗尽spring.datasource.hikari.maximum-pool-size20 spring.datasource.hikari.leak-detection-threshold5000JWT过期处理实现refresh token机制前端自动刷新token逻辑过期错误码统一处理在项目开发过程中保持日志的完整记录非常重要。我习惯使用LogbackELK组合搭建日志系统当出现问题时可以快速定位。比如视频转码失败时通过追踪日志发现是FFmpeg路径配置错误修正后问题立即解决。

更多文章