# 一、文件存储方式
- 本地目录存储
- 数据库存储
- 自建文件服务器存储
- 云存储服务器
# 二、数据库存储
# 限制性
- 文件资源小,资源过多该方式则不适用
- 上传频率低,基本等同于获取静态资源
# 概念
# BLOB
1.BLOB
BLOB全称为二进制大型对象(Binary Large Object)。它用于存储数据库中的大型二进制对象。可存储的最大大小为4G字节。
通常像图片、文件、音乐等信息就用BLOB字段来存储,先将文件转为二进制再存储进去。
MySQL有四种BLOB类型:
tinyblob:仅255个字符
blob:最大限制到65K字节
mediumblob:限制到16M字节
longblob:可达4GB
2.CLOB
CLOB全称为字符大型对象(Character Large Object)。它与LONG数据类型类似,只不过CLOB用于存储数据库中的大型单字节字符数据块,不支持宽度不等的字符集。可存储的最大大小为4G字节。
# BASE64
图片的 base64 编码就是可以将一副图片数据编码成一串字符串,使用该字符串代替图像地址。
图片的 base64字符串如下:
data:image/jpeg;base64,BASE64编码
1
为什么使用图片的 base64 编码
- 无额外请求
- 对于极小或者极简单图片
- 可像单独图片一样使用,比如背景图片重复使用等
- 没有跨域问题,无需考虑缓存、文件头或者cookies问题
我们所看到的网页上的每一个图片,都是需要消耗一个 http 请求下载而来的。
而使用图片的 base64 编码,则可以通过在获取其他数据的同时,把图片数据作为一个字符串进行同步返回。
那么前端页面显示如下:
css中的写法:
#mycss {
background: url(BASE64字符串) no-repeat center;
}
1
2
3
2
3
html标签中的写法:
<img src="BASE64字符串">
1
# 存储流程
# 后端转换
- 上传文件流到后端服务
- 将文件流转为byte[]存入数据库
后端接口接收:
@PostMapping(value = "/uploadImage", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseResult uploadImage(@RequestParam MultipartFile file) {
try {
Long fileId = fileService.upload2DB(file);
return ResponseResult.success("上传文件成功", fileId);
} catch (Exception e) {
logger.error("【捕获异常-上传文件操作】\r\n异常记录:", e);
throw new BusinessException(e.getMessage());
}
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
入库处理:
@Autowired
private SysFileMapper sysFileMapper;
public Long upload2DB(MultipartFile file) throws IOException {
if (file.isEmpty()) {
throw new BusinessException(ResponseCode.UPLOAD_FILE_NULL);
}
InputStream inputStream = file.getInputStream();
byte[] imageByte = new byte[(int) file.getSize()];
inputStream.read(imageByte);
// 文件名
String fileName = file.getOriginalFilename();
// 后缀名
String suffixName = fileName.substring(fileName.lastIndexOf("."));
SysFile sysFile = new SysFile();
sysFile.setFileName(fileName);
sysFile.setFileContent(imageByte);
sysFile.setFileSize(file.getSize());
sysFile.setFileExt(suffixName);
sysFile.setFileType(2);
sysFileMapper.insert(sysFile);
return sysFile.getId();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
实体类:
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("sys_file")
public class SysFile extends BaseDO {
private static final long serialVersionUID = 3094398542939760859L;
/**
* 文件名
*/
private String fileName;
/**
* 文件内容
*/
private String filePath;
/**
* 文件内容
*/
private byte[] fileContent;
/**
* 文件大小:单位(kb)
*/
private Long fileSize;
/**
* 文件扩展名
*/
private String fileExt;
/**
* 文件类型:1、Doc;2、Img;3、Video;9、Other
*/
private Integer fileType;
/**
* 备注说明
*/
private String memo;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
数据库表结构:
DROP TABLE IF EXISTS `sys_file`;
CREATE TABLE `sys_file` (
`id` bigint(0) NOT NULL COMMENT '文件主键ID',
`file_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '文件名',
`file_path` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '文件路径',
`file_content` mediumblob COMMENT '文件内容',
`file_size` int(0) NOT NULL COMMENT '文件大小:单位(字节)',
`file_ext` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '文件扩展名',
`file_type` tinyint(0) DEFAULT NULL COMMENT '文件类型:1、Doc;2、Img;3、Video;9、Other',
`memo` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '备注说明',
`create_time` datetime(0) NOT NULL COMMENT '创建时间',
`update_time` datetime(0) DEFAULT NULL COMMENT '修改时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '文件信息表' ROW_FORMAT = Dynamic;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 前端转换
- 在前端将文件转换为base64编码字符串
- 后端服务直接入库存储base64编码字符串
略
# 展示流程
- 上读取数据库blob数据
- 将byte[]文件流转换为base64
读取数据库blob数据
@Override
public String getImage(Long fileId) {
return FileUtils.getImageBase64(getBytes(fileId));
}
private byte[] getBytes(Long fileId) {
if (fileId == null) {
throw new BusinessException(ResponseCode.PARAM_IS_BLANK);
}
SysFile sysFile = sysFileMapper.selectById(fileId);
if (sysFile.getFileContent() == null) {
logger.error("文件主键ID为{}", fileId);
throw new BusinessException(ResponseCode.FILE_IS_NOT_EXIST);
}
return sysFile.getFileContent();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
获取base64编码工具类
public static final String IMAGE_BASE_PREFIX = "data:image/png;base64,";
public static String getImageBase64(byte[] fileBytes) {
return IMAGE_BASE_PREFIX + bytesToBase64(fileBytes);
}
public static String bytesToBase64(byte[] fileBytes) {
return Base64.encodeBase64String(fileBytes);
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
前端标签展示
html标签中的写法:
<img src="BASE64字符串">
1
# 三、本地目录存储
# 本地存储缺点
- 项目打包困难,当上传的文件越来越多,项目的打包jar越来越大。
- 代码与文件数据不能分开存储,就意味着文件数据的备份将变得复杂.
# 四、远程文件服务器存储
- 自建分布式文件服务器
fastDFS
; - 自己分布式文件服务器
MinIO
; - 购买阿里云
OSS
云存储服务器;