对象存储之minIO-java框架springcloud封装minio-sdk为http接口

前言

由于项目需要,需要存储音频、图像等二进制文件,这些文件不能存放在数据库,之前使用Hbase做过音频存储,但是,hbase的api实在是太复杂了,不好使用

文件存储也有fastdfs,就是安装配置挺复杂的,后面在工作中发现了minio,这个软件比较好用,接下来,介绍一下我封装接口的过程

我这篇文章使用的框架是springcloud,首先需要了解springcloud后才能理解代码

mioIO简介

构建高性能的云原生数据
机器学习,大数据分析,海量存储的基础架构
MinIO支持各种应用程序数据工作负载
在中国:阿里巴巴、腾讯、百度、中国联通、华为、中国移动等等9000多家企业也都在使用MinIO产品

搭建测试服务

下载服务器,地址如下
http://www.minio.org.cn/
我下载的是win版本
使用如下命令启动

minio.exe server D:\usr\local

启动界面如下:
对象存储之minIO-java框架springcloud封装minio-sdk为http接口
minio的对象存储服务已经在9000启动了

JAVA代码封装minIO-API

引入java-sdk,在pom文件添加如下依赖

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

在这里我就只封装两个接口,一个下载接口和一个上传文件接口,创建minio配置类MinioConfig

@Data
@Component
@ConfigurationProperties(prefix = "minio")
public class MinioConfig {

    @ApiModelProperty("endPoint是一个URL,域名,IPv4或者IPv6地址")
    private String endpoint;

    @ApiModelProperty("端口号")
    private int port;

    @ApiModelProperty("accessKey类似于用户ID,唯一标识账户")
    private String accessKey;

    @ApiModelProperty("secretKey是账户密码")
    private String secretKey;

    @ApiModelProperty("如果是true,则用的是https而不是http,默认值是true")
    private Boolean secure;

    @ApiModelProperty("音频存储桶")
    private String voiceBucketName;

    @ApiModelProperty("url前缀")
    private String urlPrefix;

    @Bean
    public MinioClient getMinioClient() throws InvalidEndpointException, InvalidPortException {
        MinioClient minioClient = new MinioClient(endpoint, port, accessKey, secretKey, secure);
        return minioClient;
    }
}

bootstrap.properties配置如下:

# minio配置
minio.endpoint=localhost
minio.port=9000
minio.accessKey=minioadmin
minio.secretKey=minioadmin
minio.secure=false
minio.voiceBucketName=voice-file
minio.urlPrefix=www.ooo.cn/pro

编写一个service接口

import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;

public interface MinioService {


    /**
     * 判断 bucket是否存在
     *
     * @param bucketName
     * @return
     */
    boolean bucketExists(String bucketName);

    /**
     * 创建 bucket
     *
     * @param bucketName
     */
    void makeBucket(String bucketName);

    /**
     * 文件上传
     *
     * @param multipartFile
     */
    String uploadFile(MultipartFile multipartFile);

    /**
     * 删除文件
     * @param objectName
     */
    boolean deleteFile(String objectName);

    /**
     * 下载文件
     * @param fileName
     * @param originalName
     * @param response
     */
    void downloadFile(String originalName, String fileName, HttpServletResponse response);

    /**
     * 获取文件路径
     * @param objectName
     * @return
     */
    String getFileUrl(String objectName);


    /**
     * 获取文件流
     * @param objectName
     * @return
     */
    InputStream getInputStreamByObjectName(String objectName);


}

编写接口实现类

mport com.ifly.assi.config.MinioConfig;
import com.ifly.assi.service.impl.MinioService;
import io.minio.MinioClient;
import io.minio.PutObjectOptions;
import io.minio.errors.ErrorResponseException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;


@Service
@Slf4j
public class MinioServiceImpl implements MinioService {

    @Autowired
    private MinioConfig minioConfig;
    @Autowired
    private MinioClient minioClient;

    /**
     * 判断 bucket是否存在
     * @param bucketName
     * @return
     */
    @Override
    public boolean bucketExists(String bucketName) {
        boolean flag = false;
        try {
            flag = minioClient.bucketExists(bucketName);
            if (flag) {
                return true;
            }
        } catch (Exception e){
            log.error("查询bucket = {}是否存在出错", bucketName, e);
        }

        return false;
    }

    /**
     * 创建 bucket
     * @param bucketName
     */
    @Override
    public void makeBucket(String bucketName) {
        boolean flag = bucketExists(bucketName);
        try {
            if (!flag) {
                minioClient.makeBucket(bucketName);
            }
        } catch (Exception e){
            log.error("创建bucket = {}出错", bucketName, e);
        }

    }

