SpringBoot整合Minio(实现上传与下载)

什么是MinIO?

MinIO 是一款高性能、分布式的对象存储系统. 它是一款软件产品, 可以100%的运行在标准硬件。即X86等低成本机器也能够很好的运行MinIO。

根据minio依赖实现文件上传下载

1.导入环境所需要的依赖
    
    org.springframework.boot
        spring-boot-starter-parent
        2.6.3
     
         
            org.springframework.boot
            spring-boot-starter-web
        
    
        
            io.minio
            minio
            8.2.2
        
        
            org.projectlombok
            lombok
            true
        
        
            com.alibaba.fastjson2
            fastjson2
            2.0.26
        

        
            javax.servlet
            javax.servlet-api
            3.1.0
            provided
        
2.application.yml中进行minio的配置
minio:
  endpoint: http://192.168.233.123:9000 #Minio服务所在地址
  accessKey: minioadmin                 #连接Minio用户名
  secretKey: minioadmin                 #连接Minio密码
  bucketName: testadmin                 #Minio数据桶名称
3.MinIoConfig.class 配置类 

此类主要做一些连接Minio实例化对象的配置

import io.minio.MinioClient;
import lombok.Data;
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;

/**
 * @author: yujie.li
 * @description
 * @date 2023/7/18
 */
@Data
@Configuration
@ConfigurationProperties(prefix = "minio")
public class MinIoConfig {

    /**
     * 访问密钥
     */
    @Value("${minio.accessKey}")
    private String accessKey;

    /**
     * 密钥
     */
    @Value("${minio.secretKey}")
    private String secretKey;

    /**
     * 访问api Url
     */
    @Value("${minio.endpoint}")
    private String endpoint;

    /**
     * 捅名称
     */
    @Value("${minio.bucketName}")
    private String bucketName;

    /**
     * 创建MinIo客户端
     *
     * @return
     */
    @Bean
    public MinioClient minioClient() {

        return MinioClient.builder()
                .endpoint(endpoint)
                .credentials(accessKey, secretKey)
                .build();
    }

}
 4.AjaxResult.class 实体类

此类对数据结果进行封装,返回报文

import java.util.HashMap;

/**
 * 数据结果封装体 AjaxResult
 *
 * @author yujie.li
 */
public class AjaxResult extends HashMap
{
    private static final long serialVersionUID = 1L;

    /** 状态码 */
    public static final String CODE_TAG = "code";

    /** 返回内容 */
    public static final String MSG_TAG = "msg";

    /** 数据对象 */
    public static final String DATA_TAG = "data";

    /**
     * 初始化一个AjaxResult 对象
     */
    public AjaxResult()
    {
    }

    /**
     * 初始化一个AjaxResult 对象
     *
     * @param code 状态码
     * @param msg 返回内容
     */
    public AjaxResult(int code, String msg)
    {
        super.put(CODE_TAG, code);
        super.put(MSG_TAG, msg);
    }

    /**
     * 初始化一个AjaxResult 对象
     *
     * @param code 状态码
     * @param msg 返回内容
     * @param data 数据对象
     */
    public AjaxResult(int code, String msg, Object data)
    {
        super.put(CODE_TAG, code);
        super.put(MSG_TAG, msg);
        if (!(data == null))
        {
            super.put(DATA_TAG, data);
        }
    }

    /**
     * 返回默认成功消息
     *
     * @return 成功消息
     */
    public static AjaxResult success()
    {
        return AjaxResult.success("操作成功");
    }

    /**
     * 返回成功消息
     *
     * @param msg 返回内容
     * @return 成功消息
     */
    public static AjaxResult success(String msg)
    {
        return AjaxResult.success(msg, null);
    }

    /**
     * 返回成功数据
     * @param data 数据对象
     * @return
     */
    public static AjaxResult success(Object data)
    {
        return AjaxResult.success("操作成功", data);
    }

