文件上传与诉讼资料关联表设计实战
在表外贷款诉讼模块中,我们需要支持 多文件上传 功能,例如上传判决书扫描件、庭审记录照片、协议 PDF 等,并且这些文件需要和诉讼记录进行关联。下面我结合项目中的实践,分享一下设计与实现思路。
一、文件存储核心接口
我们首先定义了 FileService
接口,主要包含文件分页、上传、删除、预签名地址获取等方法。核心方法是:
/*** 保存文件,并返回文件的访问路径** @param content 文件内容* @param name 文件名称* @param directory 目录* @param type 文件 MIME 类型* @param module 业务模块(例如 bank、system)* @return 文件访问路径*/
String createFile(@NotEmpty(message = "文件内容不能为空") byte[] content,String name, String directory, String type, String module);
实现类 FileServiceImpl
负责生成文件路径、调用底层存储(本地/MinIO/OSS 等)、保存数据库记录。
二、文件存储实现逻辑
关键实现步骤如下:
补全文件名和后缀
若文件名为空,则使用 SHA256 内容摘要作为文件名
若缺少后缀,则通过
MIME
类型补全
生成唯一存储路径
目录:例如
lawsuit
日期:按
yyyyMMdd
分目录后缀:拼接时间戳避免覆盖
最终效果类似:
lawsuit/20250908/judgement_1725805818000.pdf
上传到存储服务
调用FileClient.upload(content, path, type)
,获得文件 URL。保存数据库记录
插入到file
表,记录配置 ID、文件名、路径、URL、模块、大小等。
代码核心片段:
@Override
@SneakyThrows
public String createFile(byte[] content, String name, String directory, String type, String module) {if (StrUtil.isEmpty(type)) {type = FileTypeUtils.getMineType(content, name);}if (StrUtil.isEmpty(name)) {name = DigestUtil.sha256Hex(content);}if (StrUtil.isEmpty(FileUtil.extName(name))) {String extension = FileTypeUtils.getExtension(type);name = name + extension;}String path = generateUploadPath(name, directory);FileClient client = fileConfigService.getMasterFileClient();String url = client.upload(content, path, type);fileMapper.insert(new FileDO().setConfigId(client.getId()).setName(name).setPath(path).setUrl(url).setModule(module).setType(type).setSize(content.length));return url;
}
三、诉讼资料文件上传逻辑
业务侧只需要调用 fileService.createFile(...)
即可完成文件上传。我们以诉讼记录上传附件为例:
List<String> urls = new ArrayList<>();
if (files != null) {for (MultipartFile file : files) {if (file == null || file.isEmpty()) {continue;}try {// 调用文件服务上传String url = fileService.createFile(file.getBytes(),file.getOriginalFilename(),"lawsuit", // 文件目录file.getContentType(),"bank" // 模块标识);urls.add(url);// 保存到诉讼附件表LoanOutLawsuitFileDO f = new LoanOutLawsuitFileDO();f.setLoanId(lawsuit.getLoanId());f.setBizId(record.getId());f.setBizType("record");f.setRemark(reqVO.getRemark());f.setFileUrl(url);loanOutLawsuitFileMapper.insert(f);} catch (Exception e) {throw new RuntimeException(e);}}
}
逻辑分两步:
调用文件服务上传文件,获取 URL
将文件 URL 与业务表(诉讼记录)建立关联
这样一来,数据库中不仅有 文件存储表(FileDO
),还会有 诉讼文件表(LoanOutLawsuitFileDO
),前端在查询诉讼详情时就能把附件直接展示出来。
四、总结
通过这种方式,我们实现了一个 通用文件上传模块 与 业务文件关联表 的设计:
文件模块(infra.file):负责文件统一管理、存储、访问
业务模块(bank.lawsuit):通过文件 URL 与诉讼业务建立关联
这样既能保证文件的可复用性(统一存储),也能保证业务表清晰(只存业务相关信息和文件 URL)。
👉 后续可以扩展的方向:
文件分类(如判决书/庭审记录/和解协议)
文件权限(按用户/角色限制访问)
大文件分片上传