MinIO上传、下载、多文件压缩下载的基本使用

MinIO上传、下载、多文件压缩下载的基本使用

我们的文件是存储在自建的MinIO,一般存储员工周报、月报的文件和报告,也需要用到在线预览,为了节约成本,在线预览用的是kkfileview,它和一些商用的有些差距,不过,我们要求不要那么高嘛,又不是不能用。除了预览,我们还需要下载,单文件、多文件下载。基本使用我们就去网上抄些代码,根据自己的情况稍作修改一下,就可以用了。

先引入需要的包:

1
2
3
4
5
6
7
8
9
10
11
12
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.16</version>
</dependency>

<!-- MinIO -->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.2.2</version>
</dependency>

创建配置类:

MinioProperties

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
@Data
@ConfigurationProperties(prefix = MinioProperties.PREFIX)
public class MinioProperties {

/**
* 配置前缀
*/
public static final String PREFIX = "oss";

/**
* 对象存储名称
*/
private String name;

/**
* 对象存储服务的URL
*/
private String endpoint;

/**
* Access key 账户ID
*/
private String accessKey;

/**
* Secret key 密码
*/
private String secretKey;

/**
* 默认的存储桶名称
*/
private String bucketName = "nf-pms";

/**
* 可上传的文件后缀名
*/
private List<String> fileExt;



}

MinioConfiguration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Configuration
@EnableConfigurationProperties(MinioProperties.class)
@ConditionalOnProperty(value = "oss.name", havingValue = "minio")
public class MinioConfiguration {

@Resource
private MinioProperties ossProperties;

@Bean
@SneakyThrows
public MinioClient minioClient() {
return MinioClient.builder()
.endpoint(ossProperties.getEndpoint())
.credentials(ossProperties.getAccessKey(), ossProperties.getSecretKey())
.build();
}

}

配置配置文件:

1
2
3
4
5
6
7
8
#MINIO
oss:
name: minio
accessKey: 0QOnIhCNbhHCJOqsC5g1
secretKey: 1Kps3aH2M8Dxa5YAWqR78DzFi28i6WSHjGSg5fCp
bucketName: ppp-pms
endpoint: http://testminio.xxxxx.com:8080
fileExt: png,jpg,jpeg,pdf,docx,doc,xls,xlsx,ppt,pptx

实现调用MinIO相关接口
OssTemplate

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
public interface OssTemplate {

/**
* 存储桶是否存在
*
* @param bucketName 存储桶名称
* @return boolean
*/
boolean bucketExists(String bucketName);


/**
* 获取文件信息
*
* @param fileName 存储桶文件名称
* @return InputStream
*/
OssFile getOssInfo(String fileName);

/**
* 上传文件
*
* @param folderName 上传的文件夹名称
* @param fileName 上传文件名
* @param file 上传文件类
* @return BladeFile
*/
OssFile upLoadFile(String folderName, String fileName, MultipartFile file);

/**
* 上传文件
*
* @param folderName 上传的文件夹名称
* @param fileName 存储桶对象名称
* @param suffix 文件后缀名
* @param stream 文件流
* @return BladeFile
*/
OssFile upLoadFile(String folderName, String fileName, String suffix, InputStream stream);

/**
* 删除文件
*
* @param fileName 存储桶对象名称
*/
boolean removeFile(String fileName);

/**
* 批量删除文件
*
* @param fileNames 存储桶对象名称集合
*/
boolean removeFiles(List<String> fileNames);

/**
* @Description: 下载文件
* @Param response: 响应
* @Param fileName: 文件名
* @Param filePath: 文件路径
* @return: void
*/
void downloadFile(HttpServletResponse response, String fileName, String filePath);

void downloadZipFile(HttpServletResponse response, String outZipFileName,List<OssFile> files );

InputStream downloadFile( String filePath) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException;


}

