ARTICLE DETAIL

资讯详情

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

Spring Boot非遗管理系统实战:数据库设计、鉴权与答辩要点

Spring Boot非遗管理系统实战:数据库设计、鉴权与答辩要点 1. 这个毕设题目选得值不值先看非遗业务的门道1.1 非遗管理系统的业务边界到底有多大每到毕业设计季节计算机专业学生凑到一起聊得最多的就是你做的什么系统。学生管理、图书管理、仓库管理这些题目已经被写了十年答辩老师看都看腻了。基于springboot的非物质文化遗产管理系统这个题目恰好比它们多做了一步——它不是一个纯增删改查的演示壳子而是带有真实保护业务逻辑的场景非遗项目的分类登记、传承人信息的建档、申报材料的流转、专家审核意见的留存、按区域和级别做数据统计。单是把这几个业务流程梳理清楚就够普通管理系统喝一壶了。我在做这个项目之前先花了一周时间去查了各地非遗中心的公开资料。领域里有个基本分类传统技艺、传统美术、传统音乐、传统舞蹈、传统戏剧、曲艺、传统体育游艺与杂技、传统医药、民俗。每个大类下又分具体项目比如传统技艺下面有手工造纸、陶瓷烧制、刺绣、银饰制作。系统如果只按一个类别字段硬塞后面查询和统计就很不灵活。所以我在设计上用的是大类小类两级分类项目表里存分类 id不要直接存字符串这样后面按类筛选的效率和数据规范性都好得多。正因为有这样的领域划分这套系统的数据模型天然要比学生管理系统复杂一层。学生管理只有学生、班级、成绩三张表非遗系统至少要项目表、传承人表、申报审核表、用户表、分类表表与表之间还有引用关系。毕设评审最在意的工作量和数据建模能力在这里不用拼命堆功能也能体现出来。1.2 为什么选 Spring Boot选型背后不是跟风选技术栈的时候很多人会纠结到底用 SSM 还是 Spring Boot。如果今天有人还在让你从零搭 SSM 的 XML 配置再去整合 MyBatis基本是在浪费时间。Spring Boot 的价值在于它把工程化的事情做了比如自动配置、内嵌 Tomcat、Starter 依赖管理你只需要关注业务代码不必把时间花在配置繁琐的 spring-mvc.xml、web.xml 上。毕设选 Spring Boot 还有一个非常现实的原因后续论文好写答辩好讲。评委会关心怎么解决某个技术上比较麻烦的点而不会逼问为什么用 XML 配置不用注解。Spring Boot 的自动配置原理、Starter 机制、内嵌服务器这些都是讲得清楚、属于面试基础范畴的东西。把 Spring Boot MyBatis-Plus MySQL 这组主流组合讲透比堆砌一个重框架有了更好的解释力。从岗位角度来说现在 Java 后端的招聘需求里 Spring Boot 基本是默认技能。做完这个项目你简历上写掌握 Spring Boot 开发这个说法是被行业广泛认可的。2. 系统整体架构与技术栈选型的取舍2.1 前后端分离还是服务端渲染毕设应该怎么选做毕设时一个很典型的选择题就是用 Vue 做前后端分离还是用 Thymeleaf 模板引擎做服务端渲染。我的建议是——如果你有两到三个月的开发周期且想学点前端知识选前后端分离如果你想把精力全部放在后端和源码跑通上面选 Thymeleaf 上手更快。我这两个方案都搭过。服务端渲染方案可以用 Thymeleaf Bootstrap jQuery省掉跨域、Token、Vue 构建这些环节。前后端分离方案用 Vue Element UI Axios把前端项目单独放一个目录后端只提供 JSON 接口。从搜索趋势上是能看出来的现在大量毕设都在找springboot vue前后端分离说明这是当下主流玩法。前端用 Vue 的好处是页面交互体验好——比如非遗项目列表的分页筛选、申报审核卡片式展示这些动起来明显比模板引擎顺手。但要注意前后端分离意味着你要处理跨域问题。最省事的方式是在 Spring Boot 里写一个配置类实现 WebMvcConfigurer 并重写 addCorsMappings把本地前端的地址端口放进来。或者更好一点用 Nginx 做反向代理把 /api 前缀转发到 8080把静态资源指向前端构建目录这样连跨域都免了。毕设答辩时能讲清楚跨域为什么会出现、我用什么方式解决也是加分项。2.2 核心依赖组件清单下面是我在这套非遗管理系统里实际用到的一组依赖组合直接贴出来供参考spring-boot-starter-webWeb 基础spring-boot-starter-validation参数校验mybatis-plus-boot-starterORM 与分页mysql-connector-javaMySQL 驱动jjwtJWT 生成与解析lombok消除实体类样板代码hutool工具类库字符串、日期、文件处理spring-boot-starter-test测试这里想特别说一下认证方式。毕设级别尽量别直接引入 Spring Security因为 Security 的过滤器链配置对新手不够友好出问题排查成本高。用 JWT 拦截器的方式自己写一个 HandlerInterceptor处理逻辑直观前端登录后拿到 token之后每个请求在请求头带着 token拦截器解析 token 并放行。面试时被问你的权限怎么做的一句基于 JWT 无状态认证配合自定义拦截器做角色校验就非常标准。2.3 项目模块怎么分层后端工程我建议按功能模块分包而不是按 Controller、Service、Mapper 这种纯技术层分包一下建四五个包完事。虽然分层严格的包结构看起来更规范但如果整个项目只有十几个接口还是按业务模块来更清晰。我实际用的是这样的结构com.example.nonheritage ├── common/ // 通用返回结果、异常处理、常量枚举 ├── config/ // 跨域、拦截器、文件映射、MyBatis-Plus配置 ├── controller/ // 接口层 ├── service/ // 业务逻辑层 ├── mapper/ // MyBatis-Plus Mapper ├── entity/ // 实体类 ├── dto/ // 入参/出参对象 ├── util/ // JWT、校验等工具注意我单独搞了 dto 目录因为给前端传参、接收前端数据都需要一个独立对象不直接拿数据库实体类当接口参数。这样做的直接好处是字段可控——比如项目列表接口不想把创建人 id 这种内部字段暴露出去只要返回 vo 里没有这个字段就行。3. 数据库建模非遗领域的核心表怎么落地3.1 非遗项目表的字段设计非遗项目管理是核心中的核心我建议第一张表就把分类和状态两个字段考虑到位。分类用分类表状态用冗余字段直接存在主表。如果你不想额外建分类表也可以在项目表里直接存两个字段 category_big、category_small。但要考虑扩展性——万一以后多了三级分类你又得改表加字段。建一张分类表id、name、parent_id、sort_no一套通用的目录结构就出来了。除此之外项目表至少要包含项目名称、所属地区、级别国家级/省级/市级/区县级、类别、状态、封面图、简介、历史渊源、主要特征、重要价值以及审计相关的创建时间、创建人。我用到的表结构大概是这样CREATE TABLE heritage_project ( id BIGINT PRIMARY KEY AUTO_INCREMENT, project_name VARCHAR(100) NOT NULL COMMENT 项目名称, category_id BIGINT COMMENT 所属分类id, region VARCHAR(100) COMMENT 所属地区, level VARCHAR(20) DEFAULT MUNICIPAL COMMENT PROVINCIAL/MUNICIPAL/COUNTY, protection_unit VARCHAR(100) COMMENT 保护单位, status TINYINT DEFAULT 1 COMMENT 1在用 0废弃(软删除), cover_image VARCHAR(255) COMMENT 封面图路径, introduction TEXT COMMENT 项目简介, history TEXT COMMENT 历史渊源, feature TEXT COMMENT 主要特征, value_desc TEXT COMMENT 重要价值, create_time DATETIME, update_time DATETIME, create_by BIGINT ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT非遗项目表;状态字段我强烈建议用逻辑删除用 status 0/1 而不是物理 DELETE。做管理系统经常要保留历史数据毕设也不例外。MyBatis-Plus 提供了 TableLogic 注解直接在 status 字段上标注删除就会自动变成 update status0查询时自动带条件过滤代码不用多写一行。这个细节写进论文可以单开一小节。3.2 传承人表与项目表的关联方式传承人管理是这类系统区别于普通物品管理的关键模块。一位传承人通常掌握一项或几项技艺项目表是主体所以我在设计时让传承人表通过项目 id 引用项目同时冗余存项目名称因为列表页展示时拿完整名称很方便能少做一次表关联。传承人该有的字段要尽量齐姓名、性别、出生年月、所在地、等级国家级/省级代表性传承人等、所属项目、首批认定的年份、联系电话、个人简介、主要成就、代表作品说明、照片地址。特别要注意出生日期用 DATE 类型而认定年份用 YEAR 或字符串这两种时间语义不能混。还有一个常被忽略的字段——个人简介的存储。前端如果用的是文本框存普通文本没问题。如果以后想支持图片和排版就得用富文本编辑器数据库字段用 TEXT 也够但接口层要注意 XSS 过滤。在搜索热词里能看到有人问 SpringBoot 全局过滤器处理上传 PDF 文件时 XSS 攻击虽然场景不一样但思路是通用的要么在入库前走一遍消毒工具要么在前端渲染时转义二选一不能不做。3.3 申报审核记录表审批状态机怎么设计非遗项目不是管理员直接手一抖就录进去的需要走申报流程。我设计了申报审核记录表记录某一次申报的流转历史CREATE TABLE heritage_audit_record ( id BIGINT PRIMARY KEY AUTO_INCREMENT, project_id BIGINT NOT NULL, apply_user BIGINT NOT NULL COMMENT 申报人id, audit_user BIGINT NULL COMMENT 审核人id, audit_status TINYINT NOT NULL DEFAULT 0 COMMENT 0待审核 1通过 2驳回, audit_comment VARCHAR(500) COMMENT 审核意见, apply_time DATETIME, audit_time DATETIME ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT非遗项目申报审核记录表;状态机其实很简单待审核 - 通过或待审核 - 驳回驳回后可以重新提交。审核记录表存在的意义是保留每一次操作痕迹避免项目信息被无声无息地改掉。答辩老师特别容易追问如果审核驳回后再申报历史记录怎么保证把这张表拉出来就赢了。结合项目表里一个当前状态字段展示时判断当前处于哪一步审核历史单独从记录表拉列表非常清晰。4. 后端核心功能实现串讲4.1 登录鉴权JWT 拦截器的写法登录模块谁都会写但写出能过答辩的鉴权代码不是人人能行。我采用的方案是用户表里存用户名、加密后密码、角色管理员/审核员/普通用户登录接口校验通过后生成 JWT 返回前端前端存入 localStorage 并在 axios 请求拦截器里加上 Authorization 头后端自定义拦截器统一校验。JWT 工具类核心逻辑大概是这样public String generateToken(Long userId, String username) { return Jwts.builder() .setSubject(username) .claim(userId, userId) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() 2*60*60*1000)) .signWith(Keys.hmacShaKeyFor(secret.getBytes()), SignatureAlgorithm.HS256) .compact(); }这里有两个细节值得注意。第一个是过期时间我设了两小时对毕设足够但你如果有记住我需求可以延到 7 天。第二个是 secret 不要写在代码里放到 application.yml 的 custom 配置项里解密时再从配置读取这样源码给出去也不至于把密钥直接暴露在业务逻辑里。拦截器实现 HandlerInterceptor在 preHandle 里从请求头拿 token调用工具类解析解析失败直接返回 401。这里有个小坑拦截器对登录接口、静态资源路径都要放行否则前端登录页 get 不到图片和样式。我一般在 WebConfig 里把 /api/login、/upload/**、/error 都加入白名单。4.2 非遗项目 CRUD 与条件查询核心列表页一定不能只做一张表一个查询。我在项目查询接口里支持了多条件组合关键字模糊查询、分类下拉筛选、级别筛选、地区筛选、状态筛选、分页。用 MyBatis-Plus 的 LambdaQueryWrapper 拼条件代码很简洁LambdaQueryWrapperHeritageProject wrapper new LambdaQueryWrapper(); wrapper.like(StringUtils.hasText(dto.getKeyword()), HeritageProject::getProjectName, dto.getKeyword()) .eq(dto.getCategoryId() ! null, HeritageProject::getCategoryId, dto.getCategoryId()) .eq(StringUtils.hasText(dto.getLevel()), HeritageProject::getLevel, dto.getLevel()) .eq(StringUtils.hasText(dto.getRegion()), HeritageProject::getRegion, dto.getRegion()) .eq(HeritageProject::getStatus, 1) .orderByDesc(HeritageProject::getCreateTime);这种写法建议原样保留到项目里答辩演示时可以现场演示查询组合展示我的接口支持 4 个维度的组合条件筛选 分页听上去就不再是普通 CRUD 了。新增和修改建议做一个保存用的 DTO把封面图、各介绍类字段、分类 id 一起接收Service 层再转换成实体入库。注意长文本字段要校验最大长度入参校验用 validation 的 NotBlank、Size不要省。我见过有人直接在接口层接收实体类结果前端传了一个 status 字段把状态改了这种越权问题在毕设里虽然不扣太多分但被老师点到很尴尬。4.3 文件上传与静态资源映射非遗系统里图片是刚需。封面图、传承人照片、作品照片。Spring Boot 接收 MultipartFile 比较简单但容易在路径上踩坑。我习惯在配置里指定上传目录再通过 Value 注入而不是把路径写死在代码里。上传方法的核心逻辑是校验文件非空校验大小和扩展名jpg/png/webp用 UUID 原扩展名生成新文件名目标目录不存在则自动创建写到磁盘返回访问路径路径映射要这样配Override public void addResourceHandlers(ResourceHandlerRegistry registry) { String uploadPath file: uploadDir /; registry.addResourceHandler(/upload/**) .addResourceLocations(uploadPath); }如果不加这段映射浏览器打开 /upload/xxx.jpg 会被返回 404但 idea 进程里文件明明存在。这个坑我见过很多次源码跑起来后也常遇到务必先检查。还有一个细节是拦截器放行 /upload/**不然图片路径访问时被 JWT 拦截器拦住前端图片全挂。4.4 审核流程的完整闭环审核功能是这个项目让我觉得做得不亏的一个模块。核心逻辑如下申报人创建/修改项目后点击提交申报将项目审核状态置为待审核插入一条申报审核记录状态为待审核审核人打开待审列表查看项目详情与历史记录点击通过项目审核状态置为通过记录表更新当前记录状态为通过点击驳回项目审核状态置为驳回记录表更新当前记录状态为驳回同时填写驳回意见这里要处理一个细节同一项目被驳回后重新申报不能把旧记录覆盖了而是再插入一条新的待审核记录。历史记录和最新记录要分开。实现上我做的是一个追加式记录表每条流转都保留项目表里只存当前状态。配合统计模块可以按级别统计出国家级项目总数省级项目总数待审核项目数再用柱状图或饼图展示。数据统计功能是从普通管理系统进化到有分析价值管理系统的标志强烈建议做代码量不大论文里能多一章测试数据。5. 源码跑通实录环境、配置与启动时的坑5.1 环境准备与项目导入如果你下载的源码是 Maven Spring Boot 工程至少要准备 JDK 1.8 或更高版本、Maven 3.6、MySQL 5.7/8.0、IDEA。数据库脚本一般放在 sql/ 目录下执行建库脚本就能把表和初始数据一次性建好。导入时有一个常见的恶心问题IDEA 识别不到 Maven 依赖或者识别到了但 jar 包下载很慢。换阿里云镜像源基本立竿见影。在 Maven 的 settings.xml 的 mirrors 节点加一段阿里云镜像地址即可这个很多教程说过但我还是要重复一遍因为真的太多人卡在第一关。项目里如果是前后端分离前端目录下的前端工程要先执行安装依赖命令装完再启动开发服务。如果本地 node 版本很新偶尔会遇到 node-sass 报错解决方案是升级前端依赖或者改用 sass具体看源码里用的是哪个版本。5.2 application.yml 里最容易改错的地方我给的配置里有五处是移植到别的电脑上必须改的配置项典型值必须改点spring.datasource.urljdbc:mysql://localhost:3306/nonheritage?useUnicodetruecharacterEncodingutf8把数据库名改成自己建的库名spring.datasource.usernameroot你的数据库账号spring.datasource.password123456你的数据库密码server.port8080和其他端口冲突时改file.upload-dir/data/nonheritage/upload本机绝对路径尽量不用相对路径上传目录是重灾区。明文写相对路径在 Windows 上有时能跑通换台机器就 404改配置又要重启。我直接建议写死一个本机绝对路径目录不存在时代码会自动创建稳妥。另外MySQL 8 和 MySQL 5.7 的驱动类写法与 URL 略有差异。多数源码默认兼容 5.7如果是 MySQL 8URL 连接参数加 serverTimezoneAsia/Shanghai 会更稳否则可能出现时区相关报错。5.3 启动之后常见的三个报错跑这个项目时我记录过三个高频启动问题逐个说原因和解决思路。第一个是端口被占用。表现为启动时最后一行报绑定异常直接用命令查一下谁占用了 8080关掉其他服务或者改 server.port 都可以。第二个是数据库连不上。报连接失败时先不要乱改配置先去 MySQL 命令行执行 select 1确认数据库本身能连。很多时候是密码里含特殊字符URL 里又没做转义导致的。第三个是查询列表返回空数据。用了 MyBatis-Plus 后查询列表一直返回空经常是因为实体类没加表名注解表名映射不上。实体类名如果和表名不同记得加 TableName 注解。这个错误非常迷惑因为日志里可能看不出明显报错一查数据就是空的。我第一次排查花了两个小时。6. 论文怎么写、答辩怎么答才有区分度6.1 论文框架的搭法虽然项目叫毕设但最终考核的一半在论文。我给一个自己用了效果不错的章节框架绪论背景与意义、国内外研究现状、主要工作、相关技术介绍Spring Boot 原理、MyBatis-Plus、JWT、Vue、系统分析可行性分析、功能性需求、非功能性需求、系统设计架构设计、模块设计、数据库设计、接口设计、系统实现登录模块、项目管理、申报审核、文件上传等、系统测试测试环境、测试用例、测试结果、总结与展望。这个框架是老套路但胜在稳。真正能拉开差距的是数据库设计章节——把表关系图和 E-R 图画清楚。答辩老师问我第一版为什么这样建表时能顺出为什么引入分类表、为什么要单独建审核记录表这种理由就实现了从抄框架到由自己设计的跨越。论文里不要把大段代码贴上去。老师更想看的是关键代码的说明和思路流程整页贴代码会让人觉得你没东西写而且答辩时没人会看代码细节。6.2 答辩高频问题怎么答如果把这套系统交给别人去答辩我总结过几类必问问题为什么选 Spring Boot答自动配置降低集成成本、内嵌 Tomcat、生态庞大、与 MyBatis-Plus 配合开发效率高且作为企业主流框架有工程价值。JWT 和 Session 的区别答Session 服务端存储、有状态、依赖 CookieJWT 无状态、自包含、可跨域适合前后端分离场景。审核流程怎么设计答引入状态字段和审核记录表状态流转为待审核到通过/驳回驳回后可再次提交所有操作留痕。文件上传怎么防畸形文件答校验扩展名、限制大小、UUID 重命名有条件再加文件内容头校验。如果数据量大当前分页查询会有什么问题答深分页出现慢查询可以改游标分页查询条件多变可以加索引。这些题目我在项目总结阶段自己都练过一遍答辩当天基本不会出现完全懵掉的状态。6.3 系统还能怎么升级项目做完不等于没得做。如果你想用这个系统冲击更高分可以从四个点扩展用 Redis 做缓存和接口限流非遗项目访问排行这种动态数据放缓存里非常合适引入 ElasticSearch 做全文检索支撑历史渊源这类长文本的搜索把文件上传切换到对象存储避免服务器磁盘不足答辩时可以讲对象存储和 CDN 策略做一个数据可视化大屏用 ECharts 把非遗项目分布、传承人年龄结构做成可视化视觉效果拉满。前端展示门户也可以做成公开访问游客不需要登录就能浏览非遗项目和传承人列表后台管理才要求登录。这个改动不算大但让管理系统变成展示管理一体的系统功能完整性大幅提升论文的需求分析章节也会好写很多。我个人做完这套系统最大的收获是选对业务场景比堆砌再多的框架和库都能带来更扎实的完整感。非遗这类有真实业务背景的题目天然提供了分类、审核、统计、权限这些可以拿出来讲的能力。哪怕你最终只是把源码跑通、把论文按部就班写完沉淀出的对 Spring Boot 全链路流程的理解也远超过再做十个图书管理系统。最后再分享一个小经验拿到源码后不要急着改功能先按默认配置把项目原样跑起来再对着数据库表把每个模块的页面点一遍。这个熟悉过程花不了半天但会让你对系统的理解完全不一样答辩时哪怕源码里的代码不是你写的你也能说出这个模块我改过、那个接口我调试过这个状态才是毕设最理想的交付状态。
返回列表