minio客户端工具类实现上传、下载、删除、预览
一共有两个类,分别是MinioClientSingleton.class 和 MinioUtils.class
pom.xml
<dependencies> <!--minio文件服务--> <dependency> <groupId>io.minio</groupId> <artifactId>minio</artifactId> <version>7.1.0</version> </dependency> </dependencies> 复制代码
MinioClientSingleton.class
这是minio客户端单例类,主要是读取配置信息构建MinioClient; 此工具类提供给MinioUtils.class
使用
import io.minio.MinioClient; import lombok.Getter; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** * minio客户端单例类 * */ @Getter @Component public class MinioClientSingleton { private static String domainUrl; private static String accessKey; private static String secretKey; @Value("${min-io.endpoint}") public void setDomainUrl(String domainUrl) { MinioClientSingleton.domainUrl = domainUrl; } @Value("${min-io.accessKey}") public void setAccessKey(String accessKey) { MinioClientSingleton.accessKey = accessKey; } @Value("${min-io.secretKey}") public void setSecretKey(String secretKey) { MinioClientSingleton.secretKey = secretKey; } private volatile static MinioClient minioClient; public MinioClientSingleton() { } /** * 获取minio客户端实例 * * @return {@link MinioClient} */ public static MinioClient getMinioClient() { if (minioClient == null) { synchronized (MinioClientSingleton.class) { if (minioClient == null) { minioClient = MinioClient.builder() .endpoint(domainUrl) .credentials(accessKey, secretKey) .build(); } } } return minioClient; } } 复制代码
MinioUtils.class
主要工具类,包含上传、获取文件流(下载)、删除、获取预览路径(返回给我前端预览或下载)
import io.minio.*; import io.minio.errors.*; import io.minio.messages.Bucket; import io.minio.messages.DeleteObject; import io.minio.messages.Item; import lombok.extern.slf4j.Slf4j; import org.springframework.lang.NonNull; import org.springframework.util.StringUtils; import org.springframework.web.multipart.MultipartFile; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; /** * Minio客户端工具类 */ @SuppressWarnings("ALL") @Slf4j public class MinioUtils { /** * 创建文件桶(建议租户ID为桶的名称) */ public static boolean exitsBucket(String bucket) { boolean found = false; try { found = MinioClientSingleton.getMinioClient().bucketExists(BucketExistsArgs.builder().bucket(bucket).build()); } catch (Exception e) { log.error("create bucket is error", e); } return found; } /** * 自动创建桶并存储文件 * * @param inputStream * @param fileName * @param bucket * @param fileSize * @return */ public static String putObjectStream(InputStream inputStream, String fileName, String bucket, Long fileSize) { try { boolean bucketExsit = exitsBucket(bucket); if (bucketExsit) { makeBucketPolicy(bucket); } MinioClientSingleton.getMinioClient().putObject( PutObjectArgs.builder() .bucket(bucket).object(fileName).stream(inputStream, fileSize, -1).build()); inputStream.close(); return MinioClientSingleton.getMinioClient().getObjectUrl(bucket, fileName); } catch (Exception e) { e.printStackTrace(); } return null; } /** * @param bucket 桶名称 * @param path 文件夹路径 [doc/] * @param file 要上传的文件 * @param fileName 自定义文件名 * @return */ public static String putObject(@NonNull String bucket, @NonNull String path, @NonNull MultipartFile file, String fileName) throws Exception { if (!exitsBucket(bucket)) { makeBucketPolicy(bucket); } InputStream inputStream = null; try { MinioClientSingleton.getMinioClient().putObject( PutObjectArgs.builder().bucket(bucket).object(path).stream( new ByteArrayInputStream(new byte[]{}), 0, -1) .build()); inputStream = file.getInputStream(); if (StringUtils.isEmpty(fileName)) { fileName = file.getOriginalFilename(); } InputStream in = file.getInputStream(); PutObjectOptions options = new PutObjectOptions(in.available(), -1); options.setContentType(file.getContentType()); String objectName = path + System.currentTimeMillis() + "_" + fileName; // 生成时间戳防止重名 MinioClientSingleton.getMinioClient().putObject(bucket, objectName, in, options); file.getInputStream().close(); in.close(); return MinioClientSingleton.getMinioClient().presignedGetObject(bucket, objectName); } catch (Exception e) { e.printStackTrace(); } finally { if (inputStream != null) { inputStream.close(); } } return null; } private static void makeBucketPolicy(String bucket) throws ErrorResponseException, InsufficientDataException, InternalException, InvalidBucketNameException, InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, RegionConflictException, ServerException, XmlParserException { String policyJsonBuilder = "{\n" + " "Statement": [\n" + " {\n" + " "Action": [\n" + " "s3:GetBucketLocation",\n" + " "s3:ListBucket"\n" + " ],\n" + " "Effect": "Allow",\n" + " "Principal": "*",\n" + " "Resource": "arn:aws:s3:::" + bucket + ""\n" + " },\n" + " {\n" + " "Action": "s3:GetObject",\n" + " "Effect": "Allow",\n" + " "Principal": "*",\n" + " "Resource": "arn:aws:s3:::" + bucket + "/*"\n" + " }\n" + " ],\n" + " "Version": "2012-10-17"\n" + "}\n"; MinioClientSingleton.getMinioClient().makeBucket(MakeBucketArgs.builder() .bucket(bucket) .build()); //noinspection deprecation MinioClientSingleton.getMinioClient().setBucketPolicy(bucket, policyJsonBuilder); } /** * 自动创建桶并存储文件 * * @return */ public static String putObjectStream(MultipartFile file, String bucket) throws Exception { boolean exsit = exitsBucket(bucket); if (!exsit) { makeBucketPolicy(bucket); } String fileHeader = null; try { InputStream inputStream = file.getInputStream(); boolean bucketExsit = exitsBucket(bucket); if (bucketExsit) { MinioClientSingleton.getMinioClient().makeBucket(MakeBucketArgs.builder() .bucket(bucket) .build()); } MinioClientSingleton.getMinioClient().putObject( PutObjectArgs.builder() .bucket(bucket).object(file.getOriginalFilename()).stream(inputStream, inputStream.available(), -1).build()); inputStream.close(); return MinioClientSingleton.getMinioClient().getObjectUrl(bucket, file.getOriginalFilename()); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 查询所有桶文件 * * @return */ public static List<Bucket> getListBuckets() { try { return MinioClientSingleton.getMinioClient().listBuckets(); } catch (Exception e) { e.printStackTrace(); } return Collections.emptyList(); } /** * 删除文件 * * @param bucket 桶名称 * @param objectName 对象名称 * @return boolean */ public static boolean removeObject(String bucket, String objectName) { try { boolean exsit = exitsBucket(bucket); if (exsit) { // 从mybucket中删除myobject。removeobjectargs.builder().bucket(bucketname).object(objectname).build() MinioClientSingleton.getMinioClient().removeObject(RemoveObjectArgs.builder().bucket(bucket).object(objectName).build()); return true; } } catch (Exception e) { log.error("removeObject", e); } return false; } /** * 批量删除文件 * * @param bucket 桶名称 * @param objectNames 对象名称 * @return boolean */ public static boolean removeObjects(String bucket, List<String> objectNames) { boolean exsit = exitsBucket(bucket); if (exsit) { try { List<DeleteObject> objects = new LinkedList<>(); for (String str : objectNames) { objects.add(new DeleteObject(str)); } MinioClientSingleton.getMinioClient().removeObjects(RemoveObjectsArgs.builder().bucket(bucket).objects(objects).build()); return true; } catch (Exception e) { log.error("removeObject", e); } } return false; } /** * 获取单个桶中的所有文件对象名称 * * @param bucket 桶名称 * @return {@link List}<{@link String}> */ public static List<String> getBucketObjectName(String bucket) { boolean exsit = exitsBucket(bucket); if (exsit) { List<String> listObjetcName = new ArrayList<>(); try { Iterable<Result<Item>> myObjects = MinioClientSingleton.getMinioClient().listObjects(ListObjectsArgs.builder().bucket(bucket).build()); for (Result<Item> result : myObjects) { Item item = result.get(); listObjetcName.add(item.objectName()); } return listObjetcName; } catch (Exception e) { e.printStackTrace(); } } return null; } /** * 以流的形式获取一个文件对象 * * @param bucket 桶名称 * @param objectName 对象名称 * @return {@link InputStream} */ public static InputStream getObjectInputStream(String bucket, String objectName) { boolean exsit = exitsBucket(bucket); if (exsit) { try { ObjectStat objectStat = MinioClientSingleton.getMinioClient().statObject(StatObjectArgs.builder().bucket(bucket).object(objectName).build()); if (objectStat.length() > 0) { // 获取objectName的输入流。 return MinioClientSingleton.getMinioClient().getObject(GetObjectArgs.builder().bucket(bucket).object(objectName).build()); } } catch (Exception e) { e.printStackTrace(); } } return null; } /** * 删除一个桶 * * @param bucket 桶名称 */ public static boolean removeBucket(String bucket) throws Exception { // 删除之前先检查`my-bucket`是否存在。 boolean found = exitsBucket(bucket); if (found) { Iterable<Result<Item>> myObjects = MinioClientSingleton.getMinioClient().listObjects(ListObjectsArgs.builder().bucket(bucket).build()); for (Result<Item> result : myObjects) { Item item = result.get(); //有对象文件,则删除失败 if (item.size() > 0) { return false; } } // 删除`bucketName`存储桶,注意,只有存储桶为空时才能删除成功。 MinioClientSingleton.getMinioClient().removeBucket(RemoveBucketArgs.builder().bucket(bucket).build()); found = exitsBucket(bucket); return !found; } return false; } /** * 获取某个桶下某个对象的URL * * @param bucket 桶名称 * @param objectName 对象名 (文件夹名 + 文件名) * @return */ public static String getBucketObject(String bucket, String objectName) throws Exception { // 删除之前先检查`my-bucket`是否存在。 boolean found = exitsBucket(bucket); if (found) { return MinioClientSingleton.getMinioClient().getObjectUrl(bucket, objectName); } return ""; } /** * 根据文件路径得到预览文件绝对地址 * * @param bucket 桶名称 * @param objectName 对象名 (文件夹名+文件名) * @return */ public String getPreviewFileUrl(String bucket, String objectName) { try { return MinioClientSingleton.getMinioClient().presignedGetObject(bucket, objectName); } catch (Exception e) { e.printStackTrace(); return ""; } } } 复制代码
Controller.class
@RestController @RequestMapping("/api/notice") public class ProductNoticeController { @PostMapping("/file/upload") @ApiOperation(value = "上传文件", notes = "上传文件") public JsonResult upload(MultipartFile file) { try { String url = MinioUtils.putObject(bucket, "notice/", file, file.getOriginalFilename()); return JsonResult.ok().build(url); } catch (Exception e) { e.printStackTrace(); return JsonResult.error("upload.error", "上传失败").build(); } } } 复制代码
调用结果
浏览器预览
作者:阿豪_mike
链接:https://juejin.cn/post/7051397862596280328