    /**
     * 上传文件
     * @param multipartFile
     * @return 文件路径
     */
    @Override
    public String uploadFile(MultipartFile multipartFile) {
        // 按日期生成文件目录,用uuid重新生成文件名
        String fileName = multipartFile.getOriginalFilename();
        String objName = getObjectNameByFileName(fileName);
        PutObjectOptions putObjectOptions = new PutObjectOptions(multipartFile.getSize(), PutObjectOptions.MIN_MULTIPART_SIZE);
        putObjectOptions.setContentType(multipartFile.getContentType());
        try {
            minioClient.putObject(minioConfig.getVoiceBucketName(), objName, multipartFile.getInputStream(), putObjectOptions);
        } catch (Exception e){
            log.error("上传文件{}出错", fileName, e);
        }
        return objName;
    }

    private String getObjectNameByFileName(String fileName) {
        if (StringUtils.isBlank(fileName)) {
            return "";
        }
        String dateFormat = new SimpleDateFormat("yyyy/MM/dd/").format(new Date());
        String uuid = UUID.randomUUID().toString().replace("-", "");
        String fileType = fileName.substring(fileName.lastIndexOf("."));
        String objName = dateFormat + uuid + fileType;
        return objName;
    }

    /**
     * 删除文件
     * @param objectName
     */
    @Override
    public boolean deleteFile(String objectName) {
        boolean flag = bucketExists(minioConfig.getVoiceBucketName());
        if (flag) {
            try {
                minioClient.removeObject(minioConfig.getVoiceBucketName(), objectName);
            }catch (Exception e){
                log.error("删除文件objectName = {},出错", objectName, e);
            }
            return true;
        }
        return false;
    }

    /**
     * 下载文件
     * @param objectName 存储对象名
     * @param fileName 下载时显示的文件名
     * @param response
     */
    @Override
    public void downloadFile(String objectName, String fileName, HttpServletResponse response) {
        try {
            InputStream file = minioClient.getObject(minioConfig.getVoiceBucketName(), objectName);
            String filename = new String(fileName.getBytes("ISO8859-1"), StandardCharsets.UTF_8);
            response.setHeader("Content-Disposition", "attachment;filename=" + filename);
            ServletOutputStream servletOutputStream = response.getOutputStream();
            int len;
            byte[] buffer = new byte[1024];
            while ((len = file.read(buffer)) > 0) {
                servletOutputStream.write(buffer, 0, len);
            }
            servletOutputStream.flush();
            file.close();
            servletOutputStream.close();
        } catch (ErrorResponseException e) {
            log.error("下载文件{}出错", fileName, e);
        } catch (Exception e) {
            log.error("下载文件{}出错", fileName, e);
        }
    }

    /**
     * 获取文件路径
     * @param objectName
     * @return
     */
    @Override
    public String getFileUrl(String objectName) {
        boolean flag = bucketExists(minioConfig.getVoiceBucketName());
        String url = "";
        if (flag) {
            try {
                url = minioClient.getObjectUrl(minioConfig.getVoiceBucketName(), objectName);
            } catch (Exception e){
                log.error("获取文件{}路径出错", objectName, e);
            }
        }
        return url;
    }

    @Override
    public InputStream getInputStreamByObjectName(String objectName) {
        InputStream inputStream = null;
        try {
             inputStream = minioClient.getObject(minioConfig.getVoiceBucketName(), objectName);
        } catch (Exception e) {
            log.error("获取文件流出错", e);
        }
        return inputStream;
    }

}

新建MinioController

import com.ifly.assi.dto.DataResult;
import com.ifly.assi.service.impl.MinioService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;

@RequestMapping("/minio")
@RestController
@Api(tags = "Minio文件服务")
@Slf4j
public class MinioController {

    @Autowired
    private MinioService minioService;

    @Autowired
    private HttpServletResponse response;

    @ApiOperation(value = "上传文件")
    @PostMapping("/uploadFile")
    @ApiImplicitParams({
            @ApiImplicitParam(dataType = "MultipartFile", name = "file", value = "上传的文件", required = true)
    })
    public DataResult uploadFile(MultipartFile file) {
        String fileName = file.getOriginalFilename();
        try {
            String objectName = minioService.uploadFile(file);
            return new DataResult(objectName);
        } catch (Exception e) {
            log.error("上传文件fileName = {}出错", fileName, e);
            return DataResult.fail("上传失败");
        }
    }

    @GetMapping("/downloadFile")
    @ApiOperation(value = "下载文件")
    public void downloadFile(String objectName, String fileName) {
        minioService.downloadFile(objectName, fileName, response);
    }
}

因为我的项目里面用到了swagger,因此接口上面有一些swagger的注解,如@ApiOperation、@Api,自己测试的话就可以删除

到这里封装minio-sdk已经完成了,可以开始测试了

结果

上传文件接口
对象存储之minIO-java框架springcloud封装minio-sdk为http接口
下载接口就不截图了。如果喜欢就请点关注

上一篇:【性能优化】小伙伴问我性能指标监控怎么做,这次我安排上了!!


下一篇:JavaScript 对象(学习笔记)