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