1. 非遗数字化传承:为什么它是被低估的“全能型”毕设选题
每年到毕业设计选题季,总有同学跑来问我:“师兄,有没有那种技术栈主流、工作量能凑够、答辩又不至于被老师问到怀疑人生的题目?”说真的,这类需求年年都有,但很多同学一上来就扎进商城系统、博客系统、学生管理系统这些老掉牙的池子里。不是说这些题目不能做,而是它们太同质化了——你隔壁宿舍三个人报出来的题目可能连数据库表都长得一模一样,答辩时老师一看就审美疲劳。
我之所以推荐“基于Spring Boot + Vue的非物质文化遗产数字化传承平台”这个方向,核心原因有三个。第一,非遗这个业务域天然自带“多样性”。一个平台里要管的不只是普通的文字信息,还涉及图片、视频、音频、传承人档案、历史渊源、技艺流程等非结构化数据。这意味着你的系统设计必须有针对性,而不是套个通用CRUD就完事。第二,它同时踩中了“宣传展示”和“数字化管理”两条线:对外是面向公众的文化展示门户,对内是面向管理员的资源维护后台,这种双端结构特别适合用前后端分离架构来呈现,也符合当前企业级项目的真实开发模式。第三,答辩时你好讲故事。非遗数字化传承本身有现实意义和社会价值,老师问道“你这个项目解决了什么问题”,你可以从容地讲清楚业务背景,而不是只能答“就是做个增删改查”。
这篇内容我想从选题分析、架构设计、数据库建模、前后端实现、论文写作到答辩应对,完整拆解这个项目怎么做、为什么这么做。不管你是打算照这个题目做毕设,还是想把“非遗+数字化”作为个人项目来积累经验,这篇文章都能给你一套可以直接落地的参考方案。
2. 业务需求拆解:别急着写代码,先把平台的角色和场景理清楚
很多新手拿到这类系统,第一反应是去Github上搜个现成的脚手架改一改。这个思路不是不行,但如果你连自己做的系统到底服务谁、每个模块解决什么问题都说不清楚,答辩时老师随便问两句就会露馅。所以开工之前,必须把需求层的东西彻底捋一遍,这是整个项目的地基。
2.1 平台定位:宣传展示与数字化管理如何共存
“非物质文化遗产数字化传承”这个题目,听起来很宏大,落到系统层面其实就是两件事:让公众看得见,让管理者管得住。
所谓“看得见”,是指面向普通访客的展示端。访客打开网站,能按分类浏览非遗项目(比如传统技艺、传统舞蹈、民俗、曲艺等),可以看到每个项目的详细介绍、历史渊源、保护等级、所在地域、相关图片和视频,还能看到非遗传承人的个人档案。这部分承担的是文化传播功能,所以页面的信息架构和视觉呈现要比普通的CRUD界面讲究一些。
所谓“管得住”,是指面向管理员的维护端。管理员需要能录入和维护非遗项目信息、管理传承人档案、上传和审核数字化资源(图片、音视频)、管理用户和评论、发布公告、查看平台访问统计数据。这部分是典型的后台管理系统,重点在于操作效率和数据管理的规范性。
这两个角色如果在同一个Controller里混着写,代码很快就会变成一锅粥。所以从需求阶段就要明确:访客端只读为主,管理端可写可控,两者共享底层数据,但通过不同接口和权限机制区分开。
2.2 功能模块全景图与核心操作流程
我把这个平台按角色拆开看,功能结构大概是这样的:
- 访客端(前端门户):非遗项目列表与分类筛选、项目详情页(含图文、视频、传承人信息)、传承人风采展示、资讯/公告查看、站内搜索、个人注册登录、收藏/点赞、评论留言。
- 管理员端(后台管理):仪表盘统计(项目数量、资源数量、用户数量、访问量)、非遗项目管理(增删改查、上下架、分类维护)、传承人管理、数字化资源管理(图片/视频/音频上传与归类)、用户管理(禁用/启用)、评论审核管理、公告管理、系统设置。
核心的业务操作流程,我建议你重点准备两条,因为这是答辩时高频使用的场景。
第一条是访客从浏览到互动的完整链路:访客打开首页 → 查看非遗分类列表 → 点击进入项目详情 → 浏览图文和视频 → 查看传承人信息 → 登录后点赞或评论 → 管理员在后台看到新评论 → 审核通过后在前端公开展示。这条链路覆盖了至少五个后端的核心接口,足以展示你的业务设计能力。
第二条是管理员从录入到发布的资源管理链路:管理员登录后台 → 进入非遗项目管理 → 新建项目填写基本信息 → 上传封面图和关联视频 → 关联传承人 → 保存后前台可见 → 后期可编辑、上下架或删除。这条链路考验的是你对资源存储、关联关系和数据一致性的处理能力。
把这两条链路画清楚,再去设计接口和数据库表,你就会发现很多“理所当然”的设计(比如评论需不需要审核状态)其实都源于业务需求,而不是拍脑袋决定的。
3. 技术选型与架构设计:Spring Boot + Vue 到底怎么分工
技术栈选型这件事,在毕设里通常是“安全牌优先”。Spring Boot + Vue 的组合已经是非常成熟的主流方案,但成熟不等于你可以不思考。老师大概率会问“你为什么选这个不选那个”,所以你要能说出选型背后的逻辑。
3.1 为什么后端选 Spring Boot,为什么前端选 Vue
后端起用Spring Boot,理由非常直接:它极大地简化了Spring生态的配置成本,内嵌Tomcat、自动配置、起步依赖,让开发者可以专注于业务代码而非繁琐的XML配置。对一个毕设体量的项目来说,Spring Boot提供的Spring MVC做接口层、Spring Data JPA或MyBatis做持久层、Spring Security或拦截器做鉴权,这套组合足够稳定,也足够覆盖学校课程里教的绝大部分知识点。
前端起用Vue,最大的好处是组件化和响应式开发体验。非遗展示页这种信息密集型页面,用Vue组件去拆分(比如分类导航组件、项目卡片组件、视频播放组件),页面写起来干净、好维护。Vue的生态也很成熟,Element UI可以快速搭建管理后台界面,Axios做HTTP请求,Vue Router管路由,Vuex或Pinia管状态,整个工具链清晰顺畅。另外Vue的学习曲线相对平缓,对同时要写论文、做毕设、准备答辩的同学来说,上手成本更可控。
3.2 前后端分离的边界画在哪里
前后端分离听起来是个标配,但具体到代码里,很多同学容易画歪边界。我的建议是遵循几个朴素的判断标准:
- **凡是涉及数据增删改查、权限校验、文件存储的,都放后端。**前端只管发请求、接数据、渲染页面。
- **凡是涉及页面跳转逻辑、组件状态、交互效果的,都放前端。**后端不返回任何HTML片段或界面控制信息。
- **接口返回的数据结构必须统一。**我习惯统一封装成
{ code: 200, message: "success", data: {...} }这种格式,前端根据code判断业务是否成功,而不去解析后端的异类返回。
举个常见的反面案例:有些同学把业务判断放在前端做,比如“当用户角色是管理员时显示某个按钮”,这种判断应该由后端接口返回的权限字段决定,而不是在前端写死。非遗平台里,管理员能看见的内容和访客能看见的内容必须由后端控制返回,否则前端源码一暴露,所谓的“权限控制”就形同虚设了。
3.3 项目目录结构与接口命名规范
后端的包结构我建议按业务模块划分,而不是按技术层划分。对比一下:
按技术层划分:controller/、service/、mapper/、entity/,会导致所有业务的Controller堆在一起,项目变大之后很难定位。
按业务模块划分更符合实际开发节奏:
com.example.nonheritage ├── controller # 接口层 │ ├── HeritageController.java │ ├── InheritorController.java │ ├── ResourceController.java │ ├── UserController.java │ └── StatsController.java ├── service # 业务逻辑层 ├── mapper # 数据访问层 ├── entity # 实体类 ├── dto # 请求/响应对象 ├── config # 配置类(跨域、静态资源、拦截器) ├── common # 统一返回、异常处理、工具类 └── NationsApplication.java接口命名统一用REST风格,比如GET /api/heritage/list、POST /api/heritage/save、DELETE /api/heritage/{id}。不要把接口写成queryHeritageInfo、deleteHeritageById这种Action风格,REST风格写出来专业感更强,答辩时老师看了接口文档也会觉得舒服。
4. 数据库建模:非遗资源多样,表结构要经得起推敲
数据库是这类项目的灵魂。非遗平台的信息结构比普通博客系统复杂,因为一个非遗项目不只是一行数据,它关联着分类、传承人、图片、视频、评论等多个维度的信息。我给出的建议是:宁可多拆几张关联表,也不要把所有字段堆在一张大表里。
4.1 核心表的划分及字段设计思路
我建议至少设计以下几张核心表:
user:用户表。字段包括id、username、password(加密存储)、nickname、avatar、role(枚举:ADMIN/USER)、status(启用/禁用)、create_time。heritage_category:非遗分类表。id、category_name、sort_order。分类是典型的树形业务数据,但在毕设体量下,用一张平表存一级分类就够了,不需要做递归树。intangible_heritage:非遗项目主表。这是核心表,字段要有项目名称、所属分类id、项目级别(国家级/省级/市级)、保护单位、所在地域、历史渊源(长文本)、技艺流程(长文本)、文化价值(长文本)、封面图URL、是否上架、点击量、创建时间等。inheritor:传承人表。id、姓名、性别、出生年份、级别、所属项目id、简介、代表作品、头像URL。digital_resource:数字化资源表。id、资源类型(IMAGE/VIDEO/AUDIO)、资源名称、资源URL、所属项目id、上传时间。这张表做成通用资源表,好处是后续不管接入AR展示还是3D模型,都不用改表结构,扩展性好。comment:评论表。id、评论内容、用户id、项目id、审核状态、评论时间。notice:公告表。id、标题、正文、发布时间。
字段设计时,我特别强调几个容易被忽略的点。长文本和短文本要分字段存,比如历史渊源用TEXT类型,项目名称用VARCHAR(100)即可,不要把几千字的描述塞进VARCHAR里面。和业务展示相关的冗余字段可以保留,例如项目表里冗余一个分类名称字段,省去每次列表查询都去join分类表,但要注意冗余字段在分类改名时也要同步更新。时间字段统一用datetime类型,并设置合理默认值,避免出现前端显示“1970-01-01”这种尴尬情况。
4.2 外键与关联关系的处理策略
很多教材强调外键约束,但在实际项目中,我倾向于在数据库层面少用物理外键,而是在应用层维护逻辑关联。原因很简单:毕设项目的数据量不大,物理外键带来的级联约束反而会给数据导入、测试数据构造添麻烦。你只需要在对应的实体字段上建立索引,查询时用MyBatis或JPA手动关联即可。
举个例子,inheritor表里的heritage_id逻辑上关联intangible_heritage表。当管理员删除一个非遗项目时,业务上应该先处理它下面的传承人、数字化资源、评论,再删除项目本身。这个顺序写在Service层里,比数据库的级联删除更容易控制和理解,代码审阅时也能向老师清晰说明你的操作逻辑。
4.3 数据初始化:让演示页面不空转
数据库建模完成之后,别急着写前端,先准备一批真实的演示数据。这一点太重要了——我见过太多项目,代码没问题,但打开前台页面空荡荡的,只剩下“暂无数据”四个大字,答辩效果大打折扣。非遗项目建议录入20条以上,每条都配上真实的项目名称(如苏绣、景德镇手工制瓷技艺、京剧、皮影戏、二十四节气等),写到“历史渊源”字段时尽量复制一些真实的背景资料填充。传承人数据至少5条,视频资源可以用网上可获取的素材或者本地测试视频,图片资源可以准备一批高清素材图。数据真实,页面才有说服力。
5. 后端核心模块实现:认证、列表、文件上传、统计四个必考点
后端是工作量的大头,也是答辩时最容易深挖技术细节的地方。下面我挑四个必做且必考的模块展开讲,每个都用“实现思路 + 关键代码 + 注意点”的结构来呈现。
5.1 基于JWT的登录认证与权限拦截
非遗平台不推荐用Session方式做登录保持,因为前后端分离后,Session的跨域共享处理非常麻烦。目前的主流做法是JWT(JSON Web Token):用户登录成功后,后端签发一个包含用户信息和过期时间的Token,前端存储这个Token并在后续请求的Header里带上,后端通过拦截器解析Token来识别用户身份。
后端的核心逻辑分两层。第一层是登录接口,用户提供用户名密码后校验数据库中的记录,密码用BCrypt加密比对(Spring Security自带的BCryptPasswordEncoder即可),成功后生成Token返回前端。第二层是拦截器,我建议写一个AuthInterceptor加在Spring MVC的拦截器链中,通过HandlerMethod判断接口是否需要登录:
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 放行预检请求和登录接口 if (request.getMethod().equals("OPTIONS")) { return true; } // 从Header获取Token String token = request.getHeader("Authorization"); if (token != null && token.startsWith("Bearer ")) { token = token.substring(7); try { // 解析并校验Token Claims claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody(); request.setAttribute("userId", claims.get("userId")); return true; } catch (Exception e) { response.setStatus(401); return false; } } response.setStatus(401); return false; }管理端接口额外判断角色是否为ADMIN,可以在Token的Claim里带上角色字段,拦截器里再做一次校验。这样访客接口、登录接口放行,管理接口必须带Token且角色为管理员,权限边界就清晰了。
5.2 非遗项目条件分页查询的SQL与实现
非遗项目列表页是一个高频率接口,要支持按分类筛选、按关键词搜索、按级别筛选,还要分页返回。我推荐用MyBatis(或MyBatis-Plus)来写动态SQL,比JPA的Specification更直观可控。
核心动态SQL片段类似:
<select id="selectHeritagePage" resultType="com.example.nonheritage.entity.IntangibleHeritage"> SELECT h.*, c.category_name FROM intangible_heritage h LEFT JOIN heritage_category c ON h.category_id = c.id <where> <if test="categoryId != null"> AND h.category_id = #{categoryId} </if> <if test="keyword != null and keyword != ''"> AND (h.heritage_name LIKE CONCAT('%', #{keyword}, '%') OR h.historical_origin LIKE CONCAT('%', #{keyword}, '%')) </if> <if test="level != null and level != ''"> AND h.level = #{level} </if> </where> ORDER BY h.create_time DESC LIMIT #{offset}, #{pageSize} </select>注意两个细节。第一,分页参数不要直接传pageNum和pageSize然后自己在代码里计算offset,最好在Service层算好传入,SQL保持干净。第二,列表查询默认只查status = 1(已上架)的项目,管理后台查询则不过滤,这个逻辑可以在Mapper里拆成两个方法,避免管理员看不到下架项目。
5.3 图片和视频上传:勿踩Spring Boot默认1MB限制
数字化资源上传是这个系统的重头戏。Spring Boot默认的请求体大小和文件大小限制都很小(通常是1MB左右),传几张高清非遗照片就报错,所以必须显式配置:
spring: servlet: multipart: max-file-size: 50MB max-request-size: 100MB文件上传后,我建议使用本地磁盘存储,把资源存到项目的静态目录下(如/uploads/),并通过配置类映射为可访问的静态资源URL。代码实现上注意文件名要重命名,防止中文乱码和覆盖冲突:
String originalFilename = file.getOriginalFilename(); String ext = originalFilename.substring(originalFilename.lastIndexOf(".")); String newFilename = UUID.randomUUID().toString().replace("-", "") + ext; // 按日期分目录存储,如 /uploads/2025/06/xxx.jpg存库时不要存文件的绝对路径,存相对路径(/uploads/2025/06/xxx.jpg),前端通过域名拼接访问。这样项目迁移时不需要改数据库,只需整体拷贝上传目录即可。
5.4 仪表盘统计:让数据说话
管理员的首页仪表盘虽然只是几个数字,但它是体现你“会思考”的重要细节。比如“国家级项目数量”“省级项目数量”“视频资源总数”“本月新增用户数”,这些统计不要用笨办法循环遍历,直接用SQL聚合:
SELECT COUNT(DISTINCT heritage_id) AS total_heritage, COUNT(DISTINCT inheritor_id) AS total_inheritor, COUNT(DISTINCT user_id) AS total_user FROM ...更高级一点,可以统计各分类下非遗项目的数量占比,返回给前端用图表组件(如ECharts)渲染成饼图。答辩时展示这个页面,效果比十个普通列表页都有说服力。
6. 前端Vue落地:从首页信息流到后台管理端
前端这块我按“门户展示端”和“管理后台”两条线来讲。很多同学容易把前端写成一堆页面文件的堆砌,缺少组件化的拆分和统一的请求封装。下面重点讲几个关键决策点。
6.1 Vue项目的目录组织与请求封装
Vue脚手架创建项目之后(Vite或Vue CLI都可以,我更推荐Vite,启动速度快很多),建议目录结构为:
src ├── api # 按模块拆分的接口调用文件 ├── assets # 静态资源 ├── components # 通用组件(分页、文件上传、图片预览等) ├── router # 路由配置 ├── store # Pinia/Vuex状态 ├── views │ ├── portal # 门户展示端页面 │ └── admin # 管理后台页面 └── utils # 请求工具封装Axios请求封装值得好好做。统一设置baseURL、请求头、超时时间,在请求拦截器里加上Token,在响应拦截器里统一处理401跳转登录和业务码非200的错误提示。这样每个页面里调用接口就非常干净:
import request from '@/utils/request' export function getHeritageList(data) { return request({ url: '/api/heritage/list', method: 'post', data }) }跨域配置有两种做法。开发阶段用Vite的代理(server.proxy)把/api转发到后端地址;生产阶段后端配置CORS(跨域资源共享)允许前端地址访问。我建议开发时用代理,省去后端CORS调试的麻烦。
6.2 门户展示端的页面结构与组件拆分
门户首页是访客的第一印象,建议包含以下区块:
- 顶部导航栏:平台Logo、首页、非遗项目、传承人、资讯公告、登录/个人中心。
- 搜索栏:关键词搜索,跳转到列表页。
- 非遗分类导航:横向排布的分类Tab,点击切换筛选。
- 推荐项目卡片区:四到六个项目卡片,展示封面图、名称、级别、地区。
- 数据总览区:平台非遗项目总数、传承人总数等数字展示。
- 页脚:版权信息。
项目卡片抽成HeritageCard组件,接收一个项目对象,内部处理图片懒加载、名称截断、级别标签颜色等细节。详情页拆成HeritageInfo.vue(基本信息)、HeritageImages.vue(图集)、VideoPlayer.vue(视频播放)、CommentSection.vue(评论区)。组件化带来的好处是,首页和管理端可以复用部分组件,代码量减少,结构也更清晰。
视频播放建议直接用HTML5的<video>标签,支持MP4格式即可。不要踩m3u8的坑——那是点播直播场景才需要的协议,普通毕设项目给老师演示本地MP4视频足够了,非要处理HLS流反而是给自己加麻烦。
6.3 管理后台:用表格、弹窗和表单快速搭建
管理后端页面强烈建议用Element Plus组件库。导航用侧边栏菜单(el-menu),非遗项目管理用el-table展示列表,新增和编辑用el-dialog套el-form表单,图片上传用el-upload,分页用el-pagination。
要注意的是,编辑和新增应该复用同一个弹窗表单组件。弹窗打开时区分“新增”和“编辑”两个模式,新增时清空表单,编辑时回填数据。提交的时候通过id是否存在来决定调save还是update接口。这种设计面试官和老师都爱看,因为它体现了你对表单业务场景的细致理解。
6.4 路由守卫与动态权限
前端路由要区分“访客可访问”和“管理员专属”两类。普通用户的/admin相关路径必须受到保护。实现方式是Vue Router的全局前置守卫:
router.beforeEach((to, from, next) => { const token = localStorage.getItem('token') const role = localStorage.getItem('role') if (to.path.startsWith('/admin') && (!token || role !== 'ADMIN')) { next('/login') } else { next() } })注意,这层前端守卫只是为了提升用户体验(没权限的别看到页面),真正的安全边界还是后端拦截器。前端隐藏按钮不等于后端不提供接口,这个认知要在论文里说清楚。
7. 论文与答辩准备:让工作量“可视化”的实战策略
项目代码写完只是第一步,毕设最终要落到论文和答辩上。很多同学代码写得很好,但论文干瘪、答辩紧张,最后分数反而不如那些“会包装”的同学。既然是经验分享,这块我多说几句。
7.1 论文结构怎么安排才像“研究”而不像“说明书”
论文的正文我建议按这样的主线来组织:
- 绪论:选题背景(非遗数字化传承的政策与现实需求)、国内外数字化保护现状、研究目的与意义。
- 相关技术介绍:Spring Boot、Vue、MyBatis、JWT、MySQL等,不要写成API文档式罗列,要突出“为什么选它解决什么问题”。
- 系统分析:可行性分析(技术、经济、操作)、需求分析(功能性需求、非功能性需求)、用例图(UML用例图可以用,这不是Mermaid图,是论文标配)。
- 系统设计:总体架构、功能模块设计、数据库设计(ER图 + 表结构说明)。
- 系统实现:按模块展示页面截图和核心代码片段,配上实现思路说明。
- 系统测试:功能测试用例表、测试结果分析。
写系统实现这章时,不要贴大段完整代码,选2到3处最有代表性的方法(比如JWT拦截器、动态SQL查询、文件上传)贴片段即可,重点写清实现思路和关键逻辑,老师不会想看几千行源码打印版。
7.2 答辩演示脚本:八分钟讲完重点
答辩演示不要从登录页开始慢慢点。我建议一上来就展示访客门户首页,用真实数据吸引眼球,然后快速演示搜索和筛选功能,进入一个项目详情页展示图文和视频,再切换到管理员后台,用一条“新增项目-上传资源-前台验证”的完整链路展示业务闭环,最后打开仪表盘页面让数据亮点压轴。整个过程控制6到8分钟,剩下的时间留给老师提问。
座位上的电脑提前准备好演示环境:数据库已启动、后端已运行、前端已构建或开发模式下已运行。不要现场开启IDE编译项目,不要现场启动数据库,这些步骤看似简单,但一旦环境异常,整个答辩节奏就会乱掉。
7.3 高频答辩问题和参考应答思路
老师针对这类项目的提问,通常会集中在几个点。
“用户密码存在数据库里安全吗?”——回答思路:密码使用BCrypt加盐哈希存储,不是明文,即使数据库泄露也无法直接得到原始密码。可以展开说BCrypt的单向性和自适应强度。
“列表查询数据量大怎么办?”——回答思路:使用分页查询(LIMIT/OFFSET),查询必要条件走索引,可选条件用MyBatis动态SQL拼装,避免查全表。
“上传的图片和视频会不会把磁盘撑爆?”——回答思路:按日期分目录存储、定期归档清理,后续可以扩展用对象存储(如果项目体量需要的话),毕设层面做本地存储并说明设计思路即可。
“前后端数据交互怎么保证数据格式正确?”——回答思路:后端统一返回包装对象,前端Axios拦截器统一处理,接口文档定义好请求和响应结构,开发时前后端依照契约并行开发。
这些问题都不难,关键是你要在写代码的时候就带着答案去设计,而不是答辩前临时背题。
8. 开发过程中最容易踩的坑和对应的排查思路
最后这部分我按“踩坑实录”的形式分享几个我见过最多的问题,每个都附上完整的排查链路,希望能帮你在开发阶段就绕开这些坑。
8.1 跨域请求被拦截:后端配置了但还是报CORS错误
现象:前端调用后端接口,控制台报No 'Access-Control-Allow-Origin' header is present。
排查过程:先确认是“浏览器拦截”还是“后端未返回跨域头”。办法是打开浏览器开发者工具的Network面板,看请求是否真的发出去了、响应头里有没有Access-Control-Allow-Origin。如果响应头完全缺失,说明后端的CORS配置没生效。在Spring Boot里,推荐用WebMvcConfigurer注册CORS映射,而不是在Controller上加单个@CrossOrigin注解:
@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("*"),这是很多人排查半天没发现的细节。另外,如果前端加了自定义Header(比如Authorization),后端allowedHeaders里要放开,否则触发预检请求失败。
8.2 Spring Boot上传文件报错:文件大小超出限制
现象:上传一个十几MB的视频,后端直接抛MultipartException,报“Max upload size exceeded”。
排查过程:先看异常信息里提示的是哪个限制被突破。常见两种情况:一种是spring.servlet.multipart.max-file-size没配,默认1MB导致普通图片都传不上去;另一种是max-request-size没配,导致多文件提交时总大小超限。按前面第5.3节的配置调整即可。另外注意,如果配置了全局异常处理器,要捕获MaxUploadSizeExceededException并返回友好提示,而不是让框架默认的500错误页面直接暴露给前端。
8.3 Vue路由刷新404:部署到Nginx后白屏
现象:本地开发时路由切换正常,但打包部署到Nginx后,刷新某个子页面(如/heritage/3)直接404。
排查过程:这是Vue Router的history模式典型问题。前端使用history路由时,刷新会请求真实地址,而Nginx没有对应的物理文件,于是返回404。两种解法:一是把Vue Router改用hash模式(URL带#),简单粗暴但URL不够美观;二是Nginx配置try_files $uri $uri/ /index.html;,将所有请求回退到前端入口。我建议用第二种,保持URL干净,并在答辩时能顺便说出“前端路由与服务端配置”的原理。
8.4 首页加载慢:图片资源和数据量拖垮体验
现象:门户首页图片多的时候,打开要转好几秒,体验很差。
排查过程:本质原因是同步加载了多张高清大图。优化方案有三个:图片上加loading="lazy"做懒加载;列表页返回的图片URL使用缩略图(后端在上传时生成一套压缩图,不要前端硬扛高分辨率原图);如果图片资源很多,可以给静态资源加缓存响应头(Cache-Control),减少重复请求。这三个方案都能独立落地,即使只做其中两个,演示时页面流畅度的提升也非常明显。
8.5 数据库时区导致的时间显示偏差
现象:前端显示的后台入库时间和实际时间差了8小时。
排查过程:这是典型的JDBC连接时区问题。MySQL的连接串里如果没有指定serverTimezone=Asia/Shanghai,默认时区和本地时区不一致,导致datetime类型字段读取时偏移。解决方法是连接串显式指定时区:
url: jdbc:mysql://localhost:3306/nonheritage?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8另外,开发时统一约定数据库存储datetime类型,不要混用timestamp和datetime,避免混淆。这个坑在答辩演示时特别尴尬——你明明刚录的数据,页面上显示的时间却是8小时前,解释起来非常被动。
最后一个开发建议,也顺带当这篇内容的收尾吧。拿到这类“非遗数字化”题目,不要只把它当成一个普通的CRUD系统去交差。认真把业务场景想透,把架构选择的原因想透,把数据模型和业务规则的关联想透,你收获的不只是一个毕设分数,而是一套完整的“从需求到系统”的方法论。这套方法论在任何技术栈的项目里都是通用的,也是你真正能写进简历和面试话术里的东西。