当前位置: 首页 > news >正文

Sring Boot整合Minio实现图片上传功能

若依前后端分离版本整合Minio

一、docker下载Minio镜像

# 下载最新版Minio镜像 (等同于 : docker pull minio/minio:latest )
docker pull minio/minio 

 报错解决方案:Error response from daemon: Get “https://registry-1.docker.io/v2/“: context deadline exceeded-CSDN博客

结果:

二、创建目录

一个用来存放配置,一个用来存储上传文件的目录

启动前需要先创建Minio外部挂载的配置文件( /opt/minio/config),和存储上传文件的目录( /opt/minio/data)

mkdir -p /opt/minio/config

mkdir -p /opt/minio/data

三、创建Minio容器

docker run -d -p 9000:9000 --name minio \
-p 9001:9001 \
-e "MINIO_ACCESS_KEY=minio" \
-e "MINIO_SECRET_KEY=minio123" \
-v /opt/minio/data:/data \
-v /opt/minio/config:/root/.minio \
minio/minio server /data \
--console-address ":9001"

四、运行minio

访问地址:http://ip地址:9001/login
用户名:minio
密码:minio123

四、创建桶Buckets

1、找到创建桶的位置

2、输入桶名称:test

3、创建成功

4、bucket权限设置:将Access Policy改为public 

5、用户创建

identity—>users—>Create User

用户名为minio密码为minio123,权限配置为读写,点击保存。

java配置信息中所配置的key就是此处的用户。

五、基本依赖和配置

1、在pom.xml文件中引入minio依赖

<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>7.1.0</version>
</dependency>

2、在yml文件里加上minio配置信息 

#文件服务器  
minio:
  url: http://{这里填服务器的ip地址}:9000  服务器ip
  access-key: minio  账号
  secret-key: minio123  密码
  bucket-name: test  桶名称,minio服务器配置

3、minio客户端配置类

package com.health.common.config;

import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Minio客户端注入
 */
@ConfigurationProperties(prefix = "minio")
@Configuration
public class MinioConfig {
    @Value("${minio.accessKey}")
    private static String accessKey;

    @Value("${minio.secretKey}")
    private static String secretKey;

    @Value("${minio.url}")
    private static String url;

    /** 获取yml配置类里的桶名称*/
    @Value("${minio.bucket-name}")
    private static String bucketName;

    public static String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        MinioConfig.url = url;
    }

    public static String getAccessKey() {
        return accessKey;
    }

    public void setAccessKey(String accessKey) {
        MinioConfig.accessKey = accessKey;
    }

    public static String getSecretKey() {
        return secretKey;
    }

    public void setSecretKey(String secretKey) {
        MinioConfig.secretKey = secretKey;
    }

    public static String getBucketName() {
        return bucketName;
    }

    public void setBucketName(String bucketName) {
        MinioConfig.bucketName = bucketName;
    }

    @Bean
    public MinioClient getMinioClient() {
        return MinioClient.builder().endpoint(url).credentials(accessKey, secretKey).build();
    }
}

4、 新增MinioUtil工具类

package com.health.common.utils.file;

import com.health.common.utils.ServletUtils;
import com.health.common.utils.spring.SpringUtils;
import io.minio.GetPresignedObjectUrlArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.http.Method;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;

public class MinioUtil {
    /**
     * 上传文件
     *
     * @param bucketName 桶名称
     * @param fileName
     *
     * @throws IOException
     */
    public static String uploadFile(String bucketName,
                                    String fileName,
                                    MultipartFile multipartFile) throws IOException {
        String url;
        MinioClient minioClient = SpringUtils.getBean(MinioClient.class);
        try (InputStream inputStream = multipartFile.getInputStream()) {
            minioClient.putObject(PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(fileName)
                    .stream(inputStream, multipartFile.getSize(), -1)
                    .contentType(multipartFile.getContentType())
                    .build());
            url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                    .bucket(bucketName)
                    .object(fileName)
                    .method(Method.GET)
                    .build());
            url = url.substring(0, url.indexOf('?'));
            return ServletUtils.urlDecode(url);
        }
        catch (Exception e) {
            throw new IOException(e.getMessage(), e);
        }
    }
}

5、FileUploadUtils工具类新增minio的相关配置,完整代码如下

package com.health.common.utils.file;

import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Objects;

import com.health.common.config.MinioConfig;
import org.apache.commons.io.FilenameUtils;
import org.springframework.web.multipart.MultipartFile;
import com.health.common.config.HealthConfig;
import com.health.common.constant.Constants;
import com.health.common.exception.file.FileNameLengthLimitExceededException;
import com.health.common.exception.file.FileSizeLimitExceededException;
import com.health.common.exception.file.InvalidExtensionException;
import com.health.common.utils.DateUtils;
import com.health.common.utils.StringUtils;
import com.health.common.utils.uuid.Seq;