MinioTemplate

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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
@Slf4j
@Service
public class MinioTemplate implements OssTemplate {

private Logger logger = LoggerFactory.getLogger(this.getClass());

/**
* MinIO客户端
*/
@Resource
private MinioClient client;

/**
* 配置类
*/
@Resource
private MinioProperties ossProperties;

/**
* 格式化时间
*/
private static final String DATE_FORMAT = "yyyyMMdd";

/**
* 字符集
*/
private static final String ENCODING = "UTF-8";

/**
* 存储桶是否存在
*
* @param bucketName 存储桶名称
* @return boolean
*/
@Override
public boolean bucketExists(String bucketName) {
try {
return client.bucketExists(BucketExistsArgs.builder().bucket(getBucketName(bucketName)).build());
} catch (Exception e) {
logger.error("minio bucketExists Exception:{}", e);
}
return false;
}

/**
* @Description: 创建 存储桶
* @Param bucketName: 存储桶名称
* @return: void
* @Date: 2023/8/2 11:28
*/
public void makeBucket(String bucketName) {
try {
if (!client.bucketExists(BucketExistsArgs.builder().bucket(getBucketName(bucketName)).build())) {
client.makeBucket(MakeBucketArgs.builder().bucket(getBucketName(bucketName)).build());
logger.info("minio makeBucket success bucketName:{}", bucketName);
}
} catch (Exception e) {
logger.error("minio makeBucket Exception:{}", e);
}
}

/**
* 获取文件信息
*
* @param fileName 存储桶文件名称
* @return InputStream
*/
@Override
public OssFile getOssInfo(String fileName) {
try {
StatObjectResponse stat = client.statObject(
StatObjectArgs.builder().bucket(getBucketName(ossProperties.getBucketName())).object(fileName)
.build());
OssFile ossFile = new OssFile();
ossFile.setName(ObjectUtil.isEmpty(stat.object()) ? fileName : stat.object());
ossFile.setFilePath(ossFile.getName());
ossFile.setDomain(getOssHost(ossProperties.getBucketName()));
ossFile.setHash(String.valueOf(stat.hashCode()));
ossFile.setSize(stat.size());
ossFile.setPutTime(DateUtil.date(stat.lastModified().toLocalDateTime()));
ossFile.setContentType(stat.contentType());
return ossFile;
} catch (Exception e) {
logger.error("minio getOssInfo Exception:{}", e);
}
return null;
}

/**
* 上传文件
*
* @param folderName 上传的文件夹名称
* @param fileName 上传文件名
* @param file 上传文件类
* @return BladeFile
*/
@Override
@SneakyThrows
public OssFile upLoadFile(String folderName, String fileName, MultipartFile file) {
if (file == null || file.isEmpty()) {
throw new BusinessException( "文件不能为空");
}
// 文件大小
if (file.getSize() > 100 * 1024 * 1024) {
throw new BusinessException( "文件大小不能超过5M");
}
String suffix = getFileExtension(file.getOriginalFilename());
// 文件后缀判断
if (!CollUtil.contains(ossProperties.getFileExt(), suffix)) {
String error = String.format("文件类型错误,目前支持[%s]等文件类型",
String.join(",", ossProperties.getFileExt()));
throw new BusinessException(error);
}
try {
return upLoadFile(folderName, fileName, suffix, file.getInputStream());
} catch (Exception e) {
logger.error("minio upLoadFile Exception:{}", e);
throw new BusinessException("文件上传失败,请重新上传或联系管理员");
}
}

/**
* 获取文件后缀名
*
* @param fullName 文件全名
* @return {String}
*/
public static String getFileExtension(String fullName) {
Assert.notNull(fullName, "minio file fullName is null.");
String fileName = new File(fullName).getName();
int dotIndex = fileName.lastIndexOf('.');
return (dotIndex == -1) ? "" : fileName.substring(dotIndex + 1);
}

/**
* 上传文件
*
* @param folderName 上传的文件夹名称
* @param fileName 存储桶对象名称
* @param suffix 文件后缀名
* @param stream 文件流
* @return BladeFile
*/
@Override
public OssFile upLoadFile(String folderName, String fileName, String suffix, InputStream stream) {
try {
return upLoadFile(ossProperties.getBucketName(), folderName, fileName, suffix, stream,
"application/octet" + "-stream");
} catch (Exception e) {
logger.error("minio upLoadFile Exception:{}", e);
}
return null;
}

/**
* @Description: 上传文件
* @Param bucketName: 存储桶名称
* @Param folderName: 上传的文件夹名称
* @Param fileName: 上传文件名
* @Param suffix: 文件后缀名
* @Param stream: 文件流
* @Param contentType: 文件类型
* @Author: wmh
* @Date: 2023/8/1 19:59
*/
@SneakyThrows
public OssFile upLoadFile(String bucketName, String folderName, String fileName, String suffix, InputStream stream,
String contentType) {
if (!bucketExists(bucketName)) {
logger.info("minio bucketName is not creat");
makeBucket(bucketName);
}
OssFile file = new OssFile();
String originalName = fileName;
String newName= IdUtil.getSnowflakeNextIdStr();
String filePath = getFilePath(folderName, newName, suffix);
client.putObject(PutObjectArgs.builder().bucket(getBucketName(bucketName)).object(filePath)
.stream(stream, stream.available(), -1).contentType(contentType).build());
file.setOriginalName(originalName);
file.setName(filePath);
file.setDomain(getOssHost(bucketName));
file.setFilePath(filePath);
file.setSuffix(suffix);

stream.close();
logger.info("minio upLoadFile success, filePath:{}", filePath);
return file;
}

/**
* 删除文件
*
* @param fileName 存储桶对象名称
*/
@Override
public boolean removeFile(String fileName) {
try {
client.removeObject(
RemoveObjectArgs.builder().bucket(getBucketName(ossProperties.getBucketName())).object(fileName)
.build());
logger.info("minio removeFile success, fileName:{}", fileName);
return true;
} catch (Exception e) {
logger.error("minio removeFile fail, fileName:{}, Exception:{}", fileName, e);
}
return false;
}

/**
* 批量删除文件
*
* @param fileNames 存储桶对象名称集合
*/
@Override
public boolean removeFiles(List<String> fileNames) {
try {
Stream<DeleteObject> stream = fileNames.stream().map(DeleteObject::new);
client.removeObjects(RemoveObjectsArgs.builder().bucket(getBucketName(ossProperties.getBucketName()))
.objects(stream::iterator).build());
logger.info("minio removeFiles success, fileNames:{}", fileNames);
return true;
} catch (Exception e) {
logger.error("minio removeFiles fail, fileNames:{}, Exception:{}", fileNames, e);
}
return false;
}

/**
* 下载文件
* @param response
* @param fileName
* @param filePath
*/
@Override
public void downloadFile(HttpServletResponse response, String fileName, String filePath) {
GetObjectResponse is = null;
try {
GetObjectArgs getObjectArgs =
GetObjectArgs.builder().bucket(ossProperties.getBucketName()).object(filePath)
.build();
is = client.getObject(getObjectArgs);
// 设置文件ContentType类型,这样设置,会自动判断下载文件类型
response.setContentType("application/x-msdownload");
response.setCharacterEncoding(ENCODING);
// 设置文件头:最后一个参数是设置下载的文件名并编码为UTF-8
response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(fileName, ENCODING));
IoUtil.copy(is, response.getOutputStream());
logger.info("minio downloadFile success, filePath:{}", filePath);
} catch (Exception e) {
logger.error("minio downloadFile Exception:{}", e);
} finally {
IoUtil.close(is);
}
}

