ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

前后端分离多媒体共享平台系统:SpringBoot+Vue+MyBatis+MySQL实战

前后端分离多媒体共享平台系统:SpringBoot+Vue+MyBatis+MySQL实战 前后端分离武理多媒体信息共享平台系统SpringBootVueMyBatisMySQL完整源码部署教程高校里的多媒体资源管理说简单也简单说复杂也复杂。说简单无非是上传、存储、播放、下载这几件事说复杂则是权限、分类、检索、防滥用、多端兼容这些细节叠加在一起之后的工程问题。我前后做过好几个类似的信息共享平台项目这套基于 SpringBoot Vue MyBatis MySQL 的前后端分离架构算是在校园场景里跑得最稳、改动成本最低的一套组合。这套系统解决的典型痛点很明确同一个院系甚至同一个班级内部课件、实验视频、参考资料散落在各个群文件和网盘链接里没有统一的入口没有检索能力也没有访问控制。而一个前后端分离的多媒体共享平台恰好能把“资源集中管理”和“权限分层控制”这两件事一次讲清楚。无论是课程设计、毕业设计还是实验室里确实需要一个内网资源库这套代码和部署思路都可以直接拿去用。接下来我会从项目设计思路、核心模块拆解、部署实操、常见坑排查这四个方面完整过一遍保证你拿到源码之后不是只会跑起来而是真正能改、能调、能上线。1. 项目整体设计与思路拆解1.1 为什么一定要用前后端分离先说结论校园多媒体共享平台这种项目前后端分离不是赶时髦而是业务形态决定的。这类系统的使用场景很有特点PC 端管理 移动端浏览。老师和管理员要上传资源、审核内容、管理用户这是在电脑上完成的学生下课掏出手机想看课件和实验视频这是在移动端完成的。如果你用传统的服务端渲染模板比如 JSP、Thymeleaf那你在手机端看到的内容形态基本被后端模板锁死了想做一个适合小屏幕的交互界面就得重新写一套模板维护成本成倍增加。前后端分离之后后端只提供 JSON 接口前端不管是 Vue 的 Web 页面还是以后要套一个小程序都只需要对接同一套后端 API。这个项目里我用 Vue 2 Element UI 做管理后台和用户端接口统一走 RESTful 风格返回 JSON 数据。Vue 负责渲染和交互SpringBoot 负责业务逻辑和数据读写互不干扰出了问题也容易定位。另一个实际原因是团队协作。做毕设或者课程设计时前端一个人、后端一个人或者你自己一个人分阶段做是常态。前后端分离意味着你可以先定义好接口文档然后前端用 mock 数据开发页面后端用 Postman 调试接口两边并行推进不需要等某一方完全做好。这一点在赶工期的场景下价值非常大。1.2 技术选型背后的理由这套系统的技术栈乍一看是 Java Web 的“标准答案”SpringBoot Vue MyBatis MySQL。但标准答案之所以成为标准答案恰恰是因为它在解决这一类问题上经过了大量验证。SpringBoot选它而不是传统的 SSM 逐项配置核心原因是 SpringBoot 的自动装配机制把 Spring、SpringMVC 的繁琐配置大幅简化。版本选择上我用的是 SpringBoot 2.7.x。这里要特别提醒一句不要一上来就追 SpringBoot 3.x因为 3.x 强制要求 JDK 17并且 Jakarta EE 命名空间变化会导致部分老教程和依赖不兼容。在学习型和校园型项目中稳定压倒一切。Vue 2 Element UIVue 3 已经很成熟了但这个项目用 Vue 2 不是我保守而是 Element UI 和现有的成熟组件生态在 Vue 2 下最省心。如果你是从零学起Vue 2 的教程资料最多遇到问题搜解决方案最容易。当然如果你对 Vue 3 更熟改成 Vue 3 Element Plus 在架构上完全没问题。MyBatis为什么要用 MyBatis 而不是 JPA因为多媒体信息共享平台的查询场景高度定制化。比如“按资源类型 上传时间 关键词模糊搜索 分页”这种组合条件MyBatis 的 XML 动态 SQL 写起来非常直观你能精确控制每一条 SQL 的执行行为。JPA 虽然写基础 CRUD 快但一旦涉及多表关联和动态条件调试成本明显上升。MySQL这个不用多说校园项目的绝对主力。需要强调的一点是MySQL 的字符集和排序规则在建库那一刻就要定好。推荐使用utf8mb4utf8mb4_general_ci因为资源标题和描述里随时可能出现表情符号或者特殊字符utf8mb4才能完整支持。1.3 整体架构与表结构设计这套系统的架构分为三层前端展示层Vue 页面、后端接口层Controller Service Mapper、数据存储层MySQL 本地文件存储。数据库表的设计是整套系统的地基。我总共设计了 6 张核心表表名用途关键字段user用户信息id, username, password, role, avatar, create_timecategory资源分类id, name, parent_id, sort_orderresource资源信息id, title, type, url, cover, summary, uploader_id, category_id, status, download_count, create_timeresource_comment资源评论id, resource_id, user_id, content, create_timeresource_like资源点赞id, resource_id, user_id, create_timeoperation_log操作日志id, user_id, action, target_id, detail, create_time资源表是整个系统的核心几个关键字段我要单独解释一下。type字段区分资源类型1 表示视频2 表示文档3 表示图片4 表示压缩包。这个字段决定了前端渲染方式——视频走播放器组件文档走预览组件图片直接展示缩略图。status字段是审核状态0 待审核、1 已发布、2 已驳回。我在设计时要求所有用户上传的资源必须先经过管理员审核才能公开显示。这个设计能有效避免有人上传不合适的内容在校园网环境里这个模块的存在很重要。关于文件本身的存储我选择了本地磁盘存储 数据库记录元数据的方案而不是直接把文件存进 MySQL 的 BLOB 字段。原因很简单文件存数据库会导致表体积膨胀极快备份和查询都会变得很慢本地存储目录结构清晰比如按日期分目录/upload/2025/05/配合 Nginx 做静态资源映射访问效率高实现也简单。文件路径存在 resource 表的url字段里前端通过拼接得到完整访问地址。2. 核心功能模块拆解与实现要点2.1 用户登录与权限控制用户体系分为三个角色管理员admin、上传者teacher、普通用户student。登录认证用的是 JWTJSON Web Token没有用 Session。JWT 方案在前后端分离场景下有几个天然优势无状态、跨域友好、适合移动端复用。用户登录成功后后端签发一个有效期为 24 小时的 token 返回给前端前端存储在 localStorage 中每次请求在请求头里带上Authorization: Bearer token后端通过拦截器解析 token识别用户身份和角色。具体实现上后端会用 SpringBoot 的拦截器HandlerInterceptor统一处理 token 校验同时配合一个自定义注解RequireRole来做细粒度的权限控制。比如管理员审核资源的接口方法上标注RequireRole(admin)上传者调用上传接口标注RequireRole(teacher)普通用户就只能访问公开的资源列表和详情。这里有一个非常容易出错的细节token 失效后的前端处理。如果后端接口返回 401前端 axios 的响应拦截器里必须统一跳转登录页并清除本地缓存否则用户会看到一个报错页面之后系统就“假死”了。我在这个项目里的做法是// axios 响应拦截器 service.interceptors.response.use( response { return response }, error { if (error.response error.response.status 401) { localStorage.removeItem(token) localStorage.removeItem(userInfo) router.push(/login) } return Promise.reject(error) } )密码存储用的是 BCrypt 加密Spring Security 框架里的BCryptPasswordEncoder可以直接拿来用。记住一个原则任何情况下都不要自己写加密算法数据库里更不能存明文密码。BCrypt 每次生成的哈希值不同但校验结果是稳定的这让暴力破解的成本大幅提升。2.2 资源上传与多媒体处理上传功能是整个系统里最“硬件”的部分。前端我用的是 Element UI 的el-upload组件通过action属性指向后端上传接口。上传的同时前端会把文件类型、标题、简介、所属分类这些信息一起通过表单提交。后端上传接口的处理逻辑要重点讲一下因为这里涉及文件大小限制和存储路径的组织。首先在 SpringBoot 配置文件中设置上传限制spring: servlet: multipart: max-file-size: 500MB max-request-size: 550MB这里是第一次踩坑的地方。SpringBoot 默认的上传文件大小限制只有1MB。如果你不调整这两个配置上传稍大一点的实验视频就直接报 413 错误。而多媒体平台上 50MB 以上的视频非常常见所以我把单个文件限制放宽到 500MB这个值在大多数校园网场景下够用了。接收文件后后端会把 MultipartFile 保存到本地的指定目录目录按日期组织避免单个目录下文件过多导致 IO 变慢String dateFolder LocalDate.now().toString().replace(-, /); String realPath uploadDir / dateFolder; File dir new File(realPath); if (!dir.exists()) dir.mkdirs(); String fileName UUID.randomUUID().toString().replace(-, ) - originalFilename; File dest new File(dir, fileName); file.transferTo(dest);这里我故意用 UUID 重命名文件而不是保留原始文件名。原因有两个一是避免中文文件名和特殊字符在 URL 访问时产生编码问题二是防止同名文件互相覆盖。原始文件名会被存入数据库的另一个字段在下载时通过接口返回给前端做展示。视频上传后还有一个加分项封面图生成。如果是视频文件我会调用ffmpeg命令截取第一帧作为默认封面然后存入数据库的cover字段。这个操作虽然只多了十几行代码但用户体验提升非常明显——资源列表页不再是清一色的灰底图标而是真实的视频画面。2.3 资源检索与分类筛选检索模块是用户感知系统“好不好用”的第一道关口。我的实现方式是分类树 关键字搜索 分页查询三件套。后端查询接口通过 MyBatis 的动态 SQL 实现组合条件查询。核心 mapper 文件里这么写select idsearchResources resultTypecom.example.entity.Resource SELECT * FROM resource where if testkeyword ! null and keyword ! AND (title LIKE CONCAT(%, #{keyword}, %) OR summary LIKE CONCAT(%, #{keyword}, %)) /if if testcategoryId ! null and categoryId ! 0 AND category_id #{categoryId} /if if testtype ! null and type ! 0 AND type #{type} /if if teststatus ! null AND status #{status} /if /where ORDER BY create_time DESC /selectLIKE 模糊查询在数据量小的时候性能没有问题当资源量超过几万条后可以考虑引入 Elasticsearch但校园场景下 MySQL 完全扛得住。这里要提醒一个 MySQL 排序的常见问题ORDER BY create_time 在数据量大时无法走索引因为create_time默认是 DATETIME 类型你需要给create_time字段加一个普通索引并且如果有 WHERE 条件优先保证 WHERE 条件涉及的字段有索引。不建议在一张还在迭代的表上直接建联合索引等字段稳定了再优化不迟。前端分类筛选我做了两级分类一级分类是“学科大类”如计算机、电子、机械二级分类是“资源类型”课件、视频、文献、软件。这样用户可以按学科树逐级下钻也可以直接用顶部的搜索框全局搜索。两种方式互补覆盖了“浏览型”和“目标型”两类用户需求。2.4 视频播放与下载权限视频播放是本平台最核心的功能。前端我用video.js组件来做播放器支持 mp4 格式的直接流式播放。HTML5 的 video 标签天生支持Range请求也就是拖拽播放进度。这是浏览器和 Nginx 自动完成的不需要额外写代码。这里有一个可以分享的冷门技术点如果你需要播放 m3u8 格式的视频流比如老师上传的录课视频转成了 HLS 流需要在前端引入hls.js库才能让浏览器播放。安装方式很简单npm install hls.js在 Vue 组件里这样接入import Hls from hls.js playM3u8(url) { if (Hls.isSupported()) { const hls new Hls() hls.loadSource(url) hls.attachMedia(this.$refs.video) } }下载权限的控制我用的是一个简单但实用的方案登录用户才有下载权限下载操作在数据库中记录日志。用户点击下载按钮时前端请求后端获取真实文件地址后端校验 JWT 后返回一个临时授权地址拼接一个短暂有效的签名参数而不是直接暴露静态资源目录的完整路径。这样既能控制未登录用户的访问也能在后续统计“哪个资源最受欢迎”时拿到真实数据。3. 本地实战从零搭建与部署全流程3.1 环境准备与版本对应关系项目排坑的第一步就是要确保环境版本匹配这大概是我被问过最多的问题。先给出我验证过的版本组合软件版本说明JDK1.8 或 11不要用 17除非你上 SpringBoot 3.xMaven3.6.3 或 3.8.x3.9 以上需要 JDK 11Node.js14.x ~ 16.xVue 2 项目用这个范围最稳MySQL5.7 或 8.0推荐 8.0字符集选 utf8mb4Nginx1.20用于部署前端静态文件和代理后端接口很多人忽略的是 Node.js 的版本问题。Vue 2 项目如果装了 node-sass 依赖而你的 Node.js 版本过高比如 18node-sass 编译非常容易失败。我试过的方案里Node 14 npm 6 搭配 Vue 2 Element UI 是最省心的组合。如果项目用的是 dart-sass那版本要求会宽松一些但为了不折腾还是建议直接用 14。3.2 数据库初始化与导入拿到源码后第一步不是改代码而是先建库。项目里一般会附带一个sql目录里面有初始化脚本。命令行方式执行mysql -u root -p init.sql如果你的 MySQL 装在 Windows 上没有配好环境变量可以用 Navicat 这一类图形化工具新建数据库后右键“运行 SQL 文件”即可。关于 MySQL 安装我多说一句踩过的坑MySQL 8.0 默认认证插件是caching_sha2_password而一些老版本的驱动比如 5.1.x 的 mysql-connector-java不兼容。如果你的项目启动时报连接错误要么在 pom.xml 里升级驱动版本到 8.0.x要么在创建用户时指定老认证插件CREATE USER appuserlocalhost IDENTIFIED WITH mysql_native_password BY yourpassword;强烈建议直接用最新版驱动因为后续省事很多。3.3 后端启动配置与常见报错解决后端项目导入 IDEA 后Maven 会自动下载依赖。这里要等一会儿如果网络状况不好建议把 Maven 镜像换成阿里云镜像在settings.xml里加一段mirror idaliyun/id mirrorOfcentral/mirrorOf urlhttps://maven.aliyun.com/repository/public/url /mirror然后修改application.yml中的数据库连接配置server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/media_share?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8mb4 username: root password: 你的数据库密码 driver-class-name: com.mysql.cj.jdbc.Driver mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.example.entity configuration: map-underscore-to-camel-case: true file: upload-dir: /data/media_uploadmap-underscore-to-camel-case: true这个配置非常重要。它让数据库里的create_time字段自动映射到 Java 实体类的createTime属性不用你手动写繁琐的 resultMap。如果你发现查询返回的字段全是 null八成是这个配置没开。启动类直接运行main方法后端就起来了。验证接口是否通浏览器访问http://localhost:8080/api/health如果能返回{status:ok}就说明环境没问题。如果遇到端口被占用的情况比如 8080 被其他程序占用了两种方案改application.yml里的server.port或者启动时用命令行指定java -jar app.jar --server.port80813.4 前端环境配置与跨域处理前端项目在 idea 或者 VSCode 里打开先安装依赖npm install这里经常出问题的是依赖下载超时或者某个包安装失败。解决办法就是把 npm 源切换到国内镜像npm config set registry https://registry.npmmirror.com安装完成后启动开发服务器npm run dev正常情况下终端会显示App running at: http://localhost:8081。但是此时前端页面里的接口请求地址还是后端的 8080 端口这就涉及跨域问题CORS。我在开发环境里有两个处理方案两个都用上了方案一在 Vue 项目的vue.config.js里配置代理。这是开发环境的标配方案module.exports { devServer: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } }方案二在后端配置全局跨域。这个方案的价值是让前端也可以直接访问后端接口特别是在你临时调试或者开发环境没有代理的情况下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)就不能用allowedOrigins(*)必须用allowedOriginPatterns(*)。这是 Spring 的一个校验规则直接写allowedOrigins(*)会启动报错。3.5 生产环境发布打包与 Nginx 部署开发环境跑通之后真正的挑战在部署。前后端分离项目在生产环境的标配是前端打包成静态文件扔给 Nginx后端打成 Jar 包挂在服务器上。后端打包前注意确认application.yml里的数据库链接已经是生产库地址、上传目录是服务器上的真实路径。然后执行mvn clean package -DskipTests在target目录下会生成xxx.jar。在服务器上的启动方式nohup java -jar media-share-1.0.jar app.log 21 用nohup让进程在关闭终端后继续运行日志输出到app.log方便排查问题。前端打包npm run build生成dist目录把dist目录里的所有文件上传到服务器任意一个目录比如/var/www/media_share然后在 Nginx 的配置文件里做静态资源映射和后端 API 反向代理server { listen 80; server_name your-domain.com; # 前端静态资源 root /var/www/media_share; index index.html; # 解决 Vue Router 的 history 模式刷新 404 问题 location / { try_files $uri $uri/ /index.html; } # 后端 API 反向代理 location /api/ { proxy_pass http://127.0.0.1:8080/api/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } # 上传文件的静态访问路径 location /files/ { alias /data/media_upload/; add_header Access-Control-Allow-Origin *; } }这里有一个我最初部署时漏掉的关键项Vue Router 如果不使用 hash 模式即 URL 里没有#刷新页面时会向 Nginx 发送一个真实的路径请求比如访问/resource/12Nginx 找不到对应的静态文件就会返回 404。try_files $uri $uri/ /index.html;这行配置把所有前端路由的请求都回归到 index.html由 Vue Router 接管这个坑如果没踩过上线后绝对会慌。4. 常见问题与排查技巧实录4.1 后端启动报错对照表在跑这个项目的过程中大多数报错是环境问题而不是代码问题。我把遇到过的典型问题整理成了一张速查表报错信息常见原因解决办法Access denied for user rootlocalhost数据库密码错误或用户权限不足检查 application.yml 的密码确认 MySQL 用户允许本地登录Unknown database media_share数据库还没有创建先执行 init.sql 或手动建库Port 8080 was already in use端口占用换端口启动或找到占用进程杀掉Failed to configure a DataSource数据库连接配置缺失检查 spring.datasource 配置是否完整Cause: com.mysql.cj.jdbc.exceptions.CommunicationsExceptionMySQL 未启动或端口不是 3306先确认 MySQL 服务是否在运行Invalid bound statement (not found)MyBatis 的 mapper XML 路径配置不对检查mapper-locations是否匹配实际 XML 存放位置Failed to parse configuration classSpringBoot 版本与 JDK 版本不匹配确认 JDK 版本是否符合 SpringBoot 要求其中Invalid bound statement这个报错特别容易踩新手经常把 mapper XML 文件放在 Java 包里但 Maven 默认不会把src/main/java目录下的 XML 文件打包到 classpath。解决方法是在 pom.xml 的 build 节点中加resources resource directorysrc/main/java/directory includes include**/*.xml/include /includes /resource /resources或者干脆把 XML 文件放到src/main/resources/mapper目录下然后配置mapper-locations: classpath:mapper/*.xml。我用的是后者惯例做法最不容易出问题。4.2 MyBatis 查询条件不生效的经典排雷MyBatis 动态 SQL 有一个非常经典的坑XML 里的if判断参数明明是空的但条件就是不生效。我见过最多的场景是这样的if testcategoryId ! null and categoryId ! AND category_id #{categoryId} /if当categoryId是 Integer 类型时categoryId ! 这个判断会报错或者导致条件失效。因为 Integer 不应该和 String 比较MyBatis 在 OGNL 表达式里对这个比较的处理很微妙。正确写法是if testcategoryId ! null AND category_id #{categoryId} /if这类问题的排查思路是在 MyBatis 配置里打印 SQL看最终生成的 SQL 是什么样的。mybatis: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl这个配置项是我日常排雷的第一步。开了之后控制台会打印完整的 SQL 句子和参数列表你一眼就能看出是参数没传进来、还是 SQL 拼接逻辑有问题。这个技巧对 MyBatis 定位问题来说比我见过的大部分 debug 方式都直接。4.3 上传功能失灵的排查清单上传功能一旦失败现象五花八门有的报FileUploadException有的是 413有的是 500有的前端直接提示跨域。我自己的排查顺序是先看控制台日志——这一步能区分是文件太大被拦截还是 SpringMVC 处理过程中出了异常。确认上传请求头——前端上传时是否带上了 JWT token如果后端上传接口拦截了未登录请求而 axios 拦截器没有覆盖el-upload的自定义请求头就会返回 401。检查磁盘空间和目录权限——file.transferTo(dest)本质是文件 IO如果上传目录不存在或者没有写权限这里会异常。在 Linux 上部署时尤其要注意/data/media_upload目录的属主要和运行 Jar 包的用户一致。确认 Nginx 上传大小限制——部署模式下的 413 报错不一定是 SpringBoot 的限制也可能是 Nginx 的默认限制。必须在 Nginx 配置里加上client_max_body_size 500M;这个坑非常隐蔽因为开发环境走 Vue devServer 代理不会触发 Nginx 限制只有生产环境部署才会暴露。4.4 Vue 打包后放到 SpringBoot 的思路差异网上经常有人问“Vue 打包之后能不能放进 SpringBoot 的 static 目录里运行”。可以但不建议在前后端分离的项目里这么做。放进 SpringBoot 的方式本质上是把前后端揉回了一个部署单元好处是部署简单只跑一个端口坏处是失去了前后端分离的扩展能力——以后要是新增一个移动端或多个前端就得再维护一套部署逻辑。而且如果你用的 Nginx 不只是做静态文件服务还承担了负载均衡、HTTPS 证书、静态资源缓存这些任务那 Vue 放到 SpringBoot 里面就是给自己找麻烦。我的建议很明确按原生的前后端分离方式部署前端 Nginx 后端 Jar 包。如果只是在学校服务器上临时演示也可以合并运行但别把它当常规方案。4.5 MySQL 数据同步与备份的小建议项目跑起来之后数据备份就是第一优先级。我的习惯是每天凌晨用 crontab 做一次全量备份备份命令很简单mysqldump -u root -p你的密码 media_share /backup/media_share_$(date %Y%m%d).sql恢复时执行mysql -u root -p media_share backup.sql额外提醒一点上传的文件目录也要一起备份数据库只是文件路径的记录者文件实物丢了数据库记录再完整也恢复不了。这两个备份最好存放在不同磁盘位置防止硬件故障导致全丢。5. 源码结构解读与二次开发思路5.1 后端目录结构与分层思想源码到手后先别急着跑花十分钟看一下包结构。我的后端包结构是这样的com.example.mediashare ├── controller # 接口层接收请求、返回响应 ├── service # 业务层处理核心逻辑 ├── mapper # 数据访问层MyBatis 接口 ├── entity # 实体类 ├── config # 配置类跨域、拦截器、WebMvc ├── common # 通用类统一返回结果、异常处理 ├── interceptor # JWT 拦截器 └── utils # 工具类controller层只负责参数接收、调用 service、返回结果不写任何 SQL 相关代码service层专注业务逻辑比如上传资源时的文件名生成、路径组装、状态默认值设置mapper层就是纯粹的接口和 XML。这样的分层让每个文件的职责都很清晰改起来不会牵一发而动全身。统一返回结果是我在所有后端项目里都坚持做的。前端的每个请求都会返回一个固定的结构{ code: 200, message: 操作成功, data: { } }code是 200 表示成功400 表示参数错误401 表示未登录500 表示服务器异常。前端 axios 统一拦截这个结构体识别code之后做对应提示而不是让前端去判断 HTTP 状态码。这个设计的价值在于HTTP 状态码在跨域和网关场景下可能会被改写而业务响应里的 code 永远是我们自己说了算。5.2 前端路由与权限菜单的动态生成Vue 端用得比较顺手的设计是路由分为公共路由和权限路由两部分。公共路由只有登录页和首页权限路由根据登录用户的角色动态添加。具体说用户在登录成功后后端接口会返回一个字段roleadmin / teacher / student前端根据这个角色拼接对应的菜单项。比如管理员能看到“用户管理”和“审核管理”上传者只能看到“资源管理”和“我的上传”学生则只有“浏览资源”和“我的收藏”。Vue Router 的动态添加路由方式是// 根据角色添加路由 router.addRoutes(dynamicRoutes[role])动态路由这套逻辑在用户刷新页面时有一个需要注意的地方Vuex 里的用户状态是保存在内存里的刷新后丢失。所以刷新页面时要么把用户信息和角色存到 localStorage 中在路由初始化时读取要么在根组件的 created 钩子里重新调用一次“获取用户信息”接口。我用的是后者因为更安全——用户信息不落盘token 丢了就得重新登录。5.3 后续扩展方向日志、统计与搜索如果把这套系统作为毕设或者实验室项目我建议在现有基础上朝这几个方向扩展操作日志采集。目前的 operation_log 表已经记录了用户的行为但只是被动记录。你可以做一个简单的后台统计面板按用户、按时间、按资源类型做聚合展示用高性能的 SELECT 聚合查询就可以实现不需要引入额外的重量级组件。访问量统计与资源排行。在资源表中加一个view_count字段每次进入详情页时异步调用一个自增接口。这个方案要注意接口的防刷最简单的办法是在后端限制同一个 IP 在一分钟内的重复提交次数。接入更专业的搜索。当资源量突破一定规模且你的机器配置允许可以考虑把 Elasticsearch 引入进来。用 Logstash 或者其他同步工具把 MySQL 的数据同步到 ES然后前端搜索接口走 ES。在校园网环境下MySQL LIKE 查询在数据量几十万级别时其实已经够用所以这个扩展不着急等卡到不可接受了再上。5.4 代码阅读顺序建议如果你是第一次接触这个项目的源码我建议按照这个顺序读先看数据库表结构init.sql理解业务原型。看entity包下的实体类对比数据库字段确认映射关系。看controller包了解对外提供的所有接口。挑一个完整链路比如“用户上传资源”从 controller → service → mapper 走一遍。再看前端对应的页面理解前后端是如何通过接口配合的。跳着读是读源码的大忌尤其是前后端分离项目如果不知道某个接口对应哪个页面整个代码在你眼里就是散落的孤岛。最后再分享一点个人经验做完这一整套基于 SpringBoot Vue MyBatis MySQL 的多媒体信息共享平台我最大的感受是这类系统真正的复杂度不在技术栈本身而在“资源生命周期”的完整闭环——从上传、存储、检索、浏览、播放到审核和下线每一个环节都有大量容易被忽略的细节。比如视频播放的 Range 请求兼容、文件上传大小的三层限制SpringBoot、Nginx、浏览器、Vue Router 的 history fallback、MyBatis 动态 SQL 的类型比较陷阱这些都是在踩过坑之后才真正理解的。写这篇实战记录也是希望后来的人能少走几天弯路。如果你在实际部署中遇到了我上面没提到的问题可以按照“看日志 → 查配置 → 搜资料 → 拆链路”这个顺序来排查大多数问题都能在这个流程里找到答案。这套系统的完整源码和部署文档整理之后后续我还会补充一个 Docker 化的部署方案让整体环境搭建可以一键完成。
返回列表