小工具知识网

当前位置: 首页 > 行业知识 > SpringBoot整合Minio的详细步骤

行业知识

SpringBoot整合Minio的详细步骤

2026-11-02 02:14:14 来源:互联网转载

小伙伴们好,欢迎关注,一起学习,无限进步

minio 是对象存储服务。它基于 Apache License 开源协议,兼容 Amazon S3 云存储接口。适合存储非结构化数据,如图片,音频,视频,日志等。对象文件最大可以达到 5TB。

优点有高性能,可扩展,操作简单,有图形化操作界面,读写性能优异等。官网

minio 部署可参考这篇:Minio 详细安装部署步骤

SpringBoot 快速整合 minio

1、添加 Maven 依赖

在 pom.xml 文件中添加MinIO客户端依赖项

    io.minio    minio    8.2.2    com.alibaba    fastjson    1.2.78

2、配置MinIO连接信息

在 application.properties 或 application.yml 文件中配置MinIO的连接信息,包括服务器地址、端口、凭据等信息

# Minio 配置minio.endpoint=127.0.0.1:9000 #对象存储服务的URLminio.accessKey=admin #Access key账户 写账号也可以minio.secretKey=admin #Secret key密码minio.bucketName=test # 桶名称# 过期时间minio.expire=7200
# Minio 配置minio:  endpoint:  127.0.0.1:9000 #对象存储服务的URL  accessKey: admin #Access key账户 写账号也可以  secretKey: admin #Secret key密码  bucketName: test # 桶名称  expire: 7200 # 过期时间

3、创建 MinIO 客户端 Bean

在 SpringBoot 应用的配置类中创建一个 MinIO客户端的 Bean,以便在应用中使用 MinIO 服务

import lombok.Data;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.stereotype.Component;/** * minio 配置属性 */@Data@Component@ConfigurationProperties(prefix = "minio")public class MinioProperties {    /**     * Minio 连接地址     */    private String endpoint;    /**     * accessKey 或 账号     */    private String accessKey;    /**     * secretKey 或 密码     */    private String secretKey;    /**     * 桶名称     */    private String bucketName;    /**     * 默认是秒 地址过期时间,设置默认值7200秒     */    private int expire = 7200;}

4、异常枚举类

