一、 MinIO
MinIO 是一个基于Apache License v2.0开源协议的对象存储服务。它兼容亚马逊S3云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从几kb到最大5T不等。
MinIO是一个非常轻量的服务,可以很简单的和其他应用的结合,类似 NodeJS, Redis 或者 MySQL。
二、 MinIO安装和启动
由于MinIO是一个单独的服务器,需要单独部署,有关MinIO在Windows系统上的使用请查看以下博客。
Windows MinIO使用教程(启动,登录,修改密码)
三、 pom.xml(maven依赖文件)
org.projectlomboklombok1.18.16org.springframework.bootspring-boot-starter-webio.miniominio8.3.4
四、applicatin.properties(配置文件)
# 设置单个文件大小spring.servlet.multipart.max-file-size= 50MB#minio文件服务器配置s3.url=http://localhost:9000s3.accessKey=admins3.secretKey=admin123s3.bucketName=test
五、 编写Java业务类
minio涉及到的方法有:判断存储桶是否存在,创建存储桶,上传文件,读取文件、下载文件,删除文件等操作
1、StorageProperty 存储属性类:
import lombok.Data;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.stereotype.Component;/** * @Author yang * @Date 2023/1/3 14:00 * @Version 1.0 */@Data@Component@ConfigurationProperties(prefix = "s3")public class StorageProperty {private String url;private String accessKey;private String secretKey;//private long callTimeOut = 60000;//private long readTimeOut = 300000;}
2、minio 配置类:
import io.minio.BucketExistsArgs;import io.minio.MinioClient;import io.minio.messages.Bucket;import lombok.SneakyThrows;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Configuration;import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;import java.util.List;/** * @Author yang * @Date 2023/1/3 14:03 * @Version 1.0 */@Slf4j@Component@Configurationpublic class MinioClientConfig {@Autowiredprivate StorageProperty storageProperty;private static MinioClient minioClient;/** * @description: 获取minioClient * @date 2021/6/22 16:55 * @return io.minio.MinioClient */public static MinioClient getMinioClient(){return minioClient;}/** * 判断 bucket是否存在 * * @param bucketName: *桶名 * @return: boolean * @date : 2020/8/16 20:53 */@SneakyThrows(Exception.class)public static boolean bucketExists(String bucketName) {return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());}/** * 获取全部bucket * * @param : * @return: java.util.List * @date : 2020/8/16 23:28 */@SneakyThrows(Exception.class)public static List getAllBuckets() {return minioClient.listBuckets();}/** * 初始化minio配置 * * @param : * @return: void * @date : 2020/8/16 20:56 */@PostConstructpublic void init() {try {minioClient = MinioClient.builder().endpoint(storageProperty.getUrl()).credentials(storageProperty.getAccessKey(), storageProperty.getSecretKey()).build();} catch (Exception e) {e.printStackTrace();log.error("初始化minio配置异常: 【{}】", e.fillInStackTrace());}}}
3、minio工具类
import io.minio.*;import lombok.extern.slf4j.Slf4j;import org.springframework.stereotype.Component;import org.springframework.web.multipart.MultipartFile;import javax.servlet.ServletOutputStream;import javax.servlet.http.HttpServletResponse;import java.io.InputStream;import java.nio.charset.StandardCharsets;import java.util.Map;/** * @Author yang * @Date 2023/1/3 14:15 * @Version 1.0 */@Slf4j@Componentpublic class MinioUtil {/** * Minio文件上传 * * @param file 文件实体 * @param fileName 修饰过的文件名 非源文件名 * @param bucketName 所存文件夹(桶名) * @return */public ResultEntity<Map> minioUpload(MultipartFile file, String fileName, String bucketName) {ResultEntity<Map> resultEntity = new ResultEntity();try {MinioClient minioClient = MinioClientConfig.getMinioClient();// fileName为空,说明要使用源文件名上传if (fileName == null) {fileName = file.getOriginalFilename();fileName = fileName.replaceAll(" ", "_");}InputStream inputStream = file.getInputStream();PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(bucketName).object(fileName).stream(inputStream, file.getSize(), -1).contentType(file.getContentType()).build();//文件名称相同会覆盖minioClient.putObject(objectArgs);return resultEntity;} catch (Exception e) {e.printStackTrace();return null;}}/** * 检查存储桶是否存在 * * @param bucketName 存储桶名称 * @return */public boolean bucketExists(String bucketName) {boolean flag = false;try {flag = MinioClientConfig.bucketExists(bucketName);if (flag) {return true;}} catch (Exception e) {e.printStackTrace();return false;}return false;}/** * 获取文件流 * * @param fileName 文件名 * @param bucketName 桶名(文件夹) * @return */public InputStream getFileInputStream(String fileName, String bucketName) {try {MinioClient minioClient = MinioClientConfig.getMinioClient();return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(fileName).build());} catch (Exception e) {e.printStackTrace();log.error(e.getMessage());}return null;}/** * @param bucketName: * @author * @description: 创建桶 * @date 2022/8/16 14:36 */public void createBucketName(String bucketName) {try {if (StringUtils.isBlank(bucketName)) {return;}MinioClient minioClient = MinioClientConfig.getMinioClient();boolean isExist = MinioClientConfig.bucketExists(bucketName);if (isExist) {log.info("Bucket {} already exists.", bucketName);} else {minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());}} catch (Exception e) {e.printStackTrace();log.error(e.getMessage());}}/** * 下载文件 * * @param originalName 文件路径 */public InputStream downloadFile(String bucketName, String originalName, HttpServletResponse response) {try {MinioClient minioClient = MinioClientConfig.getMinioClient();InputStream file = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(originalName).build());String filename = new String(originalName.getBytes("ISO8859-1"), StandardCharsets.UTF_8);if (StringUtils.isNotBlank(originalName)) {filename = originalName;}response.setHeader("Content-Disposition", "attachment;filename=" + filename);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();return file;} catch (Exception e) {e.printStackTrace();return null;}}/** * @param bucketName: * @description: 删除桶 * @date 2022/8/16 14:36 */public void deleteBucketName(String bucketName) {try {if (StringUtils.isBlank(bucketName)) {return;}MinioClient minioClient = MinioClientConfig.getMinioClient();boolean isExist = MinioClientConfig.bucketExists(bucketName);if (isExist) {minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());}} catch (Exception e) {e.printStackTrace();log.error(e.getMessage());}}/** * @param bucketName: * @description: 删除桶下面所有文件 * @date 2022/8/16 14:36 */public void deleteBucketFile(String bucketName) {try {if (StringUtils.isBlank(bucketName)) {return;}MinioClient minioClient = MinioClientConfig.getMinioClient();boolean isExist = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());if (isExist) {minioClient.deleteBucketEncryption(DeleteBucketEncryptionArgs.builder().bucket(bucketName).build());}} catch (Exception e) {e.printStackTrace();log.error(e.getMessage());}}/** * 根据文件路径得到预览文件绝对地址 * * @param bucketName * @param fileName * @return */public String getPreviewFileUrl(String bucketName, String fileName) {try {MinioClient minioClient = MinioClientConfig.getMinioClient();return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().bucket(bucketName).object(fileName).build());} catch (Exception e) {e.printStackTrace();return "";}}}
六、MinIoController
文件上传、文件读取、文件下载、文件删除接口如下:
/** * @Author yangb * @Date 2022/11/27 15:55 * @Version 1.0 */@RestController@RequestMapping("/minio")public class MinIoController extends BaseController {MinioUtil minioUtil = new MinioUtil();/** * 上传文件 * @param file * @return */@PostMapping("/uploadFile")public AjaxResult uploadFile(@RequestBody MultipartFile file) {MinioClient minioClient = MinioClientConfig.getMinioClient();if (minioClient == null) {return AjaxResult.error("连接MinIO服务器失败", null);}ResultEntity<Map> result = minioUtil.minioUpload(file, "", "data-enpower");if (result.getCode() == 0) {return AjaxResult.success("上传成功");} else {return AjaxResult.error("上传错误!!!");}}/** * 获取文件预览地址 * @param fileName * @return */@RequestMapping("/getRedFile")public AjaxResult getRedFile(@RequestBody String fileName) {MinioClient minioClient = MinioClientConfig.getMinioClient();if (minioClient == null) {return AjaxResult.error("连接MinIO服务器失败", null);}String url = minioUtil.getPreviewFileUrl("data-enpower",fileName);return AjaxResult.success(url);}/** * 下载文件 * @param fileName * @param response * @return */@RequestMapping("/downloadFile")public String downloadFile(@RequestParam String fileName, HttpServletResponse response) {MinioClient minioClient = MinioClientConfig.getMinioClient();if (minioClient == null) {return "连接MinIO服务器失败";}return minioUtil.downloadFile("data-enpower",fileName,response) != null ? "下载成功" : "下载失败";}/** * 删除文件 * * @param fileName 文件路径 * @return */@PostMapping("/deleteFile")public String deleteFile(String fileName) {MinioClient minioClient = MinioClientConfig.getMinioClient();if (minioClient == null) {return "连接MinIO服务器失败";}boolean flag = minioUtil.deleteFile("data-enpower",fileName);return flag == true ? "删除成功" : "删除失败";}}
七、调试结果
1、文件上传
minio上的文件
2、 文件下载
3、 文件删除
我们在minio上看看文件是否已删除