    /**
     * 初始化一个返回成功消息AjaxResult对象
     *
     * @param msg 返回内容
     * @param data 数据对象
     * @return 成功消息
     */
    public static AjaxResult success(String msg, Object data)
    {
        return new AjaxResult(HttpStatus.SUCCESS, msg, data);
    }

    /**
     * 返回默认错误消息
     *
     * @return
     */
    public static AjaxResult error()
    {
        return AjaxResult.error("操作失败");
    }

    /**
     * 返回错误消息
     *
     * @param msg 返回内容
     * @return 警告消息
     */
    public static AjaxResult error(String msg)
    {
        return AjaxResult.error(msg, null);
    }

    /**
     * 返回错误数据
     *
     * @param code 状态码
     * @param msg 返回内容
     * @return 警告消息
     */
    public static AjaxResult error(int code, String msg)
    {
        return new AjaxResult(code, msg, null);
    }

    /**
     * 初始化一个返回错误消息AjaxResult对象
     *
     * @param msg 返回内容
     * @param data 数据对象
     * @return 警告消息
     */
    public static AjaxResult error(String msg, Object data)
    {
        return new AjaxResult(HttpStatus.ERROR, msg, data);
    }

}
 5.HttpStatus.class 实体类

此类对返回Http状态码进行封装

/**
 * 返回HTTP状态码
 *
 * @author yujie.li
 */
public class HttpStatus {
    /**
     * 操作成功
     */
    public static final int SUCCESS = 200;

    /**
     * 对象创建成功
     */
    public static final int CREATED = 201;

    /**
     * 请求已经被接受
     */
    public static final int ACCEPTED = 202;

    /**
     * 操作已经执行成功,但是没有返回数据
     */
    public static final int NO_CONTENT = 204;

    /**
     * 资源已被移除
     */
    public static final int MOVED_PERM = 301;

    /**
     * 重定向
     */
    public static final int SEE_OTHER = 303;

    /**
     * 资源未被修改
     */
    public static final int NOT_MODIFIED = 304;

    /**
     * 参数列表错误(缺少、格式不匹配)
     */
    public static final int BAD_REQUEST = 400;

    /**
     * 未授权
     */
    public static final int UNAUTHORIZED = 401;

    /**
     * 访问受限,授权过期
     */
    public static final int FORBIDDEN = 403;

    /**
     * 资源,服务未找到
     */
    public static final int NOT_FOUND = 404;

    /**
     * 未被允许http方法
     */
    public static final int BAD_METHOD = 405;

    /**
     * 资源冲突,或者资源被锁
     */
    public static final int CONFLICT = 409;

    /**
     * 不支持媒体类型数据
     */
    public static final int UNSUPPORTED_TYPE = 415;

    /**
     * 系统内部错误
     */
    public static final int ERROR = 500;

    /**
     * 未实现相应接口
     */
    public static final int NOT_IMPLEMENTED = 501;
}
6. ServletUtils.class 配置类

此类返回 JSON 数据的方法

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class ServletUtils {

    public static void renderString(HttpServletResponse response, String json) throws IOException {
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");

        try (PrintWriter writer = response.getWriter()) {
            writer.write(json);
            writer.flush();
        }
    }
}
7.MinIoUtil.class 工具类

 此工具类中包含上传与下载的方法

import io.minio.GetObjectArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.errors.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author: yujie.li
 * @description
 * @date 2023/7/18
 */
@Component
public class MinIOUtil {
    @Autowired
    private MinioClient minioClient;
    /**
     * 捅名称
     */
    @Value("${minio.bucketName}")
    private String bucketName;

