文件存储 MinIO、阿里云、腾讯云、七牛云
# 简介
JeeSite 的文件存储,默认是存到本地服务器的磁盘里,有些情况如集群多机部署,您也可以在 application.yml 里设置 file.baseDir 文件存储路径为网络磁盘映射目录,或者集成第三方文件存储服务,具体介绍如下。
# 如何将文件上传到云存储?
支持 MinIO、阿里云OSS、腾讯云COS、七牛云的上传文件存储,加入如下模块依赖代码
<dependency>
<groupId>com.jeesite</groupId>
<artifactId>jeesite-module-oss-client</artifactId>
<version>${project.parent.version}</version>
</dependency>
1
2
3
4
5
2
3
4
5
注意:v4.2.0+ 专业版提供,此模块依赖,请向售后人员索取。
配置参数如下:
# 文件存储客户端
oss:
client:
# 配置 MinIO 服务器连接信息
# 下载地址:https://min.io/download#/windows
minio:
enabled: false
url: http://127.0.0.7:9000
accessKey: minioadmin
secretKey: minioadmin
# 存储桶名称
bucketName: jeesite
# 桶下的根目录
baseDir: ~
# 公共读地址,设置后不进行生成私有地址(4.5.0+、5.1.0+)
publicUrl: ~
# 阿里云对象存储
aliyun:
enabled: false
endpoint: http://oss-cn-zhangjiakou.aliyuncs.com
accessKeyId: O23OUY32Bmd2kfjofu34r4UI
accessKeySecret: JHdH24KJ33FHd83jJHHjiOJj8
bucketName: jeesite2
baseDir: ~
publicUrl: ~
# 腾讯云对象存储
qcloud:
enabled: false
secretId: DH11KhU1R3es34w23SDf2HYM3MjbUYKBuv
secretKey: YRE2SDCv52hMLpoy47iV4BK755Vf7k
bucketName: jeesite-1833518515
region: ap-beijing
baseDir: ~
publicUrl: ~
# 七牛云对象存储
qiniu:
enabled: false
domain: http://dfv35sdg.hn-bkt.clouddn.com
accessKey: cdvji45kmibj3sDFkdf5kmtKL2JRLGKJeLOrg
secretKey: gFGo5g9jr56F78fg-KJIJkmc3kIOJg45JDjfg
bucketName: jeesite2
useHttps: false
region: ~
baseDir: ~
publicUrl: ~
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
45
46
47
48
49
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
45
46
47
48
49
v4.5.0+、v5.1.0+支持对象存储的文件预览,暂不支持 xlsx 中的图片转换,需要还需要设置如下参数:
application.yml
file:
# 默认的预览类型(true、oss)
preview: oss
1
2
3
2
3
分离端:.env 或 .env.* 如 .env.development、.env.production、.env.tomcat
# 文件预览类型(true、oss)
VITE_FILE_PREVIEW = oss
1
2
2
# 更多的存储方式
若上述存储不能满足您的需要,您可以任意扩展其它文件存储,如 FastDFS
继承 FileUploadServiceExtendSupport 类,并添加 @Service 注入到 SpringBean,举例如下:
/**
* 文件上传本地磁盘 v4.0.7+、5.0+
* @author ThinkGem
*/
@Service
public class FileUploadServiceExtendImpl extends FileUploadServiceExtendSupport{
/**
* 验证文件是否真实的存在
* @param fileEntity 文件实体信息
* @return 文件存在true,不存在false
*/
public boolean fileExists(FileEntity fileEntity){
String path = fileEntity.getFileRealPath();
File localFile = new File(path);
return localFile.exists();
}
/**
* 上传文件,首次上传文件都调用(保存到文件实体表之前调用) v4.1.6
*
* ※ 提示:需要分片上传时可重写本方法,若不需要分片可删除此方法。
*
* @param fileEntity 文件实体信息
* @param fileEntity fileRealPath 文件实际磁盘路径
* @param params file 要上传的文件,params.* 其它相关的参数
* @return 如果上传异常或有问题,则返回错误信息数据 {result:"false", message:"文件格式错误"}
*/
public Map<String, Object> uploadFile(FileEntity fileEntity, FileUploadParams params){
// 因为此方法比较复杂,建议使用 uploadFile(FileEntity fileEntity) 方法 处理第三方存储,这个比较方便
// 若不想让文件存储到本地,直接存储到文件服务器,可以实现此方法【否则,不要重写,请删除此函数】
Map<String, Object> dataMap = MapUtils.newHashMap();
try {
// 如果是分片上传
Long chunks = params.getChunks(); // 共多少片
Long chunk = params.getChunk(); // 当前分片
Long chunkSize = params.getChunkSize(); // 分片大小
Long size = params.getSize(); // 文件大小
MultipartFile file = params.getFile(); // 上传的文件
// System.out.println("文件信息:chunks="+chunks+", chunk="+chunk
// +", chunkSize="+chunkSize+", size="+size);
if (chunks != null && chunk != null && chunkSize != null && size != null) {
// 如果总共一片(文件较小,只有一片)
if (chunks.longValue() == 1 && chunk.longValue() == 0){
// System.out.println("总共一片");
InputStream inputStream = file.getInputStream(); // 当前分片数据(文件流方式)
byte[] bytes = file.getBytes(); // 当前分片数据(字节方式方式)
// Step1:上传文件到文件服务器
}
// 上传分片数据
else{
long offset = chunk * chunkSize; // 偏移位置(当前分片的字节起始位置)
InputStream inputStream = file.getInputStream(); // 当前分片数据(文件流方式)
byte[] bytes = file.getBytes(); // 当前分片数据(字节方式方式)
// Step2:根据当前分片上传数据(自己根据需求实现存储)
File currentFile = 当前已上传的文件对象;
// 如果全部上传完成,将临时文件转换为正式文件
if (currentFile.length() == size.longValue()){
// System.out.println("最后一片:tmpSize="+tmpFile.length()
// +", size="+size.longValue()+", "+tmpFile+" "+localFile);
// Step3:通知文件所有文件分片已经上传完成
}else{
// System.out.println("当前分片:"+String.valueOf(chunk + 1)+"/"+String.valueOf(chunks));
dataMap.put("message", Global.getText("sys.file.chunkUploading",
String.valueOf(chunk + 1), String.valueOf(chunks)));
dataMap.put("result", Global.TRUE);
return dataMap;
}
}
}else{
// System.out.println("不是分片上传");
// 定义上传本地路径,文件路径不存在则自动创建
File localFile = new File(fileEntity.getFileRealPath());
if (!localFile.getParentFile().exists()) {
localFile.getParentFile().mkdirs();
}
// 直接存文件
file.transferTo(localFile);
// 还可以获取文件流,自行存储
InputStream inputStream = file.getInputStream(); // 当前分片数据(文件流方式)
byte[] bytes = file.getBytes(); // 当前分片数据(字节方式方式)
// Step4:上传文件到文件服务器
}
} catch (IOException e) {
logger.error("文件保存失败:" + fileEntity.getFileUrl(), e);
}
// 这里可以写一些代码,处理文件信息。
// 比如:文件内容类型的验证;图像压缩;图像数据存储
// 存储文件附加信息:fileEntity.setFileMetaMap(map);
return null;
}
/**
* 上传文件,首次上传文件都调用( saveFileEntity 保存到文件实体表之前调用)
* @param fileEntity 文件实体信息
* @param fileEntity getFileRealPath() 文件实际磁盘路径
* @exception throw ServiceException("文件不符合要求") v4.1.5
*/
public void uploadFile(FileEntity fileEntity){
// 当前上传的文件磁盘路径
String fileName = fileEntity.getFileRealPath();
try {
// 这里写上传到文件服务器的代码
} catch (Exception e) {
throw ExceptionUtils.unchecked(e);
} finally {
// 文件上传后删除临时文件
FileUtils.deleteFile(fileName);
}
}
/**
* 保存上传文件信息,每次上传都调用(保存文件和用户关系数据之前调用)
* @param fileUpload 文件上传信息,包括文件实体
* @exception 支持抛出 throw ServiceException("文件不符合要求") v4.1.5
*/
public void saveUploadFile(FileUpload fileUpload){
// 如果想上传后,即保存业务关联的信息,可以打开如下注释
//FileEntity fileEntity = fileUpload.getFileEntity();
//FileUploadParams params = fileEntity.getFileUploadParams();
//fileUpload.setBizKey(params.getBizKey());
//fileUpload.setBizType(params.getBizType());
}
/**
* 获取访问文件的URL地址
* @param fileUpload 文件上传的信息,包括文件实体
* @return 无文件下载地址,则返回null,方便后续处理
*/
public String getFileUrl(FileUpload fileUpload){
return fileUpload.getFileEntity().getFileUrl();
}
/**
* 下载文件到浏览器
* @param fileUpload 文件上传的信息
* @param request 请求对象,可能断点续传用
* @param response 响应对象,输出文件流使用
* @return 如果不是文件流数据,也可返回文件的URL地址进行跳转,如果文件不存在返回404字符串
*/
public String downFile(FileUpload fileUpload, HttpServletRequest request, HttpServletResponse response){
FileEntity fileEntity = fileUpload.getFileEntity();
File file = new File(fileEntity.getFileRealPath());
if (file.exists()){
FileUtils.downFile(file, request, response, fileUpload.getFileName());
return null;
}
return "404";
}
}
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178