/**
 * 文件上传工具类
 *
 * @author ruoyi
 */
public class FileUploadUtils
{
    /**
     * 默认大小 50M
     */
    public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024L;

    /**
     * 默认的文件名最大长度 100
     */
    public static final int DEFAULT_FILE_NAME_LENGTH = 100;

    /**
     * 默认上传的地址
     */
    private static String defaultBaseDir = HealthConfig.getProfile();

    /**
     * Minio默认上传的地址
     */
    private static final String bucketName = MinioConfig.getBucketName();

    public static String getBucketName() {
        return bucketName;
    }

    public static void setDefaultBaseDir(String defaultBaseDir)
    {
        FileUploadUtils.defaultBaseDir = defaultBaseDir;
    }

    public static String getDefaultBaseDir()
    {
        return defaultBaseDir;
    }

    /**
     * 以默认配置进行文件上传
     *
     * @param file 上传的文件
     * @return 文件名称
     * @throws Exception
     */
    public static final String upload(MultipartFile file) throws IOException
    {
        try
        {
            return upload(getDefaultBaseDir(), file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
        }
        catch (Exception e)
        {
            throw new IOException(e.getMessage(), e);
        }
    }

    /**
     * 根据文件路径上传
     *
     * @param baseDir 相对应用的基目录
     * @param file 上传的文件
     * @return 文件名称
     * @throws IOException
     */
    public static final String upload(String baseDir, MultipartFile file) throws IOException
    {
        try
        {
            return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
        }
        catch (Exception e)
        {
            throw new IOException(e.getMessage(), e);
        }
    }

    /**
     * 文件上传
     *
     * @param baseDir 相对应用的基目录
     * @param file 上传的文件
     * @param allowedExtension 上传文件类型
     * @return 返回上传成功的文件名
     * @throws FileSizeLimitExceededException 如果超出最大大小
     * @throws FileNameLengthLimitExceededException 文件名太长
     * @throws IOException 比如读写文件出错时
     * @throws InvalidExtensionException 文件校验异常
     */
    public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension)
            throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
            InvalidExtensionException
    {
        int fileNamelength = Objects.requireNonNull(file.getOriginalFilename()).length();
        if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH)
        {
            throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
        }

        assertAllowed(file, allowedExtension);

        String fileName = extractFilename(file);

