首页 / 资讯中心 / 文章详情

SpringBoot2+Vue3+MyBatis-Plus馆藏管理系统全栈开发实践

SpringBoot2+Vue3+MyBatis-Plus馆藏管理系统全栈开发实践 ★ FEATURED ARTICLE
博物馆、档案馆、文化馆这类单位的信息化项目我做下来觉得最核心的问题不是技术本身而是“台账怎么电子化才不乱”。这里分享一个基于 SpringBoot2 Vue3 MyBatis-Plus MySQL8.0 构建的线上历史馆藏系统整套源码我近期整理过也配了完整文档正好可以拿来讲讲一个馆藏类管理系统从前到后是怎么落地成型的。这套系统的核心目标很朴素把线下纸质文物账本变成可检索、可追溯、可权限管控的电子台账同时覆盖藏品登记、分类管理、库房派存、借展记录、修复记录和用户权限管理这些日常业务。适合准备做全栈项目练手的人、正在做相关毕设的同学以及单位内部确实需要一套轻量级藏品管理后台的开发者。下面我把这个项目从技术选型、数据库设计、后端实现、前端联调到部署运维的完整过程拆开说中间穿插不少实际踩过的坑照着思路走能少走很多弯路。1. 项目整体设计与技术选型思路1.1 馆藏系统的核心需求拆解先别急着写代码拿到“历史馆藏系统”这个需求时第一件要做的事是把业务模型看清楚。馆藏系统不像电商那样订单满天飞它的数据特点是“资产台账 流转记录”一件藏品从入馆登记开始要经历编目、定级、排架、借展、修复、盘点等一系列动作。每个动作都会改变藏品的状态而所有状态变化都必须留痕。我在设计时把需求拆成了三层最底层是基础的档案数据也就是藏品主表中间层是业务动作数据比如借展记录、修复记录、出入库流水最上层是系统管理数据包括用户、角色、菜单这些权限相关的表。这套分法和大多数后台管理系统是一致的但馆藏系统有个特殊点藏品的分类体系和存放位置结构必须单独建模不能简单塞一个字段。因为实际操作中你不但要回答“库里有一件唐代的瓷器”还得回答“它存放在3号库房第2排第5格”这种层级化的查询需求直接影响数据库设计。确定好业务模型之后再把非功能性需求列出来比如操作日志、数据备份、附件上传。这些模块看似不起眼但上线之后使用频率极高。我见过不少项目把附件路径直接存在业务表里结果后期文件一多根本没法管理所以这个项目里我把文件上传单独拆了一张 file 表业务表只关联 fileId这套做法值得保留。1.2 技术栈选型背后的考量选型不是越新越好而是看团队熟悉度和项目复杂度。这个项目技术栈一共四样后端 SpringBoot2前端 Vue3持久层 MyBatis-Plus数据库 MySQL8.0我把选型理由和对应场景整理成了表技术栈选择理由使用场景SpringBoot2自动配置完善生态成熟中小型系统开发效率高后端接口服务、定时任务、文件处理MyBatis-Plus通用CRUD 条件构造器大幅减少手写SQL量复杂查询仍可控单表操作、批量写入、分页查询Vue3Composition API 逻辑复用方便配合 Vite 构建效率高后台管理页面、表单交互、数据可视化MySQL8.0utf8mb4 字符集、窗口函数、JSON 字段支持应对馆藏数据绰绰有余核心业务表存储、检索统计有人可能问为什么不用 SpringCloud 微服务或者为什么不选 JPA。答案是馆藏系统的并发量和使用规模单体应用完全扛得住微服务反而会把架构复杂度拉高。MyBatis-Plus 对比 JPA 的最大优势在于馆藏系统这种需要频繁做“多条件组合查询”的场景用 LambdaQueryWrapper 写条件比 JPA 的 Specification 更直观而且团队里已经有不少 SQL 老手MyBatis-Plus 保留的 SQL 自由度对排障也有帮助。Vue3 这块也没什么悬念后台管理系统是 Composition API 最典型的应用场景逻辑复用干净代码组织清晰。MySQL8.0 则是实打实的数据底座后面第三章我会展开讲它的表结构设计和优化点。1.3 项目工程结构怎么划分选型定了之后工程结构直接决定代码能不能长期维护。我没有用那种包名乱飞的分层方式而是在单体目录下做了模块化。后端大致是 controller、service、mapper、entity、config、common 这几个主包common 下面再放统一的返回体、异常处理、常量工具。这么做的好处是新增一个功能模块时你在每个包下各加一个类即可新人接手也能很快找到对应文件。前端这边我用 Vue3 Vite 搭建目录按 views、components、api、router、store、utils 划分。views 下面按业务模块建子目录比如 collection、exhibition、systemapi 目录里每个文件对应一个后端模块的接口方法。组件层面只抽公共组件业务组件就放在对应页面里避免过度抽象导致页面跳转都找不到组件在哪。工程结构确定后我把整个项目的设计文档和数据库脚本同步整理出来也就是标题里提到的“含文档”。这个动作相当重要因为源码只能表达“怎么实现”文档才能表达“为什么这么实现”。后面第六章我会专门讲讲文档怎么写才对接手的人有价值。2. 数据库设计MySQL8.0 下的馆藏核心模型2.1 藏品主表和扩展字段的取舍数据库是一个管理系统的地基我已经反复吃过设计不合理的亏。馆藏系统的核心表是藏品主表 collection它的字段设计要同时满足固定属性和灵活扩展的需求。固定属性包括藏品编号、名称、年代、质地、级别、来源方式、当前状态等但馆藏单位不同藏品属性差别挺大有的单位还要记录完残程度、入馆凭证号、保险估值之类。如果把这些全做成字段表结构会被撑得很难看。MySQL8.0 的 JSON 类型在这时候就派上用场了。我在 collection 表里留了一个 extra_json 字段用来存各单位自定义的扩展属性同时用 entity 表里固定的核心字段保证高频查询和列表展示的性能。实际操作中核心字段建普通索引扩展属性只做详情展示不参与主查询条件这样既灵活又不至于索引失效。给个参考建表片段CREATE TABLE collection ( id bigint NOT NULL AUTO_INCREMENT, code varchar(64) NOT NULL COMMENT 藏品编号, name varchar(256) NOT NULL COMMENT 藏品名称, era varchar(64) DEFAULT NULL COMMENT 年代, material varchar(64) DEFAULT NULL COMMENT 质地/材质, level tinyint DEFAULT NULL COMMENT 珍贵级别, category_id bigint DEFAULT NULL COMMENT 分类ID, room_id bigint DEFAULT NULL COMMENT 库房ID, status tinyint NOT NULL DEFAULT 1 COMMENT 状态1在库 2借展 3修复 4下架, cover_url varchar(512) DEFAULT NULL COMMENT 封面图片, extra_json json DEFAULT NULL COMMENT 扩展属性, deleted tinyint NOT NULL DEFAULT 0 COMMENT 逻辑删除, create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_code (code), KEY idx_cat_status (category_id, status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT藏品主表;唯一索引 uk_code 保证同一单位的藏品编号不重复联合索引 idx_cat_status 覆盖了“按分类查状态”的高频查询场景。这种设计下列表页的过滤条件基本都能命中索引数据量到几十万条也不慌。2.2 库房、借展、修复这些关联表怎么建模藏品主表之外关联业务表的设计也很有讲究。库房表 storage_room 我用两级模型一张表存库房和排架位parent_id 指向父节点这样在界面上可以做成树形结构。每一件藏品都有一个物理存放位所以藏品主表里留了 room_id 指向最末级节点。借展表 exhibition_record 不直接改藏品表里的状态而是用一条记录来保存“借出时间、归还时间、接收单位、经手人、备注”同时把藏品主表的 status 字段同步改为 2借展或改回 1在库。为什么不只改状态不留记录呢因为馆藏系统的审计要求很严格每一次状态变化都得查得到原因。这种“业务动作记录表 主表状态字段”的配合方式是馆藏类的标准玩法。修复表 restore_record 同理记录修复时间、修复内容、修复单位、费用等。还要注意一个细节关联表外键我一般不在数据库层面强加约束而是在 service 层用代码保证引用完整性。原因很简单馆藏系统未来做数据迁移时如果外键约束太强会非常痛苦。对于数据的完整性靠应用层事务去控制后面 2.4 节会提到。2.3 常见检索场景和索引优化馆藏系统真正的技术难点不在增删改而在“模糊检索”和“组合筛选”。用户经常输入一个藏品名称片段同时选择年代和分类期望秒出结果。这里如果直接 SELECT ... WHERE name LIKE %唐代%字段没索引时全表扫描会越来越慢。我在索引设计上用了两套方案一是名称字段的前缀索引适合“以关键字开头”的脑补式搜索二是用 MySQL8.0 内置的 ngram 全文索引专门解决中文分词问题。全文索引的创建语句类似 FULLTEXT KEY ft_name(name) WITH PARSER ngram检索时用 MATCH(name) AGAINST(唐代 IN NATURAL LANGUAGE MODE)。实测在几十万条数据的表上全文索引的响应速度远快于模糊匹配。当然全文索引也有局限比如对短词的支持一般所以业务层面还是把 LIKE 和全文索引都保留根据查询参数自动路由。MySQL8.0 的窗口函数也是这类系统的一个加分项。比如我想在一个列表里显示“每个朝代收藏数量排名前5的藏品”用 ROW_NUMBER() OVER(PARTITION BY era ORDER BY create_time) 就能一条 SQL 搞定不需要写复杂的子查询和临时表。这是 8.0 带给开发者的红利旧版本 MySQL 做同类统计要麻烦得多。2.4 数据一致性和事务控制馆藏数据错一笔可能都要出大问题所以一致性是这个项目的红线。系统里有几个需要事务保护的场景录入藏品时除了插入主表还要写一条入库流水借展发起时要改藏品状态同时插入借展记录修复完成时要更新修复单可能还要调整藏品状态。这些跨表操作我统一在 service 层方法上加了 Transactional。另一个容易踩坑的地方是唯一索引和逻辑删除的冲突。如果藏品编号做了唯一索引删除时用逻辑删除标记 deleted1再次插入相同编号的藏品位会导致唯一索引冲突。我处理时没有简单地把编号拼上 deleted 状态而是在唯一索引里加入了 deleted_tag 字段新记录 deleted_tag 取主键ID删除时把 deleted_tag 改成当前时间戳这样同名编号不会被唯一索引拦住业务上也说得通。遇到并发场景比如两个人同时登记同一编号的藏品我在 insert 前置阶段做一次编号查询数据库层面再用唯一索引兜底基本不会出问题。3. 后端实现SpringBoot2 MyBatis-Plus 落地细节3.1 MyBatis-Plus 怎么接入和配置后端代码里MyBatis-Plus 承担了绝大多数单表和简单联表的 CRUD。接入方式不复杂pom 引入 mybatis-plus-boot-starter然后在 application.yml 里配置逻辑删除、驼峰映射和分页插件mybatis-plus: configuration: map-underscore-to-camel-case: true global-config: db-config: logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0分页插件在配置类里声明一个 MybatisPlusInterceptor Bean添加 PaginationInnerInterceptor之后调用 Page 对象就能完成分页查询。我这里把常用的 BaseMapper 方法做个总结方便对照场景使用方式单条按ID查selectById条件单查selectOne(LambdaQueryWrapper)分页条件查selectPage(page, wrapper)批量新增saveBatch(list)批量按ID删removeBatchByIds(ids)条件更新update(null, LambdaUpdateWrapper)使用 MyBatis-Plus 最大的感受是常规业务可以完全不用写 XML SQL代码量能比传统 MyBatis 少一半。但也要克制遇到多表关联这种复杂查询我建议还是老老实实写 Mapper XML 或者 Select 注解而不是硬用 QueryWrapper 去拼 join因为 QueryWrapper 不支持多表关联强行嵌套反而可读性极差。3.2 统一响应体和异常处理和前端联调时最怕各接口返回格式不统一。这个项目从一开始就固定了 Result 结构code、message、data 三个字段。成功时 code200业务异常时 code 变成自定义错误码系统异常 code500。所有 controller 接口直接返回 Result 对象由全局异常处理器统一兜底。异常处理这块我用 RestControllerAdvice 加 ExceptionHandler。业务异常 BizException 绑定了枚举错误码比如藏品编号重复、文件类型不允许、参数校验失败等意料之外的异常统一打印日志并返回“系统繁忙”。这一套做完前端 axios 拦截器只需要看 Result.code 就能统一提示代码非常清爽。特别是文件上传场景如果后端直接抛了异常前端 upload 组件的 on-success 是等不到回调的只有统一异常处理才能把错误转换成可读的 JSON 响应。3.3 权限模型RBAC 行级数据权限馆藏系统不是面向公众的开放平台而是内部办公系统所以权限控制必须精细到角色和数据范围两个维度。我在用户表、角色表、菜单关系表的基础上实现了经典的 RBAC 模型超级管理员拥有全部权限业务管理员可以操作藏品和审核普通录入员只能新增和编辑自己负责的库房数据访客只能查看。实现上我用 JWT 做登录态。登录成功后服务端生成 token前端每次请求在 header 里携带后端通过拦截器解析 token 并把当前用户信息放入 ThreadLocal 上下文。对于需要权限校验的接口用自定义注解标注然后在 AOP 里判断角色代码整洁也不侵入业务。行级数据权限这块我遇到的实际需求是“录入员只能看到自己库房的藏品”。如果只在查询时手动加条件每条 SQL 都得记得补很容易漏。我在拦截器层面做了数据权限的自动拼接解析当前用户绑定的库房范围如果角色没有全部库房权限就自动在 SQL 上追加 AND room_id IN (...)。这个能力基于 MyBatis-Plus 的 InnerInterceptor 实现属于比较进阶的用法但对这类多租户式场景价值很大。3.4 文件上传与图片访问路径藏品封面和附件是这个系统的刚需。上传我用 MultipartFile 本地磁盘存储 Nginx 静态映射的方式不引入额外的对象存储中间件降低部署复杂度。上传文件的逻辑校验文件大小和扩展名按日期创建目录生成随机文件名最后把访问 URL 写入 sys_file 表。限制文件类型时不要光看扩展名还要读一下文件的 Content-Type防止被改扩展名绕过。这里有一个新手容易犯的错保存文件时只存了磁盘路径页面显示图片直接引用本地绝对路径线上部署后根本访问不到。正确做法是存相对路径或完整 URL由 Nginx 或网关做静态资源映射开发环境和生产环境只需改配置前缀。图片访问路径如果涉及跨域也需要在 Nginx 层统一加跨域头否则前端经常出现图片能打开但 canvas 或上传组件获取不到内容的情况。4. Vue3 前端Vite Element Plus 搭建与联调经验4.1 Vue3 工程化搭建与技术取舍前端我直接选了 Vite 作为构建工具Vite 的冷启动和热更新体验比 Webpack 好很多Vue3 项目基本已经是标配。创建项目用的 npm create vitelatest然后手动安装 vue-router、pinia、axios 和 element-plus。有人会问要不要用 TypeScript这个项目考虑到团队习惯没有上 TS但结构上保留了类型友好的写法。对于上 TS 的项目我也顺手整理过若依 Vue3 TS 模板的报错处理方式后面 5.4 节提到。Composition API 和 Options API 的区别在这个项目里体现得很明显。简单页面用 Options API 也够用但当多个页面都需要“加载状态、分页参数、查询条件”时Composition API 可以用自定义 hook 把这套逻辑抽出来。我写了一个 useCollectionList 的 hook负责调用接口、维护 loading、刷新列表页面组件里只需要调用这个 hook 再绑定模板复用效率大幅提升。对于 Vue3 新手我建议直接学 Composition API不用再惦记 Options API 的老写法。前端目录结构按业务域拆router 用 createRouter 配置静态路由store 用 Pinia 管理当前用户信息和权限标记。这里有个取舍如果菜单权限由后端动态下发路由需要改成动态注册模式如果只是固定菜单静态路由就够。我做了固定菜单 按钮级权限控制的方案权限标记用自定义指令 v-permission 控制按钮显隐简单有效。4.2 核心页面藏品列表、搜索与分页藏品列表页是前后端联调的练兵场。实现思路搜索表单上放年代、分类、关键字几个筛选条件点击查询触发列表接口接口返回的数据绑定在 el-table 上底部用 el-pagination 处理分页。Vue3 下用 ref 定义响应式数据onMounted 里调用初始化方法。script setup const searchForm ref({ keyword: , era: , categoryId: null }) const tableData ref([]) const total ref(0) const loading ref(false) async function fetchList(pageNum 1, pageSize 10) { loading.value true const res await listCollections({ ...searchForm.value, pageNum, pageSize }) tableData.value res.rows total.value res.total loading.value false } /script搜索按钮和重置按钮的逻辑也和大部分后台一样但有一个小优化搜索表单我在输入关键字处加了 debounce 防抖当用户输入完停住 500ms 后自动触发查询省得频繁点搜索按钮体验顺滑很多。表格里的藏品封面用 el-image 懒加载缩略图统一加 style 限定尺寸避免原图过大拖慢页面。4.3 axios 封装、响应拦截与文件下载所有接口请求都走一个封装好的 http 实例。axios.create 设置 baseURL 和 timeout请求拦截器里把 token 从 Pinia 或 localStorage 取出来加到 header响应拦截器里先剥掉包装层如果 code 不是 200 则统一用 ElMessage 报错并针对 401 做跳转登录的处理。下载文件这块也有讲究。如果是后端返回文件流axios 默认无法把 blob 直接给到浏览器下载要在响应拦截器里判断 responseType 是不是 blob然后单独走下载逻辑const blob new Blob([res.data], { type: application/vnd.ms-excel }) const link document.createElement(a) link.href URL.createObjectURL(blob) link.download filename link.click()导出藏品台账就是走的这条链路用户点击导出后稳定拿到 Excel 文件。要特别注意的是后端在导出接口的响应头里要正确设置 Content-Disposition文件名做 URL 编码否则中文乱码会非常难看。4.4 表格、表单和上传组件的配合馆藏系统的信息录入页面比普通表单复杂因为藏品字段多还要带图片上传。Element Plus 的 el-form 配合 rules 做校验日期选择器用 el-date-picker年代建议用下拉框而不是自由输入免得有人填“唐”有人填“唐代”。表单提交时先 validate成功后调新增接口再返回列表页刷新。上传图片我用了 el-upload 组件设置 action 指向后端上传接口name 设为和后端接收参数一致on-success 里判断响应码。我踩过的坑是一旦后端返回结构不是前端预期的结构on-success 永远不触发反而会触发 on-error。比如后端异常处理返回了 code500 的 JSON上传组件就认为成功了页面却拿不到图片 URL。解决方法是把 on-success 的响应体强校验同时利用 on-error 兜底错误提示。这一块的坑对于所有使用 Element Plus 上传组件的项目都有参考价值。5. 常见问题与排查技巧实录5.1 前后端跨域问题联调阶段最频繁遇到的就是跨域我用了一段典型的报错“Access to XMLHttpRequest at ... has been blocked by CORS policy”。解决方案很简单后端配置一个全局 CorsFilter允许指定 origin、方法、请求头。注意不要用 CrossOrigin 加在 Controller 上因为一个接口漏加就又要排查半天。还有一个细节是当接口报错时响应头可能不带 CORS 信息浏览器显示的跨域报错其实是业务异常被跨域拦截的假象排查时要先看接口本身是否通。5.2 MySQL8.0 连接串和时区问题MySQL8.0 的驱动类名是 com.mysql.cj.jdbc.Driver连接串要带 serverTimezone。这个问题我见过不少人栽跟头不配时区启动时直接报连接错误。正常配置jdbc:mysql://localhost:3306/museum?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalseallowPublicKeyRetrievaltrueallowPublicKeyRetrievaltrue 是针对 MySQL8 的认证方式本地开发经常需要加上否则连接时可能报 Public Key Retrieval is not allowed。生产环境建议去掉 SSL 相关参数同时连接池把 druid 或 hikari 的 maximum-pool-size 调到一个合理的值避免高峰期连接数不够。5.3 Lombok 编译报错开发过程中有一个经典的报错“You arent using a compiler supported by lombok, so lombok will not work with your project.” 这个问题一般发生在 JDK 版本升级之后或者 IDEA 的 Lombok 插件版本太旧。我处理过两次一次是升级 lombok 依赖版本到 1.18.30 以上解决另一次是 IDEA 里勾选了 “Enable annotation processing”。这种问题在协作开发里特别影响士气因为只有一个同事编译不过其他人好端端的排查方向先锁定 IDE 注解处理和 Lombok 版本。5.4 若依 Vue3 TS 报错的参考处理因为看过不少人在用若依框架的 Vue3 TS 版本时遇到类型报错这里顺手整理一下通用处理方法。第一种是 vue-tsc 严格模式报错解决方案是把 tsconfig 的 strict 改为 false第二种是导入组件时找不到类型声明需要在 env.d.ts 里补充声明文件第三种是第三方库本身类型不完整用 // ts-ignore 或声明模块绕过去。虽然本项目没上 TS但 vue3 后台管理的类型问题大同小异遇到不要慌先把报错信息读明白再动手。5.5 MyBatis-Plus 批量插入性能优化馆藏系统初始化导入历史数据时动辄几千上万条藏品记录入库一条一条 insert 非常慢。MyBatis-Plus 的 saveBatch 默认批量大小是 1000但如果连接串没有开启 rewriteBatchedStatementstrueMySQL 并不会真正合并 SQL 去执行性能提升有限。我在连接串里加上 rewriteBatchedStatementstrue 之后批量导入速度提升了一个量级。这也是 MyBatis-Plus 批量操作中最值得记住的一个参数。6. 项目部署与文档沉淀6.1 前后端打包与 Nginx 部署部署环节我走的是经典的前后端分离方案后端打成 jar 包跑在服务器前端 Vite 构建出 dist 静态目录交给 Nginx 托管。后端打包用 Maven 的 mvn clean package生成的可执行 jar 用 nohup java -jar 启动配置好 JVM 参数和日志输出文件。前端 npm run build 之后dist 文件夹里就是压缩好的静态资源。Nginx 配置核心是两部分托管前端静态页面以及把 /api 前缀的请求反向代理到后端服务端口server { listen 80; server_name museum.example.com; location / { root /var/www/museum; index index.html; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }try_files 那一行要特别留意VueRouter 使用 history 模式时必须配否则刷新页面会 404。这个坑我见得太多了很多前端部署到测试环境后反馈“页面一刷新就没了”基本都在这。6.2 数据库备份与初始化脚本数据库脚本我分成了 schema.sql 和 data.sql。schema.sql 负责建库建表data.sql 负责初始化基础数据比如管理员账号、字典数据、默认菜单。首次部署时顺序执行即可。线上运行后我用系统的 mysqldump 做每日备份备份文件保留最近 7 天再配合一个简单的 crontab 定时任务把备份文件归档。MySQL8.0 导入数据时要注意如果 SQL 文件里包含 utf8mb4 的字符编码客户端执行导入前最好执行 SET NAMES utf8mb4否则中文可能会乱码。数据库连接工具我也统一建议用 MySQL8 兼容的版本老版本的 Navicat 连 MySQL8 需要走 caching_sha2_password 验证方式有时会连不上。6.3 文档结构怎么组织才对交接有用标题里写着“含文档”这部分我必须多说两句。很多项目的文档形同虚设要么只有 README 写启动步骤要么线上文档和代码严重脱节。我做这个项目时把文档拆成三份一份是部署手册写清楚环境要求、初始化步骤、启动命令一份是接口说明按模块列出关键接口的入参出参还有一份是设计文档记录表结构、权限模型和业务流转逻辑。这样无论接手的人是运维、前端还是新后端都能各取所需。文档最大的价值是降低交接成本所以写的时候要克制不要大段贴源码而是写“为什么这么设计”和“改哪里会影响什么”。比如修改藏品状态的核心逻辑在 CollectionService 的 changeStatus 方法里文档里指出这一点后来的人改需求时就不会误伤其他模块。6.4 上线之后还能扩展什么方向这套馆藏系统上线后是能继续生长的。如果后续要做公开门户可以把藏品列表做成只读接口给门户网站调用如果要增强检索体验可以接入 ElasticSearch 做全文搜索如果要支持远程盘点可以再加移动端适配层。扩展方向很多但底层的数据模型如果一开始没搭好后面每一步都要返工。这也是我为什么在这个项目里花大量篇幅在数据建模和权限设计上而不是堆功能。我个人在实际操作中的体会是馆藏系统这种项目真正的复杂度从来不在代码本身而在业务规则的梳理和数据口径的统一。你先把“一件藏品从进馆到出馆会经历哪些状态、每个状态由谁触发、需要记录什么信息”这个问题想清楚后面的编码工作基本就是体力活。另外如果这个系统的代码框架你已经吃透了下一步想进阶的话可以从数据迁移工具、审计日志可视化、批量导入模板这几个方向继续玩这些都是博物馆数字化里非常实际的痛点。最后再分享一个小技巧这类系统上线前一定找业务人员做一次全流程冒烟测试从录入藏品到发起借展再到归还走一遍真实业务。前端和后端各自身逻辑都通但拼起来业务跑不通的情况我遇到过太多次了。这套 SpringBoot2 Vue3 MyBatis-Plus MySQL8.0 的组合本身已经很成熟只要业务模型扎实项目就成功了一大半。
阅读完成 · 觉得有帮助?
咨询建站