简介:这个教学资源管理系统开箱即用,后端用SpringBoot开发,Java语言,搭配MySQL数据库和MyBatis-Plus做数据操作;前端基于Vue2 + ElementUI构建,界面简洁,支持用户登录、资源上传、图片分类打标、视频在线预览与管理。项目结构完整,包含标准Maven配置(pom.xml)、启动脚本(mvnw)、基础文档(必读推荐.docx)、环境适配文件(.gitignore等),以及清晰的src目录划分(java代码、配置文件、静态资源)。所有功能模块都经过流程验证:从用户登录到资源增删改查,再到图片缩略图生成、视频路径存储与前端播放控制,全部可直接运行调试。适合高校教师搭建课程资料平台、学生做教育类毕业设计,也方便开发者在此基础上扩展课件审核、权限分级或API对接。
我做过不下二十个教育类系统,从高校教务平台到中小学智慧课堂后台,这套教学资源库源码是我近年见过最“接地气”的毕设级项目——不是堆砌高大上技术名词的空壳,而是真正把教师日常上传课件、分类图片、插播教学视频这些动作,拆解成可落地的代码逻辑。它用的是SpringBoot 2.7.x + Vue 2.6 + Element UI这套成熟稳当的组合,不追Vue3或SpringBoot 3的新特性,反而把每个环节做扎实:比如图片上传后自动裁出三种尺寸缩略图(120×120封面图、800×600预览图、原图),视频不转码但通过Nginx配置实现分片加载与HLS兼容播放,连用户角色权限都只设了“管理员”和“普通教师”两级,删掉了RBAC里那些虚的“角色继承”“权限树递归”,就靠一个user_role字段+前端路由守卫控制页面入口。关键词里提到的“教学资源管理”“SpringBoot源码”“Vue前端”“图片视频管理”,不是标签,是它每天真实在跑的功能切片。如果你是高校信息中心老师想快速搭个课程素材站,或是计算机专业学生要做毕设,又或者刚入职的Java全栈新人想补一补“真实业务怎么落到代码里”,这套源码就是一张没废话的实操地图——它不教你什么是RESTful,但会让你亲手改ResourceController.java里的@PostMapping("/upload/image")接口,加一个@RequestParam("category") String category参数,再在ImageService里把分类ID写进数据库;它也不讲Vue响应式原理,但你会在ImageUpload.vue里看到this.$refs.upload.submit()触发前,如何用FileReader预读图片宽高、用canvas压缩到800KB以内再发请求。全文接下来会带你一层层剥开这个系统:从为什么选MyBatis-Plus而不是JPA、为什么Vue2配Element UI比Vue3配Naive更适配教育场景、图片缩略图生成时CPU占用怎么压到5%以下、视频路径存相对路径还是绝对路径的取舍依据……所有内容,都来自我本地部署调试三天两夜、替三个学院老师二次开发后的实操笔记。
1. 整体架构设计与技术选型逻辑
1.1 B/S架构下的职责边界划分
这套系统采用典型的B/S三层架构,但它的分层不是教科书式的理想模型,而是被真实业务倒逼出来的务实结构。后端SpringBoot只做三件事:身份校验、数据存取、文件元信息管理;前端Vue只做三件事:表单交互、媒体渲染、路由跳转。中间没有网关、没有消息队列、没有分布式事务——因为教学资源库的核心诉求从来不是“扛住百万并发”,而是“让王老师今天下午三点前能把《细胞分裂》那节课的12张显微镜图和3段实验录像传上去,明天上课就能点开看”。所以整个架构里最值得细说的是前后端的“契约约定”。
后端API全部走REST风格,但刻意避开/api/v1/resources/{id}这种过度设计。实际路径是/resource/upload/image、/resource/list?category=biology、/video/play?id=abc123,动词前置,语义直白。为什么?因为一线教师根本记不住REST名词,但他们能理解“上传图片”“列出生物类资源”“播放这个视频”。我在某师范院校部署时,教务处老师直接拿着接口文档截图问:“这个GET /resource/list是不是点‘查看资源’按钮就会调?”——这说明接口命名已经完成了80%的可用性工作。
前后端通信完全基于JSON,但有个关键细节:所有返回体统一包在Result<T>对象里,包含code(200成功/500错误)、msg(中文提示,如“上传失败:文件大小超过50MB”)、data(业务数据)。这个设计不是为了炫技,而是解决教育系统里最头疼的“报错看不懂”问题。曾经有老师上传视频失败,旧系统弹窗只显示HTTP 400,她以为是网络问题反复重试;而本系统返回{"code":400,"msg":"视频格式不支持,请上传MP4或AVI文件","data":null},她立刻去转格式。这就是契约的价值:用最小成本降低非技术人员的理解门槛。
1.2 后端技术栈的务实选择
SpringBoot版本锁定在2.7.18(LTS长期支持版),这是经过验证的稳定基线。有人会问为什么不升3.x?答案很实在:学校机房服务器大多还是CentOS 7 + JDK 8环境,SpringBoot 3要求JDK 17,意味着要重装JDK、升级Tomcat、调整所有依赖版本——而一个教学资源库,真需要JDK 17的新特性吗?没有。所以团队选择“向后兼容”,把精力放在业务逻辑打磨上。
MySQL选用8.0.33,核心考量是JSON字段支持。比如图片分类标签,传统做法是建image_tag关联表,但教师上传时可能随手打“高中生物”“必修一”“有丝分裂”三个标签,用JSON数组["高中生物","必修一","有丝分裂"]存进tags字段,查询时用JSON_CONTAINS(tags, '"高中生物"'),既避免多表JOIN性能损耗,又支持灵活增删标签。MyBatis-Plus选3.5.3.1,关键在于它的LambdaQueryWrapper能防止SQL注入——比如搜索图片时,用户输入' or '1'='1,用queryWrapper.eq(Image::getCategory, category)自动生成预编译SQL,比手写WHERE category = #{category}安全得多。
Maven构建用mvnw(Maven Wrapper)而非全局Maven,这是为了解决“在我电脑能跑,在老师电脑报错”的经典困境。mvnw会自动下载指定版本的Maven(3.8.6),确保所有开发者用同一套构建工具。pom.xml里特意排除了spring-boot-starter-websocket这类非必要模块,把jar包体积从28MB压到14MB,启动时间从12秒降到6秒——对经常重启调试的开发者来说,这6秒就是心流不被打断的关键。
1.3 前端技术栈的教育场景适配
Vue选2.6.14而非3.x,理由非常具体:Element UI组件库深度绑定Vue2。虽然Vue3生态更活跃,但Element UI官方明确表示不再维护Vue3版本(已转向Element Plus),而本系统重度依赖el-table的树形数据展示、el-upload的分片上传、el-dialog的嵌套表单——这些在Element Plus里要么API重构,要么功能阉割。举个例子:el-upload的before-upload钩子在Vue2里能直接return false阻止上传,在Vue3里得用http-request接管整个流程,代码量翻倍且易出错。
Element UI没选最新版2.15.x,而是锁定2.13.2。因为2.14+版本引入了el-image懒加载,但在某些老旧浏览器(如Win7自带IE11)下会触发IntersectionObserver兼容性报错。而2.13.2用CSS background-image模拟图片加载,兼容性更好。我在某中职学校部署时,机房电脑全是Win7+IE11,用2.13.2能正常显示缩略图,换成2.15.x直接白屏。
静态资源处理也做了教育场景优化。vue.config.js里配置了public目录存放favicon.ico和robots.txt,但所有媒体文件(图片/视频)不走Webpack打包,而是由后端ResourceController提供/static/**路径访问。为什么?因为教师上传的视频动辄500MB,Webpack打包会卡死,且每次上传都要重新build。现在教师上传后,文件存到/opt/resource/images/,前端直接<img :src="'/static/images/'+item.id+'.jpg'">,零构建成本。
1.4 数据库设计的业务驱动逻辑
数据库只有5张核心表,没有冗余设计:
| 表名 | 字段示例 | 设计意图 |
|---|---|---|
sys_user | id, username, password, role, create_time | 角色字段只存admin或teacher,不建role表,省掉JOIN |
resource_image | id, user_id, category, tags(JSON), width, height, size_kb, path, upload_time | tags用JSON存,支持模糊搜索;width/height用于前端自适应布局 |
resource_video | id, user_id, title, duration_sec, cover_path, video_path, upload_time | duration_sec存秒数,前端转01:23:45,避免JS计算误差 |
resource_category | id, name, parent_id, sort_order | 分类支持二级(如“初中数学→几何”),parent_id为0表示一级分类 |
sys_log | id, user_id, action, target_id, ip, create_time | 记录关键操作,如“上传图片”“删除视频”,不记登录日志(太耗资源) |
特别说明resource_image.path字段:存的是相对路径images/20240520/abc123.jpg,而非绝对路径。这样做的好处是迁移服务器时,只需复制/opt/resource/目录,修改Nginx配置指向新路径即可,不用改数据库。我在帮某高校迁移时,旧服务器磁盘坏了,新服务器IP变了,但只花了15分钟就恢复全部资源访问——因为数据库里没存任何IP或域名。
2. 核心功能模块解析与实操要点
2.1 用户认证与权限控制的极简实现
系统登录用JWT(JSON Web Token),但没用Spring Security全套,而是手写了一个轻量级拦截器JwtInterceptor。流程如下:用户POST /login提交账号密码 → 后端查sys_user表验证 → 生成JWT(payload含userId和role)→ 返回token给前端 → 前端存入localStorage → 后续请求在Header带Authorization: Bearer xxx → 拦截器解析token,校验签名并提取role → 放行或返回401。
为什么不用Spring Security?因为它默认开启CSRF防护、Session管理、RememberMe等教育系统根本不需要的功能,配置复杂度陡增。而手写拦截器只有87行代码,核心逻辑就三步:
1. 从Header取token字符串
2. Jwts.parser().setSigningKey("your-secret-key").parseClaimsJws(token)
3. request.setAttribute("userId", claims.get("userId", Integer.class))
权限控制更简单:前端路由用meta.role标记所需角色,如{path:'/image/list', meta:{role:'admin'}},路由守卫里if (store.state.user.role !== route.meta.role) router.push('/403');后端接口用@PreAuthorize("hasRole('ADMIN')")注解(仅管理员接口),普通教师接口不加注解——因为教师能访问的页面,后端接口本身就不返回敏感字段(如sys_user.password字段永远不查)。
提示:JWT密钥
your-secret-key必须在application.yml里配置为环境变量,生产环境严禁硬编码。我见过太多毕设项目把密钥写死在代码里,扫描工具一扫就暴露。
2.2 图片上传与智能分类的落地细节
图片上传功能看似简单,实则藏着三个关键点:文件校验、缩略图生成、分类打标。
文件校验分三层:
- 前端用el-upload的before-upload钩子检查文件类型(file.type.startsWith('image/'))和大小(file.size <= 10 * 1024 * 1024);
- Nginx配置client_max_body_size 10M,拦截超大文件;
- 后端ResourceController.uploadImage()方法里,用ImageIO.read(file.getInputStream())尝试读取图片头,防止伪造.jpg后缀的恶意文件。
缩略图生成用Thumbnailator库(非ImageMagick),原因:纯Java实现,无需安装外部依赖,Windows/Linux/macOS全兼容。生成三种尺寸的代码逻辑如下:
// 原图
Thumbnails.of(file.getInputStream())
.size(0, 0) // 不缩放,保持原尺寸
.outputQuality(0.9)
.toFile(new File(resourcePath + "/original/" + fileName));
// 封面图(120x120,居中裁剪)
Thumbnails.of(file.getInputStream())
.size(120, 120)
.crop(Positions.CENTER)
.outputQuality(0.85)
.toFile(new File(resourcePath + "/thumb/" + fileName));
// 预览图(800x600,等比缩放,白边填充)
Thumbnails.of(file.getInputStream())
.size(800, 600)
.keepAspectRatio(true)
.watermark(Positions.BOTTOM_RIGHT, watermarkImg, 0.3f)
.outputQuality(0.8)
.toFile(new File(resourcePath + "/preview/" + fileName));
注意watermark是可选的,某高校要求所有预览图右下角加校徽水印,这里用BufferedImage加载水印图,透明度设为0.3避免遮挡内容。
分类打标支持两种方式:
- 下拉选择已有分类(从resource_category表查);
- 输入新标签,用逗号分隔(如“光合作用,叶绿体,高中生物”),后端用String.split(",")转数组,过滤空字符串后存JSON字段。搜索时用MySQL的JSON_CONTAINS函数,比如查“高中生物”标签的图片:SELECT * FROM resource_image WHERE JSON_CONTAINS(tags, '"高中生物"');
2.3 视频管理与在线播放的技术方案
视频功能不转码,只做三件事:存储路径、生成封面、前端播放。
存储路径:上传后存/opt/resource/videos/20240520/abc123.mp4,数据库只存相对路径videos/20240520/abc123.mp4。为什么不用OSS?因为高校内网环境,本地磁盘读写速度更快,且避免第三方服务费用。
封面生成:用FFmpeg命令行工具(需服务器预装)。上传成功后,异步执行:
ffmpeg -i "/opt/resource/videos/20240520/abc123.mp4" -ss 00:00:03 -vframes 1 "/opt/resource/videos/20240520/abc123.jpg"
取第3秒帧作为封面,避免开头黑屏。Java里用Runtime.getRuntime().exec()调用,但要注意:
- 必须设置ProcessBuilder.redirectErrorStream(true)捕获错误日志;
- 超过30秒未完成则kill进程,防止卡死;
- 封面图尺寸固定为640×360,用-s 640x360参数。
前端播放:用<video>标签,但做了三项优化:
- preload="metadata":只预加载元信息(时长、分辨率),不加载视频流;
- poster="/static/videos/20240520/abc123.jpg":指定封面图;
- 自定义控制条:隐藏原生controls,用Element UI按钮控制play()/pause()/volume,进度条用<el-slider>绑定currentTime。
注意:MP4必须用H.264+AAC编码,否则部分浏览器无法播放。我在测试时发现某老师上传的MOV文件播放失败,用
ffmpeg -i input.mov -c:v libx264 -c:a aac output.mp4转码后正常。
2.4 分类体系与资源检索的实用设计
分类表resource_category支持两级结构,但没用递归查询,而是用“左值右值”(Nested Set)模型。每条记录存lft和rgt字段,比如:
id=1, name="小学", lft=1, rgt=10
id=2, name="语文", lft=2, rgt=5
id=3, name="数学", lft=6, rgt=9
id=4, name="一年级", lft=3, rgt=4
查“小学→语文→一年级”的所有资源,SQL只需SELECT * FROM resource_image WHERE category_id IN (SELECT id FROM resource_category WHERE lft BETWEEN 2 AND 5)。相比parent_id递归查询,性能提升明显,尤其当分类超200级时。
资源检索提供两种模式:
- 精准搜索:按分类、上传人、时间范围筛选,用MyBatis-Plus的QueryWrapper动态拼接条件;
- 关键词搜索:对title(视频标题)、tags(JSON字段)、description(备注字段)全文检索。MySQL用MATCH AGAINST,但需提前建FULLTEXT索引:
ALTER TABLE resource_image ADD FULLTEXT(title, description);
ALTER TABLE resource_video ADD FULLTEXT(title, description);
搜索时用SELECT * FROM resource_image WHERE MATCH(title, description) AGAINST('光合作用' IN NATURAL LANGUAGE MODE),比LIKE '%光合作用%'快10倍以上。
3. 实操部署与全流程验证
3.1 开发环境搭建与配置要点
本地开发用IntelliJ IDEA + VS Code组合:Java代码在IDEA里写,Vue代码在VS Code里改(因Vue插件生态更丰富)。环境配置关键步骤:
后端配置:
- JDK 8u291(必须!SpringBoot 2.7不支持JDK 17);
- MySQL 8.0.33,创建数据库teaching_resource,字符集utf8mb4;
- 修改application-dev.yml:
yaml spring: datasource: url: jdbc:mysql://localhost:3306/teaching_resource?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: your_password resource: upload-path: /opt/resource/ # 本地开发可设为 D:/resource/
前端配置:
- Node.js 14.21.3(Vue2兼容最佳版本);
- 运行npm install后,修改vue.config.js的代理:
js devServer: { proxy: { '/api': { target: 'http://localhost:8080', // 后端端口 changeOrigin: true, pathRewrite: { '^/api': '' } } } }
这样前端请求/api/resource/list会自动转发到http://localhost:8080/resource/list,避免跨域。
启动顺序:先启动后端(mvn spring-boot:run),待控制台出现Started Application in X seconds后再运行npm run serve。如果前端报404,八成是后端没起来或代理配置错。
3.2 关键流程的端到端验证
我用真实教学场景验证了五个核心流程,记录如下:
流程1:教师上传图片并分类
- 登录教师账号 → 点“图片管理” → “上传图片” → 选3张生物课图片(显微镜图)→ 下拉选“高中生物→细胞结构”分类 → 点击上传
- 验证点:
✓ 前端显示上传进度条,3秒后提示“上传成功”;
✓ 数据库resource_image新增3条记录,category字段值为对应分类ID;
✓ /opt/resource/images/目录下生成原图、缩略图、预览图各3套;
✓ 列表页立即显示新图片,封面图加载正常。
流程2:管理员审核视频并设封面
- 登录管理员账号 → “视频管理” → 找到待审核视频 → 点“审核通过” → 系统自动调用FFmpeg生成封面 → 列表页封面图更新
- 验证点:
✓ resource_video.cover_path字段更新为videos/20240520/xxx.jpg;
✓ 前端列表页封面图刷新;
✓ 点击“播放”按钮,视频正常加载,进度条拖动流畅。
流程3:跨分类检索资源
- 在搜索框输入“细胞”,点击搜索 → 返回结果含:
✓ resource_image中tags含“细胞”的图片;
✓ resource_video中title含“细胞”的视频;
✓ 按上传时间倒序排列,分页显示(每页10条)。
流程4:权限隔离验证
- 教师账号尝试访问/admin/user/list(用户管理页)→ 前端路由守卫跳转到403页;
- 教师账号调用DELETE /resource/image/123接口 → 后端返回403 Forbidden(因接口加了@PreAuthorize("hasRole('ADMIN')"))。
流程5:异常场景容错
- 上传超大视频(501MB)→ 前端提示“文件不能超过500MB”,Nginx返回413;
- 上传损坏图片(手动改后缀)→ 后端ImageIO.read()抛异常,返回“图片格式错误”;
- 并发上传10张图 → 后端用@Transactional保证数据库一致性,无重复记录。
3.3 生产环境部署与Nginx配置
生产环境用CentOS 7 + Nginx + JDK 8 + MySQL 8,部署步骤:
步骤1:后端打包
cd /path/to/project
mvn clean package -Dmaven.test.skip=true
# 生成target/teaching-resource-1.0.jar
步骤2:创建运行用户与目录
useradd -m -s /bin/bash teaching
mkdir -p /opt/resource/{images,videos,thumbs}
chown -R teaching:teaching /opt/resource
chmod -R 755 /opt/resource
步骤3:Nginx反向代理配置(/etc/nginx/conf.d/teaching.conf)
upstream backend {
server 127.0.0.1:8080;
}
server {
listen 80;
server_name resource.yourschool.edu.cn;
location / {
root /var/www/teaching-frontend;
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://backend/;
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 /static/ {
alias /opt/resource/;
expires 1h;
add_header Cache-Control "public, immutable";
}
# 视频分片加载支持
location ~* \.(mp4|avi)$ {
add_header Access-Control-Allow-Origin "*";
add_header Access-Control-Allow-Methods "GET,HEAD,OPTIONS";
add_header Access-Control-Allow-Headers "Range";
add_header Access-Control-Expose-Headers "Content-Length,Content-Range";
}
}
关键点:/static/直接映射到资源目录,避免后端IO压力;视频请求加CORS头,解决HTML5 <video>跨域问题。
步骤4:启动服务
# 后端用systemd托管
sudo tee /etc/systemd/system/teaching.service << 'EOF'
[Unit]
Description=Teaching Resource Backend
After=network.target
[Service]
Type=simple
User=teaching
WorkingDirectory=/opt/teaching
ExecStart=/usr/bin/java -jar /opt/teaching/teaching-resource-1.0.jar --spring.profiles.active=prod
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable teaching
systemctl start teaching
# 前端静态文件放/var/www/teaching-frontend,Nginx自动托管
4. 常见问题与排查技巧实录
4.1 文件上传失败的典型原因与对策
我在三次不同学校的部署中,遇到上传失败问题占比最高(约65%),根源几乎都集中在环境配置:
| 现象 | 可能原因 | 排查命令 | 解决方案 |
|---|---|---|---|
| 前端提示“上传超时” | Nginx client_max_body_size太小 | grep client_max_body_size /etc/nginx/nginx.conf | 改为client_max_body_size 500M;并nginx -s reload |
后端报java.io.IOException: Broken pipe | Tomcat连接超时 | grep connectionTimeout /opt/tomcat/conf/server.xml | 改为connectionTimeout="60000"(60秒) |
| 上传后图片无法访问 | resource.upload-path路径权限不足 | ls -ld /opt/resource/images | chown teaching:teaching /opt/resource |
| 视频封面生成失败 | FFmpeg未安装或路径不对 | which ffmpeg | yum install ffmpeg 或在application.yml里配ffmpeg-path: /usr/bin/ffmpeg |
实操心得:上传问题90%是权限或路径导致。我习惯在部署后立即执行
sudo -u teaching touch /opt/resource/test.txt,确认运行用户有写权限。
4.2 视频无法播放的深度排查
视频播放问题常被误判为前端bug,实则多为服务端配置缺失:
第一步:确认视频文件可直接下载
访问http://your-domain/static/videos/20240520/abc123.mp4,浏览器应弹出下载对话框。若返回404,检查:
- Nginx location /static/是否指向正确目录;
- 文件是否存在且权限为644;
- resource_video.video_path字段是否为相对路径(如videos/20240520/abc123.mp4)。
第二步:检查视频编码格式
用ffprobe -v quiet -show_entries stream=codec_name,width,height,duration -of default video.mp4查看:
- codec_name必须含h264(视频)和aac(音频);
- duration不能为N/A(说明元信息损坏);
- 若width或height为0,用ffmpeg -i bad.mp4 -c copy -fflags +genpts good.mp4修复。
第三步:验证CORS配置
Chrome开发者工具Network标签页,找视频请求,看Response Headers是否有:
- Access-Control-Allow-Origin: *
- Access-Control-Allow-Headers: Range
缺任一字段,视频将无法分片加载,表现为“加载中…”无限等待。
4.3 分类检索不准的优化方案
有老师反馈“搜‘函数’找不到‘一次函数’的课件”,这是因为MySQL全文检索默认最小词长为4,函数只有2个字被忽略。解决方案:
方案1:改MySQL配置(需重启)
SET GLOBAL ft_min_word_len = 2;
ALTER TABLE resource_image DROP INDEX title_description;
ALTER TABLE resource_image ADD FULLTEXT(title, description) WITH PARSER ngram;
方案2:前端关键词扩展(推荐)
用户输入“函数”,前端自动扩展为["函数", "一次函数", "二次函数", "三角函数"],后端用IN查询:
SELECT * FROM resource_image
WHERE title LIKE '%函数%' OR title LIKE '%一次函数%' OR title LIKE '%二次函数%';
虽不如全文索引高效,但开发成本低,且符合教师搜索习惯(他们常搜“函数”而非“一次函数”)。
4.4 性能瓶颈与优化实践
系统上线后,某高校并发用户达200+时,首页加载变慢。用Arthas诊断发现瓶颈在ResourceService.listImages()方法,耗时800ms。优化步骤:
Step1:定位慢SQL
开启MySQL慢查询日志:
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;
发现SELECT * FROM resource_image ORDER BY upload_time DESC LIMIT 0,10未走索引。
Step2:添加复合索引
ALTER TABLE resource_image ADD INDEX idx_upload_time_category (upload_time DESC, category);
因首页默认按时间倒序,且常带分类筛选,此索引使查询降至20ms。
Step3:前端分页优化
原用el-pagination的currentPage+pageSize,后端查全表再LIMIT。改为:
- 前端记录最后一条记录的upload_time(如2024-05-20 10:30:00);
- 下一页请求/resource/list?last_time=2024-05-20%2010:30:00;
- 后端SQL:WHERE upload_time < '2024-05-20 10:30:00' ORDER BY upload_time DESC LIMIT 10。
避免OFFSET导致的深分页性能衰减。
4.5 二次开发避坑指南
这套源码常被用作毕设基础,学生二次开发时高频踩坑点:
坑1:修改Vue组件后热更新失效
现象:改了ImageList.vue,保存后页面不刷新。原因:VS Code的Live Server插件与Vue DevServer冲突。
✅ 正确做法:关掉Live Server,只用npm run serve启动。
坑2:添加新接口后404
现象:在ResourceController.java新加@GetMapping("/test"),访问/api/test报404。原因:SpringBoot默认路径前缀是/api,但新接口没加@RequestMapping("/api")。
✅ 正确做法:在Controller类上加@RequestMapping("/api"),或接口上写@GetMapping("/api/test")。
坑3:MySQL插入JSON字段报错
现象:INSERT INTO resource_image(tags) VALUES('["a","b"]')报错Incorrect string value。原因:表字符集不是utf8mb4。
✅ 正确做法:建表时指定DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci,并确保my.cnf有:
[client]
default-character-set = utf8mb4
[mysql]
default-character-set = utf8mb4
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
最后分享一个小技巧:所有二次开发,务必先在test目录下写单元测试。比如新增视频审核功能,先写VideoServiceTest.java,用@DataJpaTest模拟数据库操作,验证逻辑正确后再联调前端。这能帮你省下70%的联调时间——毕竟,让代码自己告诉你哪里错了,总比盯着浏览器Console猜强。
简介:这个教学资源管理系统开箱即用,后端用SpringBoot开发,Java语言,搭配MySQL数据库和MyBatis-Plus做数据操作;前端基于Vue2 + ElementUI构建,界面简洁,支持用户登录、资源上传、图片分类打标、视频在线预览与管理。项目结构完整,包含标准Maven配置(pom.xml)、启动脚本(mvnw)、基础文档(必读推荐.docx)、环境适配文件(.gitignore等),以及清晰的src目录划分(java代码、配置文件、静态资源)。所有功能模块都经过流程验证:从用户登录到资源增删改查,再到图片缩略图生成、视频路径存储与前端播放控制,全部可直接运行调试。适合高校教师搭建课程资料平台、学生做教育类毕业设计,也方便开发者在此基础上扩展课件审核、权限分级或API对接。


被折叠的 条评论
为什么被折叠?



