首页 > 其他分享 >MinIO实现文件上传

MinIO实现文件上传

时间:2022-09-19 17:13:05浏览次数:71  
标签:文件 return String minio bucket import 上传 public MinIO

一、使用Docker安装minio

docker run -d -p 9000:9000 -p 9001:9001 --name minio -e MINIO_ACCESS_KEY=qbb -e MINIO_SECRET_KEY=startqbb -v /opt/minio/data:/data -v /opt/minio/config:/root/.minio minio/minio server /data --console-address ":9000" --address ":9001"
  • MINIO_ACCESS_KEY:指定的是"用户名",可以这么理解,后面我们文件上传需要使用
  • MINIO_SECRET_KEY:指定的是"密码",可以这么理解,后面我们文件上传需要使用

二、创建一个Project工程(我是用的是Gradle,大家也可以使用Maven)

image

三、实现文件上传

1、导入相关依赖

plugins {
    id 'java'
}

group 'com.qbb'
version '1.0-SNAPSHOT'

repositories {
    mavenCentral()
}

dependencies {
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
    implementation 'org.springframework.boot:spring-boot-starter-web:2.7.3'
    implementation 'mysql:mysql-connector-java:8.0.29'
    implementation 'org.springframework.boot:spring-boot-starter-test:2.7.3'
    implementation 'org.projectlombok:lombok:1.18.24'
    implementation 'io.springfox:springfox-swagger2:3.0.0'
    implementation 'io.springfox:springfox-swagger-ui:3.0.0'
    implementation 'io.minio:minio:8.4.3'
}

test {
    useJUnitPlatform()
}

2、修改配置文件

# application.yml
server:
  port: 8080

spring:
  profiles:
    active: dev
#    include: dev
  application:
    name: minio

  #  这个mvc的配置是springboot2.6.1不支持swagger3的折衷配置,后面考虑升级Springboot版本或降级版本
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher

  servlet:
    multipart:
      # 设置 上传文件的大小
      max-file-size: 100MB
      # 设置 整个请求的大小
      max-request-size: 150MB
	  
	  
# application-dev.yml
swagger:
  enabled: true

app:
  minio:
    endpoint: http://192.168.119.159:9001
    accessKey: qbb
    secretKey: startqbb
    bucket: qbb

3、主启动类

package com.qbb.minio;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit)
 * @version 1.0
 * @date 2022-09-19  15:45
 * @Description:
 */
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

4、Swagger3配置类

package com.qbb.minio.config;


import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;

/**
 * @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit)
 * @version 1.0
 * @date 2022-09-19  15:45
 * @Description: Swagger配置
 */
@Configuration
@EnableOpenApi
public class SwaggerConfig {

    @Value("${swagger.enabled}")
    boolean swaggerEnabled;

    @Value("${spring.application.name}")
    String name;

    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.OAS_30).apiInfo(apiInfo())
                // 是否开启
                .enable(swaggerEnabled).select()
                // 扫描的路径使用@Api的controller
                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
                // 指定路径处理PathSelectors.any()代表所有的路径
                .paths(PathSelectors.any()).build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Swagger3接口文档")
                .description(name + "接口文档")
                //作者信息
                .contact(new Contact("startqbb", "https://www.cnblogs.com/qbbit", "[email protected]"))
                .version("1.0")
                .build();
    }

}

5、Minio配置类

package com.qbb.minio.config;

import io.minio.MinioClient;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit)
 * @version 1.0
 * @date 2022-09-19  15:57
 * @Description:
 */
@EnableConfigurationProperties
@ConfigurationProperties(prefix = "app.minio")
@Configuration
@Data
public class MinioConfig {

    private String endpoint;
    private String accessKey;
    private String secretKey;
    private String bucket;

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

6、Minio工具类

package com.qbb.minio.util;

import com.qbb.minio.config.MinioConfig;
import io.minio.*;
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.junit.platform.commons.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;

/**
 * @author QIUQIU&LL (个人博客:https://www.cnblogs.com/qbbit)
 * @version 1.0
 * @date 2022-09-19  16:44
 * @Description:
 */
@Component
@Slf4j
public class MinioUtil {

    @Autowired
    private MinioConfig minioConfig;

    @Resource
    private MinioClient minioClient;