    /**
     * putObject上传文件
     *
     * @param file 文件
     * @return filePath
     */
    public String putObject(MultipartFile file) throws IOException, ServerException, InsufficientDataException, InternalException, InvalidResponseException, InvalidKeyException, NoSuchAlgorithmException, XmlParserException, ErrorResponseException {
        //文件名
        String originalFilename = file.getOriginalFilename();
        //文件流
        InputStream inputStream = file.getInputStream();
        //文件大小
        long size = file.getSize();
        //文件路径
        String filePath = createFilePath(originalFilename);
        System.out.println(filePath+"\t文件路径");
        //存储方法 putObject
        minioClient.putObject(PutObjectArgs.builder()
                .bucket(bucketName)
                .object(filePath)
                .stream(inputStream, size, -1)
                .contentType(file.getContentType())
                .build());
        return filePath;
    }

    /**
     * 下载文件
     *
     * @param filePath 文件路径
     */
    public void getObject(HttpServletResponse httpServletResponse, String filePath) throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, ErrorResponseException {
        String fileName = getFileName(filePath);
        InputStream inputStream = minioClient.getObject(GetObjectArgs.builder()
                .bucket(bucketName)
                .object(filePath)
                .build());
        downloadFile(httpServletResponse, inputStream, fileName);
    }

    /**
     * 获取文件路径
     *
     * @param originalFilename 原始文件名称
     * @return FilePath
     */
    public String createFilePath(String originalFilename) {
        return new SimpleDateFormat("yyyy/MM/dd").format(new Date()) + "/" + originalFilename;
    }

    /**
     * 根据文件路径获取文件名称
     *
     * @param filePath 文件路径
     * @return 文件名
     */
    public String getFileName(String filePath) {
        String[] split = StringUtils.split(filePath, "/");
        return split[split.length - 1];
    }

    /**
     * 下载文件
     *
     * @param httpServletResponse httpServletResponse
     * @param inputStream         inputStream
     * @param fileName            文件名
     * @throws IOException IOException
     */
    public void downloadFile(HttpServletResponse httpServletResponse, InputStream inputStream, String fileName) throws IOException {
        //设置响应头信息,告诉前端浏览器下载文件
        httpServletResponse.setContentType("application/octet-stream;charset=UTF-8");
        httpServletResponse.setCharacterEncoding("UTF-8");
        httpServletResponse.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
        //获取输出流进行写入数据
        OutputStream outputStream = httpServletResponse.getOutputStream();
        // 将输入流复制到输出流
        byte[] buffer = new byte[4096];
        int bytesRead = -1;
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, bytesRead);
        }
        // 关闭流资源
        inputStream.close();
        outputStream.close();
    }
}
8. MinioController.class 控制类
import com.alibaba.fastjson2.JSON;
import com.lyj.msg.AjaxResult;
import com.lyj.msg.HttpStatus;
import com.lyj.utils.MinIOUtil;
import com.lyj.utils.ServletUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author yujie.li
 * @description
 * @date 2023/7/18
 */
@RestController
@Slf4j
public class MinioController {
    @Autowired
    private MinIOUtil minioUtil;

    @PostMapping("/upload")
    public AjaxResult upload(@RequestPart MultipartFile file) {
        String filePath;
        try {
            filePath = minioUtil.putObject(file);
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("上传失败");
        }
        return AjaxResult.success(filePath);
    }

    @GetMapping("/download")
    public void download(HttpServletResponse response, @RequestParam(value = "filepath") String filepath) throws IOException {
        try {
            minioUtil.getObject(response, filepath);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("下载失败", e);
            response.reset();
            AjaxResult result = new AjaxResult(HttpStatus.ERROR, e.getMessage());
            String json = JSON.toJSONString(result);
            ServletUtils.renderString(response, json);
        }
    }
}
ps.遇到的坑

1.需要将自己所创建的Buckets桶权限设置为public

2.桶的名称需要与yml配置类中bucketName一致

SpringBoot整合Minio(实现上传与下载)_第1张图片

3. 测试下载接口时,传递的参数值为桶中的文件路径即可,不需要在加桶的名称,例如(testadmin/1.png)

SpringBoot整合Minio(实现上传与下载)_第2张图片

尾注:每一行代码 都是改变世界的能量 愿你每一次的运行 都是发自内心的快乐

你可能感兴趣的:(spring,boot,后端,java)