ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

基于RuoYi的Java档案管理系统实战:从表设计到权限落点

基于RuoYi的Java档案管理系统实战:从表设计到权限落点 简介面向Java全栈学习者以及RuoYi快速开发平台的使用者这份基于RuoYi开发的档案管理系统完整源码能够帮助理解典型前后端分离项目中的架构设计、权限控制与业务功能扩展方式适用于课程设计、毕业设计或企业档案信息管理模块的参考实现。压缩包共包含812个文件大小约99.27MB其中以367个Java源文件、116个Vue文件、101个JavaScript文件为主体辅以XML、SQL、YAML等配置文件及Shell、BAT脚本完整覆盖后端服务逻辑、前端交互页面、数据库脚本、环境变量与自动化构建流程此外还包含SVG、SCSS、VM模板等资源便于按需调整界面样式与页面模板。目前已有970人浏览学习适合希望动手实践RuoYi框架的开发者。透过这份源码读者可对照学习RuoYi中用户、角色、菜单权限的实现思路掌握Java与Vue之间的接口联调方式也能借助批处理脚本快速启动前后端环境减少本地搭建成本附带的Word/PDF说明与环境配置样例对理解部署流程、定位常见问题也有直接帮助。1. 基于RuoYi的Java档案管理系统这套源码到底能帮你省多少事接手过传统档案管理系统的Java工程师大概率都经历过这种场景代码是十年前的 SSH 结构档案表里存着密级、保管期限、借阅记录但权限全靠if硬编码加一个角色要改三个类更别提流程审批——完全靠线下纸质单子流转。换到 RuoYi若依之后前后端分离、代码生成器、数据权限注解、操作日志这些底座直接白嫖档案管理系统的核心难点从写框架变成了设计业务表与权限落点。这篇笔记就是围绕一套基于 RuoYi 的 Java 档案管理系统源码讲清楚它解决了什么、从拉代码到跑通要动哪些地方、哪些坑是这类项目必踩的。适合两类人一是接了档案/文档类交付项目想短周期上线的小团队二是想拿若依做脚手架、但不想在权限和上传上重复造轮子的后端工程师。以下所有内容来自我用 RuoYi 落地同类系统的实操经验照着做能复现但不代表某份特定源码包的内部实现。2. 为什么选 RuoYi 做档案系统框架选型与工程目录拆解2.1 RuoYi-Vue 和 RuoYi-Cloud 怎么选三个判断标准档案管理系统的部署场景通常很固定要么是单机部署的内网环境要么是客户机房里的几张虚拟机。选若依的哪个分支别看名气看实际约束。我一般按三个标准过滤第一客户有没有多租户需求——纯内部档案系统没有RuoYi-Vue 就够第二团队有没有专职运维——没有就老老实实用单体别上 Cloud 那套 Nacos、Gateway 全家桶出问题查起来够喝一壶第三有没有历史系统要集成外部接口——档案系统常要对接 OA 或审批流RuoYi-Vue 的单体应用反而好部署一个 jar 包扔上去就行。RuoYi-Vue 本身就是 Spring Boot Vue MyBatis 的组合把用户、角色、菜单、部门、操作日志、定时任务这些系统管理底座全部做完了。档案管理系统的核心业务——档案录入、密级控制、借阅审批、到期销毁——是在这个底座上长出来的业务模块。选若依意味着你不必从零写登录鉴权、不必自己设计 RBAC 表结构这些部分在 RuoYi 里是现成的而且被大量生产项目验证过比自己造的稳。另外若依自带代码生成器档案表的增删改查页面可以直接生成再把权限和数据范围填进去一个模块的效率能提升两倍以上。有人会问 ruoyi 桌面版能不能拿来改我的建议是别碰。桌面版走的是 JavaFX 路线和大多数档案系统的 B/S 架构诉求不一致后续维护和部署都是额外的学习成本。档案系统的使用方是档案管理员和部门借阅人他们习惯打开浏览器就用你交付一个桌面客户端反而要被 IT 部门反复装环境。2.2 拉取源码后的工程目录哪些能直接用哪些要改从 Git 拉下 RuoYi-Vue 之后后端是标准的 Maven 多模块工程。刚打开的几分钟很容易懵因为模块比想象的要多但真正需要动的没几个。我习惯先把目录过一遍分清基础设施和可替换部分心里有个底再下手这是后续改动不迷路的关键——很多人在这一步跳过了结果想加个定时清理任务时找不到该放哪个模块。RuoYi-Vue 的模块粒度很清晰ruoyi-admin是启动入口Controller 和配置类都在这ruoyi-framework放的是框架级配置比如 Spring Security 过滤器链、MyBatis 配置、Redis 配置、切面日志都在这里ruoyi-system是系统管理模块用户、角色、菜单这些基础表对应的 Service 和 Mapper 全在这里ruoyi-common是通用工具包字符串处理、文件上传工具、返回结果封装都在里面ruoyi-quartz是定时任务模块。对于档案管理系统我会在ruoyi-system旁边新建一个ruoyi-archive模块专门放档案业务。为什么不直接写在 system 里因为档案模块有自己的实体类、Mapper、Service独立成模块后后续客户要扩展销毁鉴定、库房管理这些子功能时不需要动系统管理那部分代码发布时也能单独打包。模块之间的依赖关系是 archive 依赖 system 和 common不反向依赖。2.3 建库建表RuoYi 的表结构里哪些要留哪些别动RuoYi-Vue 初始化时会自动执行sql/ry_2024xxxx.sql脚本生成用户表、角色表、菜单表、部门表、字典表等十几张基础表。这里有一条铁律基础表的结构不要动。用户表加字段可以但不要去改sys_user和sys_role的关联方式一旦改动菜单权限和数据权限的链路就断了后面排查权限问题会非常痛苦。档案系统要新加的表我在项目里一般分四类档案主表archive_info存档案元数据、档案附件表archive_file存文件路径与关联关系、借阅申请表archive_borrow存借阅流程状态、审批记录表archive_approval存审批轨迹。这四张表是档案系统的最小闭环缺一张流程就断。建表脚本我习惯放在后端的sql/archive.sql里和 RuoYi 的初始化脚本分开这样客户环境初始化时能按顺序执行也能单独升级档案模块。这里还有个关键点RuoYi 的表名统一用sys_前缀档案表我建议用archive_前缀不要图省事全塞进 sys 前缀里。理由很实际——RuoYi 自带的代码生成器扫描表时可以按前缀过滤你只选 archive_ 开头的表就能生成档案模块的代码不会把系统管理表混进来后续维护的边界感也会清晰很多。3. 档案管理核心表设计与权限落点密级、借阅、归档状态怎么建模3.1 档案主表设计编号规则、元数据字段与归档状态档案主表是整个系统的数据中枢字段设计直接影响后续的检索、统计和权限控制。我常用的archive_info表结构在核心字段上长这样CREATE TABLE archive_info ( id BIGINT NOT NULL AUTO_INCREMENT COMMENT 主键, archive_no VARCHAR(64) NOT NULL COMMENT 档案编号唯一, title VARCHAR(255) NOT NULL COMMENT 档案标题, category_code VARCHAR(32) NOT NULL COMMENT 档案分类代码如 XZ/人事、CW/财务, secret_level CHAR(1) NOT NULL DEFAULT 4 COMMENT 密级1绝密 2机密 3秘密 4公开, retention_type VARCHAR(8) NOT NULL COMMENT 保管期限类型永久/长期/短期, status CHAR(1) NOT NULL DEFAULT 0 COMMENT 状态0未归档 1已归档 2已销毁 3借出中, file_count INT NOT NULL DEFAULT 0 COMMENT 附件数量, dept_id BIGINT NOT NULL COMMENT 归档部门ID用于数据权限过滤, create_by VARCHAR(64) NULL COMMENT 创建人, create_time DATETIME NULL COMMENT 创建时间, PRIMARY KEY (id), UNIQUE KEY uk_archive_no (archive_no), KEY idx_status (status), KEY idx_secret_dept (secret_level, dept_id) ) ENGINEInnoDB COMMENT档案主表;这段建表 SQL 有三个值得说明的设计决策。一是密级字段用CHAR(1)存单选值而不是字符串配合字典管理在页面上显示中文权重低、查询快也不容易写错。二是dept_id这个字段看起来只是普通外键实际上它是若依数据权限的落点——后面通过DataScope配置本部门可见时MyBatis 会自动在 SQL 上追加dept_id过滤条件不需要你在每个查询里手写。三是唯一索引uk_archive_no在数据库层面兜底档案编号重复这一步是防止并发入库时编号重复的最后一道防线。档案编号的设计建议直接用分类码 年份 四位流水号的拼接规则比如XZ20240001。不要在数据库里直接存这一长串的拼接过程而是在 Service 层生成后写入。后面第 5 章会专门讲并发情况下编号重复的坑这里先留个伏笔。3.2 借阅审批流程不引入工作流引擎的状态机方案档案系统的借阅流程说复杂也复杂说简单也简单。如果客户没有强流程定制需求我不建议上 Activiti 或 Flowable 这类工作流引擎——对单体应用来说引入工作流引擎意味着学习成本、部署成本和流程设计器的维护成本同时上升而档案借阅通常只是申请→部门审批→归档管理员审批→借出→归还这条固定链路上的流转一套状态机完全够用。我用的是archive_borrow表加一个状态字段的方式。核心字段包括archive_id借哪份档案、borrow_user_id借阅人、borrow_dept_id借阅人部门、status0待审批 1审批中 2已批准 3已借出 4已归还 5已拒绝、expect_return_time预计归还时间、actual_return_time实际归还时间、apply_reason借阅事由。审批动作做在archive_approval表里每条记录保存审批人、审批意见、审批时间、审批结果这样就能完整还原一条借阅从申请到归还的轨迹。状态流转的代码实现我在 Service 层都写成显式的方法而不是散落的 update 语句比如applyBorrow()、approveBorrow()、returnArchive()每个方法里只允许从特定状态跳转到下一状态。举个例子approveBorrow()方法里必须先判断当前 status 是否为1 审批中否则直接抛业务异常。这样做的价值在于流程状态不会因为前端多点了两次按钮而错乱接口的幂等性也更容易保证。3.3 行级权限与密级可见性在若依 DataScope 之上做二次过滤RuoYi 自带的数据权限注解DataScope可以做到部门、岗位、用户三个维度的数据隔离档案系统的密级控制则是在部门隔离之上再叠加一层行级过滤。换句话说一个财务部的员工默认只能看到本部门的档案但如果这份档案密级是绝密即使同部门也不能看。这个业务规则必须和数据权限配合才能实现。我的实现方式是双层过滤。第一层用若依的DataScope注解让 MyBatis 自动追加部门条件第二层在 Mapper 的 SQL 里手动拼接密级条件。SQL 大概长这样select idselectArchiveList resultTypeArchiveInfo SELECT a.* FROM archive_info a where if testarchiveNo ! null and archiveNo ! AND a.archive_no LIKE CONCAT(%, #{archiveNo}, %) /if if testsecretLevel ! null and secretLevel ! AND a.secret_level lt; #{secretLevel} /if AND a.dept_id IN (${params.dataScope}) /where /select这里secret_level的比较用而不是原因是密级数字越大表示越公开秘密级别用户应该能看到秘密和公开的档案而看不到机密和绝密这个逻辑用小于等于比较最自然。${params.dataScope}是若依DataScope注解追加进来的 SQL 片段不需要你手动传值。这个方案有一个要注意的地方——密级判断是数字比较相当于把业务规则写死在 SQL 里。如果客户后续要求改成跨部门借阅绝密档案必须走特批流程不能只靠 SQL 解决而是要在审批方法里增加特批分支。我一般会在 Service 层加一个checkSecretLevel()方法把密级校验独立出来不管是查询还是借阅都走同一套校验逻辑避免出现查询时看不到、借阅时却能提交申请这种前后不一致的尴尬。4. 档案管理模块的后端落地三层代码、建表 SQL 与文件上传4.1 Controller、Service、Mapper 三层怎么写才能少返工若依的代码生成器可以按表生成 Controller、Service、Mapper 和 Vue 页面但生成出来的代码是能用而不是够用。我把档案模块的 Controller 代码调整成下面这种形态核心是保持薄 Controller、厚 ServiceRestController RequestMapping(/archive/info) public class ArchiveInfoController extends BaseController { Autowired private ArchiveInfoService archiveInfoService; PreAuthorize(ss.hasPermi(archive:info:list)) GetMapping(/list) public TableDataInfo list(ArchiveInfo archiveInfo) { startPage(); ListArchiveInfo list archiveInfoService.selectArchiveInfoList(archiveInfo); return getDataTable(list); } PreAuthorize(ss.hasPermi(archive:info:add)) PostMapping public AjaxResult add(Validated RequestBody ArchiveInfo archiveInfo) { archiveInfoService.insertArchiveInfo(archiveInfo); return success(档案录入成功); } PreAuthorize(ss.hasPermi(archive:info:edit)) PutMapping public AjaxResult edit(Validated RequestBody ArchiveInfo archiveInfo) { archiveInfoService.updateArchiveInfo(archiveInfo); return success(修改成功); } }这段代码有三个若依风格的要点。一是startPage()和getDataTable()是若依的现成分页封装前端表格只要传pageNum和pageSize参数后端就会自动做 PageHelper 分页不需要自己在每个方法里写 Page 对象。二是PreAuthorize(ss.hasPermi(archive:info:list))是若依的按钮权限控制这里的字符串archive:info:list要跟前端菜单管理里配置的权限标识完全一致否则会出现菜单看得到、接口调不通的权限问题。三是Validated注解配合实体类上的NotBlank等校验注解参数校验交给框架不用在方法体里写一堆 if。真正填写业务逻辑的地方是 Service 实现类。在insertArchiveInfo()里我除了做 insert还做了三件事生成档案编号、检查密级与部门匹配性、记录操作日志。这三件事放在 Controller 里也能跑但放在 Service 里能让不同入口复用——比如后面做批量导入时直接调用 Service 方法而不需要再写一遍编号生成逻辑。4.2 从实体类到数据库表MyBatis-Plus 生成建表 SQL 与若依的适配热词里经常刷到mybatisplus根据java实体类生成创建表的sql语句这个需求在档案系统里确实存在——当你的档案表字段频繁调整时手工改 DDL 再同步实体类很容易漏字段。若依默认用的是原生 MyBatis 而不是 MyBatis-Plus但很多人会引入 MP 来简化单表操作我这边的情况是能用但要做一层适配。如果你决定引入 MyBatis-Plus实体类上的注解写法如下Data TableName(archive_info) public class ArchiveInfo { /** 主键 */ TableId(type IdType.AUTO) private Long id; /** 档案编号 */ private String archiveNo; /** 档案标题 */ private String title; /** 密级1绝密 2机密 3秘密 4公开 */ private Character secretLevel; /** 保管期限永久/长期/短期 */ private String retentionType; }这是一个极其典型的 MP 实体类。TableName指定表名TableId(type IdType.AUTO)指定主键自增策略字段名默认驼峰转下划线所以archiveNo自动对应archive_no列。较新的 MyBatis-Plus 支持通过实体类生成建表 SQL 的工具但我在实际项目中不太依赖这个能力——原因是档案表通常要同时定义唯一索引、联合索引和字段备注纯注解声明表达不了这些 DDL 细节反而会生成一张能用但没有索引的裸表。更务实的做法是SQL 脚本作为唯一事实来源实体类反向生成只是辅助。也就是说先写好archive_info.sql并执行到数据库中然后用若依的代码生成器从表结构直接生成实体类保证注释、字段名、类型和数据库完全一致。如果你已经写好了实体类但还没有建表脚本也可以用 MP 的工具生成一个基础版的CREATE TABLE然后把索引和备注补进去两步合一步操作。4.3 文件上传与预览附件是直接存数据库还是存磁盘档案附件的存储选型是这个系统里争议比较大的地方。很多刚接触的人第一反应是用 BLOB 存数据库方便备份。这个想法在附件数量少、单文件不超过几 MB 时没毛病但档案系统跑一两年后附件数量轻松过万数据库会膨胀到几十 GBmysqldump一次要几十分钟查询和备份性能都会明显劣化。我最终的方案是文件存磁盘数据库只存路径和元数据这也是若依框架默认推荐的做法。若依的文件上传工具有现成的封装我在档案模块里加了一个附件上传接口PostMapping(/upload) public AjaxResult upload(RequestParam(file) MultipartFile file, RequestParam(archiveId) Long archiveId) throws IOException { if (file.isEmpty()) { return error(上传文件不能为空); } String originalName file.getOriginalFilename(); String extName StringUtils.substringAfter(originalName, .); String fileName DateUtils.dateTimeNow(yyyyMMddHHmmss) _ IdUtils.fastSimpleUUID() . extName; String filePath RuoYiConfig.getUploadPath() /archive/ DateUtils.dateTimeNow(yyyyMMdd); File uploadDir new File(filePath); if (!uploadDir.exists()) { uploadDir.mkdirs(); } file.transferTo(new File(uploadDir.getAbsolutePath() File.separator fileName)); ArchiveFile archiveFile new ArchiveFile(); archiveFile.setArchiveId(archiveId); archiveFile.setFileName(originalName); archiveFile.setFilePath(/profile/archive/ DateUtils.dateTimeNow(yyyyMMdd) / fileName); archiveFile.setFileSize(file.getSize()); archiveFileService.insertArchiveFile(archiveFile); return success(MapUtil.build(path, archiveFile.getFilePath())); }这段代码的关键点都集中在文件路径设计上。一是文件名用了时间戳 UUID的重命名方式避免客户上传两个同名文件时互相覆盖二是按日期分子目录存储每天一个文件夹后续做冷热数据分层或定期清理可以直接按目录操作不用扫数据库三是数据库存的路径是profile开头的虚拟路径若依的ResourcesConfig会把/profile/**映射到磁盘上的实际目录前端直接拿这个路径渲染图片或预览 PDF不需要后端再写一个下载接口在内存里转流。预览这块要特别提醒PDF 和图片预览很轻松浏览器原生支持但 Office 文件docx、xlsx在 web 端预览要引入额外的转换服务比如用基于 LibreOffice 的转换组件把 Office 转 PDF。如果客户预算有限我的折中方案是只做下载而非预览让用户在本地用 Office 打开这个交互改变能省掉一个服务节点的运维成本。5. 档案管理系统避坑5 个最容易翻车的地方5.1 附件存数据库导致数据库膨胀备份窗口越来越长现象客户要求把档案扫描件直接存数据库 BLOB 字段理由是数据安全好备份上线半年后数据库达到 60GBmysqldump备份一次要 40 分钟期间业务页面偶发卡死。原因大字段和业务数据混存在同一个 InnoDB 表空间里查询档案列表时即使不查 BLOB 字段InnoDB 的页节点也可能被大字段撑碎扫描性能大幅劣化。解决迁移为文件存磁盘方案数据库只保留路径和大小字段。迁移脚本用分批读取的方式每次取 500 条记录把 BLOB 写成文件更新路径字段避免一次性加载全部大字段打爆内存。这个坑我踩过一次后新项目一律先问客户附件平均多大、量级多少超过 5MB 或预期过万份坚决走文件存储路线。5.2 数据权限叠加导致密级越权低密级角色看到了高密级档案现象某个用户同时拥有档案管理员和普通借阅人两个角色结果他能检索到绝密档案的标题列表点开详情却报无权限页面表现极度分裂。原因若依的数据权限注解DataScope对多角色用户会生成并列条件比如一个角色允许查看本部门数据、另一个角色允许查看全部部门数据MyBatis 拼接出来的 SQL 条件用的是OR结果等于放开了全部数据范围。密级过滤虽然用了但没挡住部门维度的放行。解决密级不能依赖单条DataScope的叠加逻辑我在checkSecretLevel()方法里增加硬性判断——无论数据权限如何叠加用户真实的最大密级由其所有角色的最低密级数字决定也就是取最严格的那个。在selectArchiveList的 Service 方法里先查出用户的最大可见密级再作为参数传给 Mapper彻底绕开if拼接可能出现的条件失配。这个问题的排查思路也可以当成一个常见面试题来记数据权限拼接是 OR 逻辑还是 AND 逻辑决定了多角色下的可见边界。5.3 档案编号并发重复两个人同时录入生成了同一个编号现象录入高峰期出现两条archive_no完全相同的档案记录因为数据库唯一索引报错导致其中一单录入失败客户认为是系统不稳定。原因最初的编号生成是查当前最大流水号 1在并发情况下两个线程同时查到同一个最大值各自加一后都能通过应用层校验狭路相逢在数据库唯一索引上。解决我改成了 Redis 自增方案archive_no 分类码 年份 RedisINCR生成的增量值利用 Redis 单线程特性保证同一分类码下的流水号唯一。如果客户环境没有 Redis 也不想引入退而求其次用数据库表archive_sequence配合SELECT ... FOR UPDATE行锁也能解决但并发性能会下降一个量级。这里有一句血泪经验唯一索引一定要留着它是数据正确性的最后一道防线哪怕应用层逻辑写得再完美也别删掉这个兜底。5.4 修改密级后列表还在显示旧值清除缓存才是关键现象档案管理员把一份档案从机密改成公开用户在列表页刷新后仍然看不到但直接查数据库已经改了。原因若依的框架里字典数据和部分业务数据会缓存在 Redis 中列表查询接口如果加了Cacheable或使用了 Redis 缓存工具类更新操作后如果没有主动清除缓存用户拿到的一直是旧数据。解决在updateArchiveInfo()方法里更新成功后立即调用缓存删除操作并顺手把该档案的借阅状态缓存也清掉——因为密级变更可能影响当前正在审批中的借阅单。遇到这类问题不要急着改缓存配置先在方法里搜一下有没有RedisCache的调用通常删掉对应 key 就能解决。后续如果数据量大了建议引入缓存版本号字段每次更新密级时版本号加一查询 key 带上版本号从根上避免 改了一个地方、忘删另一个缓存 的更新遗漏。5.5 大文件上传报 413 或超时Nginx 和前端配置要一起调现象上传 200MB 的工程图纸 PDF 时进度条走到一半提示网络错误或者直接报 413 Request Entity Too Large。原因Nginx 默认client_max_body_size是 1MBSpring Boot 默认的spring.servlet.multipart.max-file-size也是 1MB前端 axios 默认没有设置超时时间任何一个环节不调都会导致上传失败。解决Nginx 配置加client_max_body_size 500m;后端application.yml里把两项参数调大spring: servlet: multipart: max-file-size: 500MB max-request-size: 500MB前端 axios 请求里显式设置timeout: 600000让大于 100MB 的文件有足够时间上传。这三处一起改才能彻底解决缺一处都会以不同形式翻车——Nginx 没调报 413后端没调报 MaxUploadSizeExceededException前端没调报 timeout。如果客户文件常态化超过 500MB就要考虑分片上传或引入 MinIO 这类对象存储方案光靠单体应用扛不是长久之计。6. 让档案系统从能用变好用三个进阶验证技巧6.1 权限边界用接口测试用例验证而不是手动点页面改动数据权限相关的代码后我最怕的就是自己测没问题、客户一用就出事。原因是人工点页面只会用管理员账号测很难覆盖多角色、多密级组合。我后来定了一个规矩每次改权限逻辑必须跑一遍接口测试用例至少覆盖这四个场景——绝密档案对普通角色不可见、机密档案对同部门秘密角色不可见、部门数据权限用户看不到其他部门档案、同一用户多角色时取最严格密级。用 Postman 或 JMeter 写断言脚本比反复人工登录退出高效得多也方便交给新同事快速熟悉这套权限规则。6.2 借阅全流程追踪把操作日志串成一条业务链若依自带的Log注解记录的是操作日志但它是离散的——用户申请借阅是一条日志管理员审批是另一条日志两条日志之间只有时间先后关系没有业务关联。我加了一张archive_borrow_log表每条借阅单从申请动作开始就生成一个borrow_no后续的审批、借出、归还、拒绝全部带着这个borrow_no写入日志表。好处是出问题时只要拿borrow_no一查整条链路一目了然不用翻操作日志表格去猜哪个请求对应哪份档案。监听器实现在ArchiveBorrowServiceImpl的关键方法里调用一个独立的borrowLogService.record()方法记录时间、操作人、动作、备注。这个设计对后续统计哪些档案借阅最频繁也有帮助一张表同时服务审计和运营分析。6.3 归档文件指纹校验防止上传后文件被篡改档案文件的完整性要求比普通业务附件高特别是涉及合同、竣工验收资料的归档。我在上传接口里增加了 SHA-256 指纹计算文件落盘后立刻计算摘要存入archive_file表的file_hash字段。每次下载或定期巡检时重新计算一次文件摘要和库里存的比对不一致就报警。这个逻辑代码量不大——DigestUtils.sha256Hex(inputStream)一行调用就能拿到摘要但要处理大文件的分批读取不能把整个文件一次性加载到内存。别小看这个功能档案管理部门对文件完整性是有硬性要求的我之前因为没有加指纹校验出现过一次文件在磁盘上被误修改、客户审计时Discovery的问题补上校验后类似风险才算真正控住。这里还有一个常被忽略的细节文件重命名后指纹不会变但文件路径变了所以校验时应该先按 ID 查库拿库里的路径去读文件不能靠前端传路径过来直接算。我在这上面吃过亏前端传一个拼接路径就去校验结果文件挪了目录后校验一直失败查了半天才发现是路径问题。现在统一在 Service 层按主键查路径再执行校验没有再犯过同样的错。做档案管理系统这些年我最大的感受是RuoYi 把框架层的活干完了真正决定项目成败的是业务表和权限边界的设计——这两块想清楚开发速度会快得超乎想象想不清楚后面每一步都在还债。这套基于 RuoYi 的 Java 档案管理系统方案从表结构、状态机、密级控制到文件存储我都踩过坑也填过坑写出来的都是验证过的路径。希望帮到你下次接手档案类需求能少走一段弯路。本文还有配套的精品资源点击获取
返回列表