    /**
     * 查看存储bucket是否存在
     *
     * @return boolean
     */
    public Boolean bucketExists(String bucketName) {
        boolean found;
        try {
            found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return found;
    }

    /**
     * 创建存储bucket
     */
    public void makeBucket(String bucketName) {
        try {
            minioClient.makeBucket(MakeBucketArgs.builder()
                    .bucket(bucketName)
                    .build());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 删除存储bucket
     *
     * @return Boolean
     */
    public Boolean removeBucket(String bucketName) {
        try {
            minioClient.removeBucket(RemoveBucketArgs.builder()
                    .bucket(bucketName)
                    .build());
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 获取全部bucket
     */
    public List<Bucket> getAllBuckets() {
        try {
            return minioClient.listBuckets();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 文件上传
     *
     * @param file 上传的文件
     * @return
     */
    public String upload(MultipartFile file) {
        String originalFilename = file.getOriginalFilename();
        if (StringUtils.isBlank(originalFilename)) {
            throw new RuntimeException();
        }
        String fileName = UUID.randomUUID().toString().replace("-", "") + "_" + originalFilename;
        // 日期目录
        // SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
        // String datePath = dateFormat.format(new Date());// 日期目录:2021/10/27
        // 也可以使用JDK1.8的新时间类LocalDate/LocalDateTime
        LocalDate now = LocalDate.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
        String formatDatePath = formatter.format(now);
        // 加一个时间戳
        long timeMillis = System.currentTimeMillis();
        String objectName = formatDatePath + "/" + timeMillis + fileName;
        try {
            PutObjectArgs objectArgs = PutObjectArgs.builder()
                    .bucket(minioConfig.getBucket())
                    .object(objectName)
                    .stream(file.getInputStream(), file.getSize(), -1)
                    .contentType(file.getContentType())
                    .build();
            minioClient.putObject(objectArgs);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return objectName;
    }

    /**
     * 预览图片
     *
     * @param fileName 文件名称
     * @return 图片地址
     */
    public String preview(String fileName) {
        // 查看文件地址
        GetPresignedObjectUrlArgs build = GetPresignedObjectUrlArgs.builder()
                .bucket(minioConfig.getBucket())
                .object(fileName)
                .method(Method.GET)
                .build();
        try {
            return minioClient.getPresignedObjectUrl(build);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 文件下载
     *
     * @param fileName 文件名称
     * @param res      response
     */
    public void download(String fileName, HttpServletResponse res) {
        GetObjectArgs objectArgs = GetObjectArgs.builder().bucket(minioConfig.getBucket())
                .object(fileName).build();
        try (GetObjectResponse response = minioClient.getObject(objectArgs)) {
            byte[] buf = new byte[1024];
            int len;
            try (FastByteArrayOutputStream os = new FastByteArrayOutputStream()) {
                while ((len = response.read(buf)) != -1) {
                    os.write(buf, 0, len);
                }
                os.flush();
                byte[] bytes = os.toByteArray();
                res.setCharacterEncoding("utf-8");
                // 设置强制下载不打开
                // res.setContentType("application/force-download");
                res.addHeader("Content-Disposition", "attachment;fileName=" + fileName);
                try (ServletOutputStream stream = res.getOutputStream()) {
                    stream.write(bytes);
                    stream.flush();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 查看文件对象
     *
     * @return 存储bucket内文件对象信息
     */
    public List<Item> listObjects(String bucketName) {
        if (StringUtils.isBlank(bucketName) || !bucketExists(bucketName)) {
            return null;
        }
        Iterable<Result<Item>> results = minioClient.listObjects(
                ListObjectsArgs.builder().bucket(bucketName).build());
        List<Item> items = new ArrayList<>();
        try {
            for (Result<Item> result : results) {
                items.add(result.get());
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return items;
    }


    /**
     * 获取单个桶中的所有文件对象名称
     *
     * @param bucket 桶名称
     * @return {@link List}<{@link String}>
     */
    public List<String> getBucketObjectName(String bucket) {
        boolean exsit = bucketExists(bucket);
        if (exsit) {
            List<String> listObjetcName = new ArrayList<>();
            try {
                Iterable<Result<Item>> myObjects = minioClient.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 fileName 文件名称
     * @return true|false
     */
    public boolean remove(String fileName) {
        try {
            minioClient.removeObject(RemoveObjectArgs.builder().bucket(minioConfig.getBucket()).object(fileName).build());
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    /**
     * 批量删除文件
     *
     * @param bucket      桶名称
     * @param objectNames 对象名称
     * @return boolean
     */
    public boolean removeObjects(String bucket, List<String> objectNames) {
        boolean exsit = bucketExists(bucket);
        if (exsit) {
            try {
                List<DeleteObject> objects = new LinkedList<>();
                for (String str : objectNames) {
                    objects.add(new DeleteObject(str));
                }
                minioClient.removeObjects(RemoveObjectsArgs.builder().bucket(bucket).objects(objects).build());
                return true;
            } catch (Exception e) {
                log.error("removeObjects", e);
            }
        }
        return false;
    }

}

7、测试

package com.qbb.minio.controller;

import com.qbb.minio.config.MinioConfig;
import com.qbb.minio.util.MinioUtil;
import io.minio.messages.Bucket;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.List;

/**
 * @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit)
 * @version 1.0
 * @date 2022-09-19  15:45
 * @Description:
 */
@Slf4j
@Api(tags = "MinIO")
@RestController
@RequestMapping("/minio")
public class FileUploadController {

    @Resource
    MinioConfig minioConfig;

    @Resource
    MinioUtil minioUtil;

    @ApiOperation("测试程序")
    @GetMapping("/hello")
    public String hello() {
        return "hello";
    }

    @ApiOperation("文件上传")
    @PostMapping("/upload")
    public String upload(@ApiParam("文件") MultipartFile file) {
        try {
            /**
             * 这里应该放在service层处理的,将上传的文件路径存入数据库,我就不这么麻烦了,直接返回给前端
             */
            String bucket = minioConfig.getBucket();
            String endpoint = minioConfig.getEndpoint();

            // 1.检查存储桶是否已经存在
            boolean isExist = minioUtil.bucketExists(bucket);
            if (isExist) {
                log.info("Bucket already exists");
            } else {
                // 不存在则创建一个名为bucket的存储桶,用于存储照片的zip文件。
                minioUtil.makeBucket(bucket);
            }
            // 2.上传
            String objectName = minioUtil.upload(file);
            // 3.访问路径
            return endpoint + "/" + bucket + "/" + objectName;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("文件上传异常!!!");
        }
    }

    @ApiOperation("文件下载")
    @GetMapping("/download")
    public void download(@RequestParam("fileName") String fileName, HttpServletResponse response) {
        minioUtil.download(fileName, response);
    }

    @ApiOperation("文件删除")
    @DeleteMapping("/remove")
    public String remove(@RequestParam("fileName") String fileName) {
        boolean flag = minioUtil.remove(fileName);
        if (flag) {
            return "success";
        }
        return "error";
    }

    @ApiOperation("文件预览")
    @GetMapping("/preview")
    public String preview(@RequestParam("fileName") String fileName) {
        String url = minioUtil.preview(fileName);
        if (!StringUtils.isEmpty(url)) {
            return url;
        }
        return "error";
    }

    @ApiOperation("获取Bucket列表")
    @GetMapping("/getAllBuckets")
    public List<Bucket> getAllBuckets() {
        return minioUtil.getAllBuckets();
    }

    @ApiOperation("创建一个Bucket")
    @PostMapping("/makeBucket/{bucketName}")
    public String makeBucket(@PathVariable("bucketName") String bucketName) {
        minioUtil.makeBucket(bucketName);
        return "success";
    }

    @ApiOperation("删除一个Bucket")
    @DeleteMapping("/removeBucket/{bucketName}")
    public String removeBucket(@PathVariable("bucketName") String bucketName) {
        Boolean isSuccess = minioUtil.removeBucket(bucketName);
        if (isSuccess) {
            return "success";
        }
        return "error";
    }

    @ApiOperation("查看Bucket中的所有Object")
    @GetMapping("/getBucketObjectName/{bucketName}")
    public List<String> getBucketObjectName(@PathVariable("bucketName") String bucketName) {
        return minioUtil.getBucketObjectName(bucketName);
    }
}

image

标签:文件,return,String,minio,bucket,import,上传,public,MinIO
From: https://www.cnblogs.com/qbbit/p/16708305.html

相关文章

  • 迅为3568开发板文件系统构建之简介
    迅为3568开发板文件系统构建之简介 1.1根文件系统简介在移植Linux系统的时候,我们需要先移植一个bootloader代码,bootLoader用于启动Linux内核,然后移植LinuxKernel,......
  • python主文件调用其他文件函数的方法
    关键:from文件名import函数名主文件(main.py)需要和包含子函数的文件(fun_cal_modulus8.py)放到同一路径下fun_cal_modulus8.pyfromnumpyimport*#8水平defc......
  • Java使用FTP下载文件(将流返回给HttpServletResponse)
    1.添加依赖<dependency><groupId>commons-net</groupId><artifactId>commons-net</artifactId><version>3.6</version>......
  • 给文件添加数字签名
    使用SignTool官方文档:https://learn.microsoft.com/zh-cn/windows/win32/seccrypto/signtool?redirectedfrom=MSDN签名盖时间戳服务器:http://timestamp.sectigo.com/1.......
  • 河北稳控科技可编程 USB 转串口适配器开发板芯片驱动文件说明
    可编程USB转UART/I2C/SMBusS/SPI/CAN/1-Wire适配器USB2S芯片驱动文件说明 芯片选择下拉框内列出的每一个备选芯片的驱动文件和数据手册位于S2STool工具文件夹中的......
  • vue中导出excel文件
    1、在src目录下创建一个目录vendor,放入Export2Excel.js2、安装相关组件npminstall-Sfile-saver 用来生成文件的web应用程序npminstall-Sxlsx 电子表格格......
  • /dev/null文件的作用以及使用方法
    关于/dev/null,以及如何使用它今天在看MIT的一个课程时,老师给的程序实例中有一个地方没弄明白:#!/bin/bashecho"Startingprogramat$(date)"#Datewillbesubstitu......
  • 怎么把word文件插入到公众号文章中
    怎么把word文件插入到公众号文章中呢?相信,这是很多公众号运营师经常会遇到的情境。因为,在日常的公众号运营中,他们经常需要在文章中添加一些附件,比如:登记表、申请表、报名表......
  • springboot内置tomcat配置本地文件夹的映射路径
    例如要访问的本地路径是D盘下的PersonalHomePage目录的某个图片1importorg.springframework.context.annotation.Configuration;2importorg.springframework.web.......
  • 如何单文件独立剪裁部署
    提出问题如何单文件独立剪裁部署解决问题dotnetpublish-cRelease-rwin-x64-p:PublishSingleFile=true-p:PublishTrimmed=true--self-containedtrue参考单文......