文件上传数据表
在这个指南中,我们将详细介绍如何设计和实现一个文件上传和管理系统的数据库
1. 文件表设计
首先,我们需要设计一个表来存储上传文件的相关信息。以下是一个示例的 SQL 表结构:
CREATE TABLE tio_boot_admin_system_upload_file (
id BIGINT NOT NULL, -- 文件ID
md5 VARCHAR(32) NOT NULL, -- 文件的MD5值,用于校验文件一致性
name VARCHAR(64) NOT NULL, -- 文件名
size BIGINT NOT NULL, -- 文件大小,单位为字节
user_id VARCHAR(32), -- 用户ID,标识上传文件的用户
platform VARCHAR(64) NOT NULL, -- 上传平台(如S3)
region_name VARCHAR(32), -- 区域名
bucket_name VARCHAR(64) NOT NULL, -- 存储桶名称
file_id VARCHAR(64) NOT NULL, -- 文件存储ID
target_name VARCHAR(64) NOT NULL, -- 文件存储路径
tags JSON, -- 文件标签,使用JSON格式
creator VARCHAR(64) DEFAULT '', -- 创建者
create_time TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
updater VARCHAR(64) DEFAULT '', -- 更新者
update_time TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 更新时间
deleted SMALLINT NOT NULL DEFAULT 0, -- 删除标志
tenant_id BIGINT NOT NULL DEFAULT 0, -- 租户ID
PRIMARY KEY (id) -- 主键
);
插入示例数据:
INSERT INTO tio_boot_admin_system_upload_file (
id, md5, name, file_size, user_id, platform, bucket_name, file_id, target_name, tags, creator, create_time, updater, update_time, deleted, tenant_id
) VALUES (
1, -- 文件ID
'd41d8cd98f00b204e9800998ecf8427e', -- MD5值
'example.txt', -- 文件名
1024, -- 文件大小
'user123', -- 用户ID
's3', -- 平台
'sd', -- 存储桶名称
'367962274737995776', -- 文件存储ID
'public/images/367962274737995776.png', -- 文件存储路径
'{"genre": "text", "language": "English"}', -- 标签,JSON格式
'admin', -- 创建者
CURRENT_TIMESTAMP, -- 创建时间
'admin', -- 更新者
CURRENT_TIMESTAMP, -- 更新时间
0, -- 删除标志
100 -- 租户ID
);
该表记录了文件的基本信息和元数据,如文件的 MD5 值、文件名、文件大小、存储路径和标签等。
2. 业务表设计
业务表用于存储与业务相关的信息,同时记录与文件关联的数据。以下是业务表的示例:
CREATE TABLE professors (
id BIGINT NOT NULL, -- 教授ID
name VARCHAR(256), -- 教授姓名
department VARCHAR(256), -- 所属部门
email VARCHAR(256), -- 邮箱
description TEXT, -- 描述
files JSON, -- 文件信息,JSON格式
remark VARCHAR(256), -- 备注
creator VARCHAR(64) DEFAULT '', -- 创建者
create_time TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
updater VARCHAR(64) DEFAULT '', -- 更新者
update_time TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 更新时间
deleted SMALLINT DEFAULT 0, -- 删除标志
tenant_id BIGINT NOT NULL DEFAULT 0, -- 租户ID
PRIMARY KEY (id) -- 主键
);
文件字段的示例数据如下:
[
{
"uid": "1719137636702",
"name": "image.png",
"status": "done",
"size": 424869,
"type": "image/png",
"id": "394523104107352064",
"url": "https://rumiapp.s3.us-west-1.amazonaws.com/sjsj/professors/394523099162267648.png"
},
{
"uid": "1719137646121",
"name": "image.png",
"status": "done",
"size": 424869,
"type": "image/png",
"id": "394523144213319680",
"url": "https://rumiapp.s3.us-west-1.amazonaws.com/sjsj/professors/394523138647478272.png"
}
]
3. 上传场景业务逻辑描述
1. 检查文件是否已存在
前端生成文件的 MD5 值,通过后端的 URL 接口判断对应的文件是否存在。如果文件存在,返回如下数据:
GET /api/system/file/s3/url?md5=c9fa90c0e145f2d62560f5431b271326
响应示例:
{
"code": 1,
"data": {
"id": 394519014493130752,
"url": "https://rumiapp.s3.us-west-1.amazonaws.com/public%2Fimages%2F394519008180703232.png"
},
"ok": true
}
2. 上传文件
如果文件不存在,前端调用上传接口上传文件,后端同时将文件信息存入文件表。上传完成后,返回包含文件信息的 id 和 url。
3. 提交业务数据
前端在完成业务数据录入后,将包含文件字段的数据提交到后端。请求示例如下:
POST /api/professor/create
{
"name": "Tong Li",
"其他业务字段": "其他值",
"files": [
{
"uid": "1719430104206",
"name": "image.png",
"status": "done",
"size": 424869,
"type": "image/png",
"id": 394519014493130750,
"url": "https://rumiapp.s3.us-west-1.amazonaws.com/public%2Fimages%2F394519008180703232.png"
}
]
}
通过上述步骤,您可以轻松实现一个文件上传和管理系统的数据库设计,并确保数据的完整性和一致性。
实体类
package com.litongjava.tio.boot.admin.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class UploadResultVo {
private Long id;
private String name;
private Long size;
private String url, md5;
}
数据操作层
package com.litongjava.tio.boot.admin.dao;
import com.litongjava.db.activerecord.Db;
import com.litongjava.db.activerecord.Record;
public class SystemUploadFileDao {
public static final String tableName = "tio_boot_admin_system_upload_file";
public static final String getFileBasicInfoByMd5Sql = String.format(
//
"select id,name,size,bucket_name,target_name from %s where md5=? and deleted=0", tableName);
public static final String getFileBasicInfoByIdSql = String.format(
//
"select md5,name,size,bucket_name,target_name from %s where id=? and deleted=0", tableName);
public Record getFileBasicInfoByMd5(String md5) {
return Db.findFirst(getFileBasicInfoByMd5Sql, md5);
}
public Record getFileBasicInfoById(long id) {
return Db.findFirst(getFileBasicInfoByIdSql, id);
}
public boolean save(long id, String md5, String originname, int fileSize, String platform, String bucketName,
//
String targetName) {
Record record = Record.by("id", id)
//
.set("md5", md5).set("name", originname).set("size", fileSize)
//
.set("platform", platform).set("bucket_name", bucketName)
//
.set("target_name", targetName);
return Db.save(tableName, record);
}
}
业务操作层
package com.litongjava.tio.boot.admin.services;
import com.jfinal.kit.Kv;
import com.litongjava.db.activerecord.Record;
import com.litongjava.jfinal.aop.Aop;
import com.litongjava.tio.boot.admin.dao.SystemUploadFileDao;
import com.litongjava.tio.boot.admin.utils.AwsS3Utils;
import com.litongjava.tio.boot.admin.vo.UploadResultVo;
public class SystemUploadFileService {
public UploadResultVo getUrlById(String id) {
return getUrlById(Long.parseLong(id));
}
public UploadResultVo getUrlById(long id) {
Record record = Aop.get(SystemUploadFileDao.class).getFileBasicInfoById(id);
if (record == null) {
return null;
}
String url = this.getUrl(record.getStr("bucket_name"), record.getStr("target_name"));
String originFilename = record.getStr("fielename");
String md5 = record.getStr("md5");
Long size = record.getLong("size");
return new UploadResultVo(id, originFilename, size, url, md5);
}
public UploadResultVo getUrlByMd5(String md5) {
Record record = Aop.get(SystemUploadFileDao.class).getFileBasicInfoByMd5(md5);
if (record == null) {
return null;
}
Long id = record.getLong("id");
String url = this.getUrl(record.getStr("bucket_name"), record.getStr("target_name"));
Kv kv = record.toKv();
kv.set("url", url);
kv.set("md5", md5);
String originFilename = record.getStr("filename");
Long size = record.getLong("size");
return new UploadResultVo(id, originFilename, size, url, md5);
}
public String getUrl(String bucketName, String targetName) {
return String.format(AwsS3Utils.urlFormat, AwsS3Utils.bucketName, targetName);
}
}
业务层接口
package com.litongjava.tio.boot.admin.services;
import com.litongjava.model.body.RespBodyVo;
import com.litongjava.tio.boot.admin.vo.UploadResultVo;
import com.litongjava.tio.http.common.UploadFile;
public interface StorageService {
public RespBodyVo upload(String category, UploadFile uploadFile);
public UploadResultVo uploadBytes(String category, String originname, int size, byte[] fileContent);
public UploadResultVo uploadBytes(long id, String originname, String targetName, byte[] fileContent,
//
int size, String suffix);
public String getUrl(String bucketName, String targetName);
public UploadResultVo getUrlById(String id);
public UploadResultVo getUrlById(long id);
public UploadResultVo getUrlByMd5(String md5);
}