admin管理员组文章数量:1632987
springboot2.x + minio7.0.2
本文记录 minio的调用关键步骤和关键文档. 主要记录大文件分片上传和文件合并记录
- minio官网地址 http://www.minio
- minio 安装参考官网说明
- mino 文件加密需要https证书. 可以使用签名证书
- minio 服务启动脚本 start.sh
#!/bin/bash
export MINIO_ACCESS_KEY=admin
export MINIO_SECRET_KEY=admin123
# minio 存放位置
dir=/data/menhu/minio
# https证书位置minio/certs
$dir/minio --certs-dir $dir/certs/ server $dir/data/minio &> $dir/logs/minio.log &
minio 客户端maven配置
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>7.0.2</version>
</dependency>
minio 配置类
/**
* minio 配置类
*
* @author dennis
* @date 2021/5/26
*/
@Component
public class MinioConfig {
@Value("${minio.host:https://play.min.io}")
private String host;
@Value("${minio.accessKey:Q3AM3UQ867SPQQA43P2F}")
private String accessKey;
@Value("${minio.secretKey:zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG}")
private String secretKey;
// 文件是否加密存储
@Value("${minio.encryption:false}")
private Boolean encryption;
@Bean
public MinioClient getMinioClient() {
try {
MinioClient minioClient = new MinioClient(host, accessKey, secretKey);
minioClient.ignoreCertCheck(); //忽略自签名证书有效性
return minioClient;
} catch (Exception e) {
e.printStackTrace();
throw new ValidatorException(e.fillInStackTrace().getMessage());
}
}
/**
* 如何是https环境可以启用 文件加密
* @return
*/
public SecretKey getSecretKey() {
if (encryption && StringUtils.startsWith(host, "https")) {
try {
KeyGenerator aes = KeyGenerator.getInstance("AES");
aes.init(256);
return aes.generateKey();
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
}
minio 工具类
/**
* minio 工具类
*
* @author dennis
* @date 2021/5/26
*/
@Component
public class MinioUtil {
@Autowired
private MinioClient minioClient;
private static final int DEFAULT_EXPIRY_TIME = 7 * 24 * 3600;
/**
* 检查存储桶是否存在
*
* @param bucketName 存储桶名称
* @return
* @throws Exception
*/
public boolean bucketExists(String bucketName) throws Exception {
return minioClient.bucketExists(bucketName);
}
/**
* 创建存储桶
*
* @param bucketName 存储桶名称
* @return
* @throws Exception
*/
public boolean makeBucket(String bucketName) throws Exception {
boolean flag = bucketExists(bucketName);
if (!flag) {
minioClient.makeBucket(bucketName);
return true;
}
return false;
}
/**
* 文件上传
*
* @param bucketName
* @param multipartFile
*/
public void putObject(String bucketName, MultipartFile multipartFile, String filename, SecretKey secretKey) throws Exception {
makeBucket(bucketName);
PutObjectOptions putObjectOptions = new PutObjectOptions(multipartFile.getSize(), PutObjectOptions.MIN_MULTIPART_SIZE);
putObjectOptions.setContentType(multipartFile.getContentType());
if (null != secretKey) {
putObjectOptions.setSse(ServerSideEncryption.withCustomerKey(secretKey));
}
minioClient.putObject(bucketName, filename, multipartFile.getInputStream(), putObjectOptions);
}
/**
* 以流的形式获取一个文件对象
*
* @param bucketName 存储桶名称
* @param objectName 存储桶里的对象名称
* @return
*/
public InputStream getObject(String bucketName, String objectName, SecretKey secretKey) throws Exception {
boolean flag = bucketExists(bucketName);
if (flag) {
ObjectStat statObject = statObject(bucketName, objectName, secretKey);
if (statObject != null && statObject.length() > 0) {
if (null != secretKey) {
return minioClient.getObject(bucketName, objectName, ServerSideEncryption.withCustomerKey(secretKey));
}
return minioClient.getObject(bucketName, objectName);
}
}
return null;
}
/**
* 以流的形式获取一个文件对象(断点下载)
*
* @param bucketName 存储桶名称
* @param objectName 存储桶里的对象名称
* @param offset 起始字节的位置
* @param length 要读取的长度 (可选,如果无值则代表读到文件结尾)
* @return
*/
public InputStream getObject(String bucketName, String objectName, long offset, Long length, SecretKey secretKey) throws Exception {
boolean flag = bucketExists(bucketName);
if (flag) {
ObjectStat statObject = statObject(bucketName, objectName, secretKey);
if (statObject != null && statObject.length() > 0) {
if (null != secretKey) {
return minioClient.getObject(bucketName, objectName, offset, length, ServerSideEncryption.withCustomerKey(secretKey));
}
return minioClient.getObject(bucketName, objectName, offset, length);
}
}
return null;
}
/**
* 获取对象的元数据
*
* @param bucketName 存储桶名称
* @param objectName 存储桶里的对象名称
* @return
*/
public ObjectStat statObject(String bucketName, String objectName, SecretKey secretKey) throws Exception {
boolean flag = bucketExists(bucketName);
if (flag) {
try {
if (null != secretKey) {
return minioClient.statObject(bucketName, objectName, ServerSideEncryption.withCustomerKey(secretKey));
}
return minioClient.statObject(bucketName, objectName);
} catch (Exception e) {
}
}
return null;
}
/**
* 删除一个对象
*
* @param bucketName 存储桶名称
* @param objectName 存储桶里的对象名称
*/
public boolean removeObject(String bucketName, String objectName) throws Exception {
boolean flag = bucketExists(bucketName);
if (flag) {
minioClient.removeObject(bucketName, objectName);
return true;
}
return false;
}
/**
* 分享。
*
* @param bucketName 存储桶名称
* @param objectName 存储桶里的对象名称
* @param expires 失效时间(以秒为单位),默认是7天,不得大于七天
* @return
*/
public String getPresignedObjectUrl(String bucketName, String objectName, Integer expires) throws Exception {
boolean flag = bucketExists(bucketName);
if (flag) {
if (null == expires) {
expires = DEFAULT_EXPIRY_TIME;
}
if (expires < 1 || expires > DEFAULT_EXPIRY_TIME) {
throw new RuntimeException("expires must be in range of 1 to " + DEFAULT_EXPIRY_TIME);
}
try {
return minioClient.getPresignedObjectUrl(Method.GET, bucketName, objectName, expires, null);
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
/**
* 获取一个临时可以上传的url
*
* @param bucketName
* @param objectName
* @return
* @throws Exception
*/
public String presignedPutObject(String bucketName, String objectName) throws Exception {
return minioClient.presignedPutObject(bucketName, objectName);
}
/**
* 列出某个存储桶中的所有对象
*
* @param bucketName
* @param objectNamePrefix 前缀
* @return
* @throws Exception
*/
public List<ComposeSource> listObjectsSource(String bucketName, String objectNamePrefix) throws Exception {
List<ComposeSource> sources = new ArrayList<>();
Iterable<Result<Item>> results = minioClient.listObjects(bucketName, objectNamePrefix);
for (Result<Item> result : results) {
Item item = result.get();
ComposeSource source = new ComposeSource(bucketName, item.objectName());
sources.add(source);
}
return sources;
}
/**
* 文件合并
*
* @param bucketName
* @param objectName
* @param sources
* @param secretKey
* @throws Exception
*/
public void composeObject(String bucketName, String objectName, List<ComposeSource> sources, SecretKey secretKey) throws Exception {
if (null != secretKey) {
minioClientposeObject(bucketName, objectName, sources, null, ServerSideEncryption.withCustomerKey(secretKey));
}
minioClientposeObject(bucketName, objectName, sources, null, null);
for (ComposeSource source : sources) {
minioClient.removeObject(source.bucketName(), source.objectName());
}
}
}
service 方法实现文件切割
实现思路
- 判断文件大小是否需要分片上传
- 生成每个分片上传的minio地址, 前端直接调用对应的地上上传分片
- 前端上传完所有分片之后, 调用文件合并接口完成大文件上传
/**
* 文件分割
*
* @param md5
* @param fileSize
* @return
* @throws Exception
*/
public JSONObject partInitUpload(String md5, double fileSize) throws Exception {
// 存储桶名称
String bucketName = Constants.FILE_CAT_BUCKET_NAME;
minioUtil.makeBucket(bucketName);
String username = ThreadLocalContextHolder.getCurrentUsername();
JSONObject jsonObject = new JSONObject(true);
// 判断文件大小, 是否需要切割
if (Constants.FILE_CAT_SIZE > fileSize) {
return null;
}
// 判断需要切割多少片
int partSize = (int) Math.ceil(fileSize / Constants.FILE_CAT_FILE_PART);
jsonObject.put("count", partSize);
JSONArray uploadInfos = new JSONArray();
for (long i = 0; i < partSize; i++) {
JSONObject uploadInfo = new JSONObject();
String objectName = username + "/" + md5 + "_" + i;
ObjectStat statObject = minioUtil.statObject(bucketName, objectName, null);
if (statObject != null && statObject.length() > 0) {
continue;
}
// 获取每一片文件的上传地址
String uploadUrl = minioUtil.presignedPutObject(bucketName, objectName);
uploadInfo.put("part", i);
uploadInfo.put("url", uploadUrl);
uploadInfos.add(uploadInfo);
}
jsonObject.put("uploadInfos", uploadInfos);
return jsonObject;
}
/**
* 文件合并
*
* @param md5
* @param fileSize
* @param fileName
* @param folderId
* @param diskType
* @return
* @throws Exception
*/
public FileStorage composeFilePart(String md5, double fileSize, String fileName, String folderId, DiskType diskType) throws Exception {
// 存储桶 名称
String bucketName = Constants.FILE_CAT_BUCKET_NAME;
String username = ThreadLocalContextHolder.getCurrentUsername();
String objectName = username + "/" + md5;
List<ComposeSource> composeSources = minioUtil.listObjectsSource(bucketName, objectName);
int partSize = (int) Math.ceil(fileSize / Constants.FILE_CAT_FILE_PART);
if (null != composeSources && partSize == composeSources.size()) {
String randomCode = getRandomCode();
String extension = FilenameUtils.getExtension(fileName);
objectName = diskType + "/" + username + "/" + Constants.DATA_YEAR_MONTH.format(new Date()) + "/" + randomCode + "." + extension;
bucketName = ThreadLocalContextHolder.getCurrentEcode();
// 判断文件是否需要加密存储
SecretKey secretKey = minioConfig.getSecretKey();
minioUtilposeObject(bucketName, objectName, composeSources, secretKey);
FileStorage fileStorage = new FileStorage();
// todo
// 存文件相关信息
return fileStorageRepository.save(fileStorage);
}
return null;
}
关注个人公众号
版权声明:本文标题:minio文件加密文件切割合并 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/dongtai/1729147393a1187834.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论