        String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();
        file.transferTo(Paths.get(absPath));
        return getPathFileName(baseDir, fileName);
    }

    /**
     * 以默认BucketName配置上传到Minio服务器
     *
     * @param file 上传的文件
     *
     * @return 文件名称
     *
     * @throws Exception
     */
    public static String uploadMinio(MultipartFile file) throws IOException {
        try {
            return uploadMinino(getBucketName(), file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
        }
        catch (Exception e) {
            throw new IOException(e.getMessage(), e);
        }
    }

    /**
     * 自定义bucketName配置上传到Minio服务器
     *
     * @param file 上传的文件
     *
     * @return 文件名称
     *
     * @throws Exception
     */
    public static String uploadMinio(MultipartFile file,
                                     String bucketName) throws IOException {
        try {
            return uploadMinino(bucketName, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
        }
        catch (Exception e) {
            throw new IOException(e.getMessage(), e);
        }
    }

    private static String uploadMinino(String bucketName,
                                       MultipartFile file,
                                       String[] allowedExtension) throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException, InvalidExtensionException {
        int fileNameLength = file.getOriginalFilename().length();
        if (fileNameLength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) {
            throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
        }
        assertAllowed(file, allowedExtension);
        try {
            String fileName = extractFilename(file);
            return MinioUtil.uploadFile(bucketName, fileName, file);
        }
        catch (Exception e) {
            throw new IOException(e.getMessage(), e);
        }
    }


    /**
     * 编码文件名
     */
    public static final String extractFilename(MultipartFile file)
    {
        return StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(),
                FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), getExtension(file));
    }

    public static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException
    {
        File desc = new File(uploadDir + File.separator + fileName);

        if (!desc.exists())
        {
            if (!desc.getParentFile().exists())
            {
                desc.getParentFile().mkdirs();
            }
        }
        return desc;
    }

    public static final String getPathFileName(String uploadDir, String fileName) throws IOException
    {
        int dirLastIndex = HealthConfig.getProfile().length() + 1;
        String currentDir = StringUtils.substring(uploadDir, dirLastIndex);
        return Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName;
    }

    /**
     * 文件大小校验
     *
     * @param file 上传的文件
     * @return
     * @throws FileSizeLimitExceededException 如果超出最大大小
     * @throws InvalidExtensionException
     */
    public static final void assertAllowed(MultipartFile file, String[] allowedExtension)
            throws FileSizeLimitExceededException, InvalidExtensionException
    {
        long size = file.getSize();
        if (size > DEFAULT_MAX_SIZE)
        {
            throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024);
        }

        String fileName = file.getOriginalFilename();
        String extension = getExtension(file);
        if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension))
        {
            if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION)
            {
                throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension,
                        fileName);
            }
            else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION)
            {
                throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension,
                        fileName);
            }
            else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION)
            {
                throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension,
                        fileName);
            }
            else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION)
            {
                throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension,
                        fileName);
            }
            else
            {
                throw new InvalidExtensionException(allowedExtension, extension, fileName);
            }
        }
    }

    /**
     * 判断MIME类型是否是允许的MIME类型
     *
     * @param extension
     * @param allowedExtension
     * @return
     */
    public static final boolean isAllowedExtension(String extension, String[] allowedExtension)
    {
        for (String str : allowedExtension)
        {
            if (str.equalsIgnoreCase(extension))
            {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取文件名的后缀
     *
     * @param file 表单文件
     * @return 后缀名
     */
    public static final String getExtension(MultipartFile file)
    {
        String extension = FilenameUtils.getExtension(file.getOriginalFilename());
        if (StringUtils.isEmpty(extension))
        {
            extension = MimeTypeUtils.getExtension(Objects.requireNonNull(file.getContentType()));
        }
        return extension;
    }
}

6、CommonController.java自定义Minio服务器上传请求(com.health.web.controller.common)

/**
     * 自定义 Minio 服务器上传请求
     */
    @PostMapping("/uploadMinio")
    public AjaxResult uploadFileMinio(MultipartFile file) {
        try {
            // 上传并返回新文件名称
            String fileName = FileUploadUtils.uploadMinio(file);
            AjaxResult ajax = AjaxResult.success();
            ajax.put("url", fileName);
            ajax.put("fileName", fileName);
            ajax.put("newFileName", FileUtils.getName(fileName));
            ajax.put("originalFilename", file.getOriginalFilename());
            return ajax;
        }
        catch (Exception e) {
            return AjaxResult.error(e.getMessage());
        }
    }

六、Vue3前端改写

分别修改:

 src/components/ImageUpload/index.vue

src/components/FileUpload/index.vue

到此就全部结束了!!!

 感谢🌹:若依框架(RuoYi)集成minio实现文件上传、预览 - 码匠的随手分享

相关文章:

  • Web3 环境下用户数据隐私保护的技术方案分析
  • 【初学者】谈谈DeepSeek使用的算法?
  • 合法C标识符查(信息学奥赛一本通-1134)
  • 告别“人工智障”!给小米音箱“开个挂”?(接入各类AI大模型,让小爱同学秒变全屋智能AI中枢!)
  • 深入解析 Linux 声卡驱动:从架构到实战
  • 《深度学习》—— YOLOv1
  • 【Python数据分析+可视化项目案例】:亚马逊平台用户订单数据分析
  • pytorch3d学习(五)——批量输出图片+对渲染器的位姿解读+npy文件解读
  • 基于django的线上教育平台大数据分析-spark+spider+vue
  • 交易所系统平台开发流程及核心优势解析
  • 记录 macOS 上使用 Homebrew 安装的软件
  • Fragment与React.StrictMode一起使用时有什么需要注意的?
  • 佳能(Canon)摄像机断电dat文件0字节的恢复方法
  • WRF/Chem在线耦合模式:大气污染模拟的时空密码—从气象场驱动到化学反馈的全过程解析
  • Java开发经验——Throwable/Exception异常处理方式
  • Innodb的索引结构和MyISAM有区别吗
  • 哪些企业需要做Ecovadis认证?
  • PCIE Spec ---Software Initialization and Configuration(二)
  • 计算机网络基础:认识网络硬件与传输介质
  • 【MATLAB例程】三维环境下,动态轨迹的AOA定位与UKF滤波,模拟IMU/AOA的数据融合,附完整代码
  • “一码难求”的Manus开放注册但价格不菲,智能体距离“实用”还有多远
  • 中华人民共和国和巴西联邦共和国关于强化携手构建更公正世界和更可持续星球的中巴命运共同体,共同维护多边主义的联合声明
  • 梅花奖在上海|“我的乱弹我的团”,民营院团首次入围终评
  • 中国社科院:网文市场超430亿元,作者破3000万人
  • 时代中国控股:前4个月销售额18.1亿元,境外债重组协议押后聆讯至5月底
  • 市自规局公告收回新校区建设用地,宿迁学院:需变更建设主体