1.maven依赖

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

2.application.yml

minio:
  url: http://localhost:9000
  accessKey: minioadmin
  secretKey: minio123
  bucketName: test

3.创建配置属性类MinioPropertes

@Component
// 这里的minio与上面的配置文件种的对应
@ConfigurationProperties(prefix = "minio")
public class MinioPropertes {

    /**
     * 外网访问服务地址
     */
    private String url;

    /**
     * 用户名
     */
    private String accessKey;

    /**
     * 密码
     */
    private String secretKey;
    /**
     * 桶名称
     */
    private String bucketName;

    /**
     * 预览到期时间(小时)
     */
    private Integer previewExpiry;

    public Integer getPreviewExpiry() {
        return previewExpiry;
    }

    public void setPreviewExpiry(Integer previewExpiry) {
        this.previewExpiry = previewExpiry;
    }

    public String getUrl() {
        return url;
    }

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

    public String getAccessKey() {
        return accessKey;
    }

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

    public String getSecretKey() {
        return secretKey;
    }

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

    public String getBucketName() {
        return bucketName;
    }

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

4.minio配置类

@Configuration
public class MinioConfig {

    @Autowired
    private MinioPropertes minioPropertes;

    @Bean
    public MinioClient minioClient() {
        return MinioClient.builder()
                .endpoint(minioPropertes.getUrl())
                .credentials(minioPropertes.getAccessKey(), minioPropertes.getSecretKey())
                .build();
    }
}

5.写接口

public interface MinioService {

    /**
     * 上传文件
     * @param file
     */
    void uploadFile(MultipartFile file) throws Exception;
    
    void downloadFile(String filePath, HttpServletResponse response) throws Exception;

    String getPreviewUrl(String fileName);
}

6.接口实现

@Service
public class MinioServiceImpl implements MinioService{
    @Autowired
    private MinioPropertes minioPropertes;

    @Autowired
    private MinioClient minioClient;

    @Override
    public void uploadFile(MultipartFile file) throws Exception {
        // 存入minio
        minioClient.putObject(PutObjectArgs.builder()
                .bucket(minioPropertes.getBucketName())
                .object("2023/10/01/" + file.getOriginalFilename())
                .stream(file.getInputStream(), -1, 10485760)
                .contentType(file.getContentType())
                .build());
    }

    /**
     * 从minio下载文件,直接通过response传输
     */
    public void downloadFile(String filePath, HttpServletResponse response) throws Exception {

        try (InputStream is = getObject(minioPropertes.getBucketName(), filePath);
             BufferedInputStream bis = new BufferedInputStream(is);
             OutputStream os = response.getOutputStream()) {
            //try {
            response.setContentType("application/force-download;charset=utf-8");// 设置强制下载而不是直接打开
            response.addHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(filePath, "UTF-8"));// 设置文件名
            byte[] buffer = new byte[1024 * 1024 * 1024]; //buffer 1M
            int offset = bis.read(buffer);
            while (offset != -1) {
                os.write(buffer, 0, offset);
                offset = bis.read(buffer);
            }
            os.flush();
        } catch (Exception e) {
            throw new RuntimeException("下载文件失败", e);
        }
    }

    @Override
    public String getPreviewUrl(String fileName) {
        if (StringUtils.isNotBlank(fileName)) {
            try {
                minioClient.statObject(StatObjectArgs.builder().bucket(minioPropertes.getBucketName()).object(fileName).build());
                if (null != minioPropertes.getPreviewExpiry()){
                    return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(minioPropertes.getBucketName()).object(fileName).expiry(minioPropertes.getPreviewExpiry(), TimeUnit.HOURS).build());
                }else {
                    return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(minioPropertes.getBucketName()).object(fileName).build());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 从bucket获取指定对象的输入流,后续可使用输入流读取对象
     * getObject与minio server连接默认保持5分钟,
     * 每隔15s由minio server向客户端发送keep-alive check,5分钟后由客户端主动发起关闭连接
     */
    public InputStream getObject(String bucketName, String objectName) throws Exception {
        GetObjectArgs args = GetObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .build();
        return minioClient.getObject(args);
    }
}

7.控制器使用

@RestController
@RequestMapping("/file")
public class MinioController {

    @Autowired
    private MinioService minioService;

    @PostMapping("/upload")
    public String uploadFile(@RequestParam("file") MultipartFile multipartFile) throws Exception {
        minioService.uploadFile(multipartFile);
        return "ok";
    }

    /**
     * 文件下载请求
     */
    @GetMapping("downloadFile")
    public void downloadFile(String filePath, HttpServletResponse response) {
        try {
            minioService.downloadFile(filePath, response);
        } catch (Exception e) {
            System.out.println(e);
        }
    }

    /**
     * 文件下载请求
     */
    @GetMapping("preview")
    public String preview(String filePath, HttpServletResponse response) {
        try {
            return minioService.getPreviewUrl(filePath);
        } catch (Exception e) {
            System.out.println(e);
            return null;
        }
    }
}