依赖
<dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.5.3</version></dependency>
配置项
minio:url: http://localhost:9000accessKey: exampleAccessKeysecretKey: exampleSecretKeybucket: exampleBucketaccessUrl: http://localhost:9000/exampleBucket
配置属性绑定
@Data
@ConfigurationProperties(prefix = "minio")
public class MinioProperties {private String url;private String accessKey;private String secretKey;private String bucket;private String accessUrl;
}
工具类:
import io.minio.*;
import io.minio.errors.MinioException;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.DeleteObject;
import io.minio.messages.Item;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@Slf4j
public class MinioUtils {private static MinioClient minioClient;private static String endpoint;private static String accessKey;private static String secretKey;private static final String SEPARATOR = "/";private MinioUtils() {}public MinioUtils(String endpoint, String accessKey, String secretKey) {MinioUtils.endpoint = endpoint;MinioUtils.accessKey = accessKey;MinioUtils.secretKey = secretKey;createMinioClient();}public void createMinioClient() {try {if (null == minioClient) {minioClient = MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build();System.err.println("创建Minio通道成功!");}} catch (Exception e) {System.err.println("创建Minio通道失败!");}}public static String getBasisUrl(String bucketName) {return endpoint + SEPARATOR + bucketName + SEPARATOR;}public static boolean bucketExists(String bucketName)throws Exception {return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());}public static void createBucket(String bucketName)throws Exception {if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());}}public static List<Bucket> getAllBuckets() throws Exception {return minioClient.listBuckets();}public static Optional<Bucket> getBucket(String bucketName) throws Exception {return minioClient.listBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();}public static void removeBucket(String bucketName) throws Exception {minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());}public static boolean doesObjectExist(String bucketName, String objectName) {boolean exist = true;try {minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());} catch (Exception e) {exist = false;}return exist;}public static boolean doesFolderExist(String bucketName, String objectName) {boolean exist = false;try {Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(objectName).recursive(false).build());for (Result<Item> result : results) {Item item = result.get();if (item.isDir() && objectName.equals(item.objectName())) {exist = true;}}} catch (Exception e) {exist = false;}return exist;}public static List<Item> getAllObjectsByPrefix(String bucketName, String prefix, boolean recursive) throws Exception {List<Item> list = new ArrayList<>();Iterable<Result<Item>> objectsIterator = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(prefix).recursive(recursive).build());if (objectsIterator != null) {for (Result<Item> o : objectsIterator) {Item item = o.get();list.add(item);}}return list;}public static ObjectWriteResponse putObject(String bucketName, MultipartFile file, String objectName, String contentType) throws Exception {InputStream inputStream = file.getInputStream();return minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).contentType(contentType).stream(inputStream, inputStream.available(), -1).build());}public static ObjectWriteResponse putObject(String bucketName, MultipartFile file, String objectName) throws Exception {InputStream inputStream = file.getInputStream();return minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(inputStream, inputStream.available(), -1).build());}public static ObjectWriteResponse putObject(String bucketName, String objectName, String filePath)throws Exception {URLConnection urlConnection = new URL(filePath).openConnection();return minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).contentType(urlConnection.getContentType()).stream(urlConnection.getInputStream(), urlConnection.getContentLength(), -1).build());}public static ObjectWriteResponse putObject(String bucketName, String fileAbsName, URLConnection connection) throws Exception {InputStream inputStream = connection.getInputStream();return minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(fileAbsName).contentType(connection.getContentType()).stream(inputStream, inputStream.available(), -1).build());}public static ObjectWriteResponse putObject(String bucketName, String objectName,InputStream inputStream)throws Exception {return minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(inputStream, inputStream.available(), -1).build());}public static ObjectWriteResponse putDirObject(String bucketName, String objectName)throws Exception {return minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(new ByteArrayInputStream(new byte[]{}), 0, -1).build());}public static ObjectWriteResponse copyObject(String bucketName, String objectName,String srcBucketName, String srcObjectName)throws Exception {return minioClient.copyObject(CopyObjectArgs.builder().source(CopySource.builder().bucket(bucketName).object(objectName).build()).bucket(srcBucketName).object(srcObjectName).build());}public static void downloadFile(String bucketName, String originalName,HttpServletRequest request,HttpServletResponse response) {try {InputStream file = getObject(bucketName, originalName);String useragent = request.getHeader("USER-AGENT").toLowerCase();if (useragent.contains("msie") || useragent.contains("like gecko") || useragent.contains("trident")) {originalName = URLEncoder.encode(originalName, StandardCharsets.UTF_8.displayName());} else {originalName = new String(originalName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);}response.setCharacterEncoding("UTF-8");response.setHeader("Content-Disposition", "attachment;filename=" + originalName);ServletOutputStream servletOutputStream = response.getOutputStream();int len;byte[] buffer = new byte[1024];while ((len = file.read(buffer)) > 0) {servletOutputStream.write(buffer, 0, len);}servletOutputStream.flush();file.close();servletOutputStream.close();} catch (Exception e) {System.err.println(String.format("下载文件:%s异常", originalName));}}public static InputStream getObject(String bucketName, String objectName) throws Exception {return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());}public InputStream getObject(String bucketName, String objectName, long offset, long length)throws Exception {return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).offset(offset).length(length).build());}public static Iterable<Result<Item>> listObjects(String bucketName, String prefix, boolean recursive) {return minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(prefix).recursive(recursive).build());}public static Iterable<Result<Item>> listObjects(String bucketName, boolean recursive) {return minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).recursive(recursive).build());}public static void removeObject(String bucketName, String objectName)throws Exception {minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());}public static void removeObjects(String bucketName, List<String> keys) {List<DeleteObject> objects = new LinkedList<>();keys.forEach(s -> {objects.add(new DeleteObject(s));try {removeObject(bucketName, s);} catch (Exception e) {System.err.println("批量删除失败!");}});}public static String getPreviewUrl(String bucketName, String object, String contentType, Integer validTime, TimeUnit timeUnit) {Map<String, String> reqParams = null;if (contentType != null) {reqParams = new HashMap<>();reqParams.put("response-content-type", contentType != null ? contentType : "application/pdf");}String url = null;try {url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(bucketName).object(object).expiry(validTime, timeUnit).extraQueryParams(reqParams).build());} catch (Exception e) {e.printStackTrace();}return url;}public List<Item> listObjects(int limit, String bucketName) {List<Item> objects = new ArrayList<>();Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).maxKeys(limit).includeVersions(true).build());try {for (Result<Item> result : results) {objects.add(result.get());}} catch (Exception e) {e.printStackTrace();}return objects;}public static void netToMinio(String httpUrl, String bucketName) {int i = httpUrl.lastIndexOf(".");String substring = httpUrl.substring(i);URL url;try {url = new URL(httpUrl);URLConnection urlConnection = url.openConnection();urlConnection.setRequestProperty("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36");DataInputStream dataInputStream = new DataInputStream(url.openStream());File tempFile = File.createTempFile(UUID.randomUUID().toString().replace("-", ""), substring);FileOutputStream fileOutputStream = new FileOutputStream(tempFile);ByteArrayOutputStream output = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int length;while ((length = dataInputStream.read(buffer)) > 0) {output.write(buffer, 0, length);}fileOutputStream.write(output.toByteArray());putObject(bucketName, tempFile.getAbsolutePath(), tempFile.getName());dataInputStream.close();fileOutputStream.close();} catch (Exception e) {e.printStackTrace();}}public byte[] fileToBytes(String path) {FileInputStream fis = null;ByteArrayOutputStream bos = null;try {bos = new ByteArrayOutputStream();fis = new FileInputStream(path);int temp;byte[] bt = new byte[1024 * 10];while ((temp = fis.read(bt)) != -1) {bos.write(bt, 0, temp);}bos.flush();} catch (IOException e) {e.printStackTrace();} finally {try {if (Objects.nonNull(fis)) {fis.close();}} catch (IOException e) {e.printStackTrace();}}return bos.toByteArray();}public static String getUtf8ByURLDecoder(String str) throws UnsupportedEncodingException {String url = str.replaceAll("%(?![0-9a-fA-F]{2})", "%25");return URLDecoder.decode(url, "UTF-8");}public static void downloadMinioFileToZip(String bucketName, HttpServletResponse response) {downloadMinioFileToZip(bucketName, "", response);}public static void downloadMinioFileToZip(String bucketName, String folderPath, HttpServletResponse response) {try {if (folderPath == null || folderPath.isEmpty()) {folderPath = "";}response.setContentType("application/zip");response.setHeader("Content-Disposition", "attachment;filename=" + bucketName + ".zip");try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(folderPath).recursive(true).build());for (Result<Item> result : results) {Item item = result.get();String objectName = item.objectName();log.info("找到对象: {}", objectName);if (objectName.endsWith("/")) {continue;}ZipEntry zipEntry = new ZipEntry(objectName);zipOut.putNextEntry(zipEntry);try (InputStream stream = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build())) {byte[] buf = new byte[8192];int bytesRead;while ((bytesRead = stream.read(buf)) != -1) {zipOut.write(buf, 0, bytesRead);}zipOut.closeEntry();log.info("文件压缩成功: {}", objectName);} catch (Exception e) {log.error("下载并压缩文件时发生错误: {}", e.getMessage(), e);}}log.info("所有文件已成功压缩并通过响应输出。");} catch (IOException e) {log.error("创建压缩包时发生错误: {}", e.getMessage(), e);}} catch (MinioException | InvalidKeyException | NoSuchAlgorithmException e) {log.error("发生错误: {}", e.getMessage(), e);}}}
配置类:
import com.saas.iot.utils.MinioUtils;
import io.minio.MinioClient;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import javax.annotation.Resource;@Configuration
@EnableConfigurationProperties(MinioProperties.class)
public class MinioConfig {@Resourceprivate MinioProperties minioProperties;@Beanpublic MinioClient minioClient() {return MinioClient.builder().endpoint(minioProperties.getUrl()).credentials(minioProperties.getAccessKey(), minioProperties.getSecretKey()).build();}@Beanpublic MinioUtils creatMinioClient() {return new MinioUtils(minioProperties.getUrl(), minioProperties.getAccessKey(), minioProperties.getSecretKey());}}
测试接口实现类:
请求接口:
@PostMapping("upload")@ApiOperation("文件上传")public R upload(MultipartFile file) {return R.ok(sysFileService.uploadFile(file));}
服务层接口方法:
String uploadFile(MultipartFile file) throws Exception;
实现方法:
@Overridepublic String uploadFile(MultipartFile file) throws Exception {if (file.isEmpty() || file.getSize() <= 0 || StrUtil.isBlank(file.getOriginalFilename())) {throw new RuntimeException("上传文件不能为空");}String originalFilename = file.getOriginalFilename();String[] defaultAllowedExtension = MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION;Set<String> typeSet = new HashSet<>(Arrays.asList(defaultAllowedExtension));originalFilename = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);if (!typeSet.contains(originalFilename)){throw new RuntimeException("文件格式不支持"); }ObjectWriteResponse response = MinioUtils.putObject(minioConfig.getBucket(), file, getFileName(originalFilename), file.getContentType());return minioConfig.getAccessUrl() + minioConfig.getBucket() + "/" + response.object();}private String getFileName(String suffix) {return "data/local/" + suffix + "/" + IdUtil.getSnowflake() + "." + suffix;}
定义系统允许文件类型:
public static final String[] DEFAULT_ALLOWED_EXTENSION = {"bmp", "gif", "jpg", "jpeg", "png","doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt","rar", "zip", "gz", "bz2","bin", "apk", "ipa","mp4", "avi", "rmvb","tif","pdf" };