前言
由于项目需要,需要存储音频、图像等二进制文件,这些文件不能存放在数据库,之前使用Hbase做过音频存储,但是,hbase的api实在是太复杂了,不好使用
文件存储也有fastdfs,就是安装配置挺复杂的,后面在工作中发现了minio,这个软件比较好用,接下来,介绍一下我封装接口的过程
我这篇文章使用的框架是springcloud,首先需要了解springcloud后才能理解代码
mioIO简介
构建高性能的云原生数据
机器学习,大数据分析,海量存储的基础架构
MinIO支持各种应用程序数据工作负载
在中国:阿里巴巴、腾讯、百度、中国联通、华为、中国移动等等9000多家企业也都在使用MinIO产品
搭建测试服务
下载服务器,地址如下
http://www.minio.org.cn/
我下载的是win版本
使用如下命令启动
minio.exe server D:\usr\local
启动界面如下:
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已经完成了,可以开始测试了
结果
上传文件接口
下载接口就不截图了。如果喜欢就请点关注