/**
* 多文件下载压缩包
* @param response
* @param outZipFileName
* @param files
*/
@Override
public void downloadZipFile(HttpServletResponse response, String outZipFileName, List<OssFile> files) {

try {
outZipFileName=outZipFileName+".zip";
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment; filename="+URLEncoder.encode(outZipFileName, ENCODING));
ZipOutputStream zos = new ZipOutputStream(response.getOutputStream(), CharsetUtil.defaultCharset());
for(OssFile file:files) {
GetObjectArgs getObjectArgs =
GetObjectArgs.builder().bucket(ossProperties.getBucketName()).object(file.getFilePath())
.build();
GetObjectResponse is = client.getObject(getObjectArgs);
// 设置文件ContentType类型,这样设置,会自动判断下载文件类型
ZipEntry zipEntry = new ZipEntry(file.getOriginalName()); // 或者使用其他名称
zos.putNextEntry(zipEntry);
zos.write(IoUtil.readBytes(is));
zos.closeEntry();
IoUtil.close(is);
}
logger.info("minio downloadFile success, filePath:{}", outZipFileName);
} catch (Exception e) {
logger.error("minio downloadFile Exception:{}", e);
}
}

@Override
public InputStream downloadFile( String filePath) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
GetObjectArgs getObjectArgs =
GetObjectArgs.builder().bucket(ossProperties.getBucketName()).object(filePath)
.build();
return client.getObject(getObjectArgs);
}

/**
* 获取文件外链
*
* @param bucketName bucket名称
* @param fileName 文件名称
* @param expires 过期时间
* @return url
*/
public String getPresignedObjectUrl(String bucketName, String fileName, Integer expires) {
String link = "";
try {
link = client.getPresignedObjectUrl(
GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(getBucketName(bucketName))
.object(fileName).expiry(expires).build());
} catch (Exception e) {
logger.error("minio getPresignedObjectUrl is fail, fileName:{}", fileName);
}
return link;
}

/**
* 根据规则生成存储桶名称规则
*
* @param bucketName 存储桶名称
* @return String
*/
private String getBucketName(String bucketName) {
return bucketName;
}

/**
* 根据规则生成文件路径
*
* @param folderName 上传的文件夹名称
* @param originalFilename 原始文件名
* @param suffix 文件后缀名
* @return string 上传的文件夹名称/yyyyMMdd/原始文件名_时间戳.文件后缀名
*/
private String getFilePath(String folderName, String originalFilename, String suffix) {
return StrPool.SLASH + String.join(StrPool.SLASH, folderName, DateUtil.date().toString(DATE_FORMAT),
originalFilename) + StrPool.C_UNDERLINE + DateUtil.current() + StrPool.DOT + suffix;
}

/**
* 获取域名
*
* @param bucketName 存储桶名称
* @return String
*/
public String getOssHost(String bucketName) {
return ossProperties.getEndpoint() + StrPool.SLASH + getBucketName(bucketName);
}

}

MinIO上传、下载、多文件压缩下载的基本使用

https://blogs.52fx.biz/posts/1064745133.html

作者

eyiadmin

发布于

2024-10-25

更新于

2024-10-25

许可协议

评论