/** * 异常枚举类 */public enum ExceptionEnums {    FILE_NAME_NOT_NULL("0001", "文件名不能为空"),    BUCKET_NAME_NOT_NULL("0002", "桶名称不能为空"),    FILE_NOT_EXIST("0003", "文件不存在"),    BUCKET_NOT_EXIST("0004", "桶不存在"),    BUCKET_NAME_NOT_EXIST("0005", "桶不存在,需要先创建桶在创建文件夹");//枚举类如果写方法的话,此处需要写分号    private String code;    private String msg;    ExceptionEnums(String ecode, String emsg) {        this.code = ecode;        this.msg = emsg;    }    public String getCode() {        return code;    }    public String getMsg() {        return msg;    }    public static ExceptionEnums statOf(String code) {        for (ExceptionEnums state : values())            if (state.getCode().equals(code))                return state;        return null;    }}

5、全局异常

import org.springframework.http.HttpStatus;/** * 异常 */public class GeneralException extends RuntimeException {    private Integer errorCode;    public GeneralException() {    }    public GeneralException(Throwable throwable) {        super(throwable);    }    public GeneralException(String msg) {        super(msg);        this.errorCode = HttpStatus.INTERNAL_SERVER_ERROR.value();    }    public GeneralException(Integer errorCode, String msg) {        super(msg);        this.errorCode = errorCode;    }    public Integer getErrorCode() {        return this.errorCode;    }    public void setErrorCode(Integer errorCode) {        this.errorCode = errorCode;    }}

6、minio 工具类

工具类包含创建 bucket,获取全部 bucket,获取 bucket 文件名和大小列表,文件上传,获取上传文件的完整路径,创建文件夹或目录,判断 bucket 是否存在,判断文件是否存在,文件下载,删除文件,批量删除文件方法

import com.alibaba.fastjson.JSON;import io.minio.*;import io.minio.errors.*;import io.minio.http.Method;import io.minio.messages.Bucket;import io.minio.messages.DeleteError;import io.minio.messages.DeleteObject;import io.minio.messages.Item;import lombok.extern.slf4j.Slf4j;import org.apache.tomcat.util.http.fileupload.IOUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import org.springframework.util.CollectionUtils;import org.springframework.util.StringUtils;import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletResponse;import java.io.ByteArrayInputStream;import java.io.IOException;import java.io.InputStream;import java.net.URLEncoder;import java.security.InvalidKeyException;import java.security.NoSuchAlgorithmException;import java.text.DecimalFormat;import java.util.*;/** * Minio 工具类 */@Component@Slf4jpublic class MinioUtils {    @Autowired    private MinioClient minioClient;    @Autowired    private MinioProperties minioProperties;    /**     * 初始化Bucket     */    private void createBucket(String bucketName) {        try {            // 判断 BucketName 是否存在            if (bucketExists(bucketName)) {                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());            }        } catch (Exception e) {            e.printStackTrace();        }    }    /**     * 验证bucketName是否存在     *     * @return boolean true:存在     */    public boolean bucketExists(String bucketName) {        if (StringUtils.isEmpty(bucketName)) {            throw new GeneralException(ExceptionEnums.BUCKET_NAME_NOT_NULL.getMsg());        }        boolean flag = true;        try {            flag = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());        } catch (Exception e) {            e.printStackTrace();        }        return flag;    }    /**     * 获取全部bucket     * 

*/ public List getAllBuckets() { List list = null; try { final List buckets = minioClient.listBuckets(); list = new ArrayList(buckets.size()); for (Bucket bucket : buckets) { list.add(bucket.name()); } } catch (Exception e) { e.printStackTrace(); } return list; } /** * 根据bucketName获取信息 * * @param bucketName bucket名称 * @return */ public String getBucket(String bucketName) throws Exception { final Optional first = minioClient.listBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst(); String name = null; if (first.isPresent()) { name = first.get().name(); } return name; } /** * 获取桶中文件名和大小列表 * * @param bucketName bucket名称 * @param recursive 查询是否递归 * @return */ public List getFileList(String bucketName, boolean recursive) { if (StringUtils.isEmpty(bucketName)) { throw new GeneralException(ExceptionEnums.BUCKET_NAME_NOT_NULL.getMsg()); } List items = new ArrayList(); try { Iterable myObjects = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix("/2022-08-03/4674a894-abaf-48cb-9ea9-40a4e8560af9/Desktop").recursive(recursive).build()); Iterator iterator = myObjects.iterator(); String format = "{'fileName':'%s','fileSize':'%s'}"; for (Result myObject : myObjects) { System.out.println(myObject.get().objectName()); } while (iterator.hasNext()) { Item item = iterator.next().get(); items.add(JSON.parse(String.format(format, item.objectName(), formatFileSize(item.size()))));// items.add(JSON.parse(String.format(format, "/".concat("test").concat("/").concat(item.objectName()), formatFileSize(item.size())))); } } catch (Exception e) { e.printStackTrace(); log.info(e.getMessage()); } items.remove(0); return items; } /** * 文件上传 * * @param file * @return */ public Map uploadFile(String bucketName, MultipartFile[] file) { if (file == null || file.length == 0) { throw new GeneralException(ExceptionEnums.FILE_NAME_NOT_NULL.getMsg()); } if (StringUtils.isEmpty(bucketName)) { throw new GeneralException(ExceptionEnums.BUCKET_NAME_NOT_NULL.getMsg()); } List orgfileNameList = new ArrayList(file.length); for (MultipartFile multipartFile : file) { String orgfileName = multipartFile.getOriginalFilename(); orgfileNameList.add(orgfileName); try { //文件上传 InputStream in = multipartFile.getInputStream(); minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(orgfileName).stream(in, multipartFile.getSize(), -1).contentType(multipartFile.getContentType()).build()); in.close(); } catch (Exception e) { e.printStackTrace(); log.error(e.getMessage()); } } Map data = new HashMap(); data.put("bucketName", bucketName); data.put("fileName", orgfileNameList); return data; } /** * 获取上传文件的完整路径 * * @param bucketName 桶名称 * @param fileName 文件名 * @param expire 地址过期时间 * @return */ public String getPresignedObjectUrl(String bucketName, String fileName, Integer expire) { if (StringUtils.isEmpty(bucketName)) { throw new GeneralException(ExceptionEnums.BUCKET_NAME_NOT_NULL.getMsg()); } if (StringUtils.isEmpty(fileName)) { throw new GeneralException(ExceptionEnums.FILE_NAME_NOT_NULL.getMsg()); } expire = Objects.isNull(expire) ? minioProperties.getExpire() : expire; // 验证桶是否存在在 final boolean validationBucket = bucketExists(bucketName); if (!validationBucket) { throw new GeneralException(ExceptionEnums.BUCKET_NOT_EXIST.getMsg()); } // 验证文件是否存在 final boolean validationFileName = doFileNameExist(bucketName, fileName); if (!validationFileName) { throw new GeneralException(ExceptionEnums.FILE_NOT_EXIST.getMsg()); } String url = null; try { // 获取桶和文件的完整路径 url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().bucket(bucketName).object(fileName).method(Method.GET).expiry(expire).build()); } catch (MinioException e) { log.error("Error occurred: " + e); } catch (Exception e) { e.printStackTrace(); } return url; } /** * 创建文件夹或目录 * * @param bucketName 存储桶 * @param objectName 目录路径 */ public Map putDirObject(String bucketName, String objectName) throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, ErrorResponseException { // 判断桶是否存在 if (!bucketExists(bucketName)) { throw new GeneralException(ExceptionEnums.BUCKET_NAME_NOT_EXIST.getMsg()); } final ObjectWriteResponse response = minioClient.putObject( PutObjectArgs.builder().bucket(bucketName).object(objectName).stream( new ByteArrayInputStream(new byte[]{}), 0, -1) .build()); Map map = new HashMap(); map.put("etag", response.etag()); map.put("versionId", response.versionId()); return map; } /** * 判断桶是否存在 * * @param bucketName 存储桶 * @param objectName 文件夹名称(去掉/) * @return true:存在 */ public boolean doFolderExist(String bucketName, String objectName) { boolean exist = false; try { Iterable results = minioClient.listObjects( ListObjectsArgs.builder().bucket(bucketName).prefix(objectName).recursive(false).build()); for (Result result : results) { Item item = result.get(); if (item.isDir()) { exist = true; } } } catch (Exception e) { exist = false; } return exist; } /** * 判断文件是否存在 * * @param fileName 对象 * @return true:存在 */ public boolean doFileNameExist(String bucketName, String fileName) { if (StringUtils.isEmpty(bucketName)) { throw new GeneralException(ExceptionEnums.BUCKET_NAME_NOT_NULL.getMsg()); } if (StringUtils.isEmpty(fileName)) { throw new GeneralException(ExceptionEnums.FILE_NAME_NOT_NULL.getMsg()); } boolean exist = true; try { minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(fileName).build()); } catch (Exception e) { exist = false; } return exist; } /** * 文件下载 * * @param response * @param fileName */ public void downloadFile(HttpServletResponse response, String bucketName, String fileName) { if (StringUtils.isEmpty(bucketName)) { throw new GeneralException(ExceptionEnums.BUCKET_NAME_NOT_NULL.getMsg()); } if (StringUtils.isEmpty(fileName)) { throw new GeneralException(ExceptionEnums.FILE_NAME_NOT_NULL.getMsg()); } // 判断文件是否存在 final boolean flag = doFileNameExist(bucketName, fileName); if (!flag) { throw new GeneralException(ExceptionEnums.FILE_NOT_EXIST.getMsg()); } InputStream in = null; try { // 获取对象信息 StatObjectResponse stat = minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(fileName).build()); response.setContentType(stat.contentType()); response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8")); //文件下载 in = minioClient.getObject( GetObjectArgs.builder().bucket(bucketName).object(fileName).build()); IOUtils.copy(in, response.getOutputStream()); } catch (Exception e) { log.error(e.getMessage()); } finally { if (in != null) { try { in.close(); } catch (IOException e) { log.error(e.getMessage()); } } } } /** * 删除文件 * * @param bucketName bucket名称 * @param fileName 文件名称 * 说明:当前方法不能真正删除,需要验证 */ public void deleteFile(String bucketName, String fileName) { if (StringUtils.isEmpty(bucketName)) { throw new GeneralException(ExceptionEnums.BUCKET_NAME_NOT_NULL.getMsg()); } if (StringUtils.isEmpty(fileName)) { throw new GeneralException(ExceptionEnums.FILE_NAME_NOT_NULL.getMsg()); } try { minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build()); } catch (Exception e) { log.error(e.getMessage()); e.printStackTrace(); } } /** * 批量文件删除 * * @param bucketName bucket名称 * @param fileNames 文件名 */ public void deleteBatchFile(String bucketName, List fileNames) { if (StringUtils.isEmpty(bucketName)) { throw new GeneralException(ExceptionEnums.BUCKET_NAME_NOT_NULL.getMsg()); } if (CollectionUtils.isEmpty(fileNames)) { throw new GeneralException(ExceptionEnums.FILE_NAME_NOT_NULL.getMsg()); } try { List objects = new LinkedList(); for (String fileName : fileNames) { objects.add(new DeleteObject(fileName)); } Iterable results = minioClient.removeObjects( RemoveObjectsArgs.builder().bucket(bucketName).objects(objects).build()); for (Result result : results) { DeleteError error = result.get(); log.error("Error occurred: " + error); } } catch (Exception e) { e.printStackTrace(); log.error("批量删除失败!error:{}", e); } } /** * 文件大小 * * @param fileS * @return */ private static String formatFileSize(long fileS) { DecimalFormat df = new DecimalFormat("#.00"); String fileSizeString = ""; String wrongSize = "0B"; if (fileS == 0) { return wrongSize; } if (fileS

7、文件调用接口

上传文件,获取上传文件完整路径,文件下载,文件删除,批量删除

import org.springframework.beans.factory.annotation.Autowired;import org.springframework.util.StringUtils;import org.springframework.web.bind.annotation.*;import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletResponse;import java.util.List;import java.util.Map;@RestControllerpublic class MinioController {    @Autowired    private MinioUtils minioUtils;    /**     * 获取桶中文件名和大小列表     *     * @return     */    @GetMapping("/getFileList")    public List getFileList() {        return minioUtils.getFileList("test", true);    }    /**     * 判断文件是否存在     *     * @param bucketName     * @param fileName     * @return     */    @GetMapping("/doFileNameExist")    public boolean doFileNameExist(String bucketName, String fileName) {        return minioUtils.doFolderExist(bucketName, fileName);    }    /**     * 上传文件     *     * @param file     * @return     */    @PostMapping("/uploadFiles")    public Map uploadFiles(String bucketName, @RequestParam(name = "file", required = false) MultipartFile[] file) {        if (file == null || file.length == 0) {            throw new GeneralException(ExceptionEnums.FILE_NAME_NOT_NULL.getMsg());        }        if (StringUtils.isEmpty(bucketName)) {            throw new GeneralException(ExceptionEnums.BUCKET_NAME_NOT_NULL.getMsg());        }        return minioUtils.uploadFile(bucketName, file);    }    /**     * 获取上传文件的完整浏览路径     *     * @param filename     * @return     */    @GetMapping("/getPresignedObjectUrl")    public String getPresignedObjectUrl(@RequestParam(name = "filename") String filename) {        return minioUtils.getPresignedObjectUrl("test", filename, null);    }    /**     * 文件下载     *     * @param response     * @param fileName     */    @GetMapping("/downloadFile")    public void downloadFile(HttpServletResponse response, @RequestParam("fileName") String fileName) {        minioUtils.downloadFile(response, "test", fileName);    }    /**     * 删除单个文件     *     * @param fileName 完整路径(不包含bucket)     */    @DeleteMapping("/deleteFile")    public void deleteFile(String bucketName, String fileName) {        minioUtils.deleteFile(bucketName, fileName);    }    /**     * 批量删除文件     *     * @param fileNames 完整路径(不包含bucket)     */    @DeleteMapping("/deleteBatchFile")    public void deleteBatchFile(String bucketName, @RequestParam("fileNames") List fileNames) {        minioUtils.deleteBatchFile(bucketName, fileNames);    }}

上一篇:嵌入式驱动学习第一周——linux的休眠与唤醒

下一篇:有公网怎么架设服务器?