生成Minio工具starter
引言
- 我们之前编写了一个控制Minio的工具模块,主要实现了以下几个功能:
- 将链接配置写在了配置文件中,并编写一个类读取配置文件中的信息,并注册为一个Bean对象
- 将MinioClient初始化后注册为一个Bean
- 将Minio原生的方法进行封装
接下来,我们将尝试将这些功能剥离出来,并编写一个starter,以方便我们之后随时通过Maven引入这个starter,实现对Minio的控制
↓ 编写好的starter放在了下面的Git仓库中,虽然只是一个学习和测试的工具,可能很多地方还不够完善,但是欢迎大家访问
minio-mosfield-springboot-starter: Minio对象存储工具starter (gitee.com)
1.1. 结构及功能
- 与之前直接编写模块代码相比,编写成starter有什么变化?
starter依赖于SpringBoot的自动装配,SpringBoot项目在启动的时候,通过扫描各个依赖包中 META-INF/spring目录下的org.springframework.boot.autoconfigure.AutoConfiguration.imports文件,获取需要被加入Spring容器中的配置类。 所以,我们需要把我们的配置类的全路径名写在这个文件中。
↓ 关于自动装配的原理,可以参考这篇博客
目录结构
link
└─ xiaomo
└─ minio
└─ MinioAutoConfiguration
└─ MinioHelper
└─ MinioProperties
└─ MinioUtils
META-INF
└─ spring
└─ org.springframework.boot.autoconfigure.AutoConfiguration.imports
功能
- 操作桶相关(桶是否存在,新建桶,删除桶,获取所有桶,获取桶内对象信息)
- 对象操作:
- 上传到指定的桶的指定位置
- 下载指定桶内的指定文件
- 删除指定文件
- 获取文件的url
- 获取文件的二进制数组
- 工具
- 对图片附件进行压缩,可以按最大尺寸或按质量压缩
1.2. 使用说明
下面的内容为使用此starter的说明
1.2.1. 依赖
拉取到本starter项目后,需要在maven中编译本项目,并使用maven安装至本地仓库
安装后,使用本starter时需要引入如下依赖
<dependency>
<groupId>link.xiaomo</groupId>
<artifactId>minio-mosfield-springboot-starter</artifactId>
<version>0.1.1</version>
</dependency>
1.2.2. 填写配置文件
- 引入本starter后,在引入的项目中的配置文件里配置如下信息
- 此处以application.yml的格式为例
# minio相关配置
minio:
endpoint: http://IP:端口
bucketName: 默认桶名称
accessKey: 实际accessKey
secretKey: 实际secretKeyt
# 选填:上传文件大小限制
spring:
servlet:
multipart:
max-file-size: 100MB
max-request-size: 100MB
1.3. starter功能方法
1.3.1. 配置类MinioAutoConfiguration
这个类就是我们需要再org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中注册的类,会在Springboot启动的时候扫描到。
这个类主要实现了三个功能:
- 通过@EnableConfigurationProperties注解将MinioProperties类注册为Bean,这个Bean对象用于从配置文件中读取Minio配置信息
- 通过@Bean注解将Minio对象初始化并注册为Bean,它用于调用Minio的原生方法
- 通过@Bean注解将我们的业务类MinioHelper初始化,注入Minio对象和MinioProperties对象,也将其注册为Bean,方便我们随时使用这个业务类。
import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableConfigurationProperties(MinioProperties.class)
public class MinioAutoConfiguration {
@Autowired
private MinioProperties minioProperties;
@Bean
public MinioClient minioClient() {
return MinioClient.builder()
.endpoint(minioProperties.getEndpoint())
.credentials(minioProperties.getAccessKey(), minioProperties.getSecretKey())
.build();
}
@Bean
public MinioHelper minioHelper(@Autowired MinioClient minioClient) {
return new MinioHelper(minioClient, minioProperties);
}
}
1.3.2. MinioProperties
在这个类中,我们通过@ConfigurationProperties注解,从配置文件中读取 minio
下的配置信息
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "minio")
public class MinioProperties {
private String endpoint;
private String accessKey;
private String secretKey;
private String bucketName;
public String getEndpoint() {
return endpoint;
}
public void setEndpoint(String endpoint) {
this.endpoint = endpoint;
}
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;
}
}
1.3.3. MinioHelper类的方法
此starter的功能,主要是通过MinioHelper类中的方法实现,我们在这个类中对Minio的原生方法进行了封装,并对很多方法进行了重载,以方便我们在不同的情况下使用。具体的方法如下:
import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import org.apache.commons.compress.utils.IOUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
/**
* Minio业务实现类
*
* @Author Mosfield
*/
public class MinioHelper {
private final MinioClient minioClient;
private final MinioProperties minioProperties;
public MinioHelper(MinioClient minioClient, MinioProperties minioProperties) {
this.minioClient = minioClient;
this.minioProperties = minioProperties;
}
/**
* 查看bucket是否存在
*
* @param bucketName
* @return
*/
public Boolean bucketExists(String bucketName) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
}
/**
* 创建存储bucket
*
* @param bucketName
*/
public void makeBucket(String bucketName) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
}
/**
* 删除存储bucket
*
* @param bucketName
*/
public void removeBucket(String bucketName) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
}
/**
* 获取全部bucket
*
* @return
*/
public List<Bucket> listBuckets() throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
return minioClient.listBuckets();
}
/**
* 递归查看桶内的所有文件信息
*
* @return 存储bucket内文件对象信息
*/
public List<Item> listObjects() throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
return this.listObjects(null, null, true, null);
}
/**
* 列出某个存储桶中的所有对象。
*
* @param bucketName 存储桶名称
* @param prefix 对象名称的前缀
* @param recursive 是否递归查找,如果是false,就模拟文件夹结构查找
* @param useVersion1 如果是true, 使用版本1 REST API
* @return
*/
public List<Item> listObjects(String bucketName, String prefix, Boolean recursive, Boolean useVersion1) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
if (bucketName == null) {
bucketName = minioProperties.getBucketName();
}
if (recursive == null) {
recursive = false;
}
if (useVersion1 == null) {
useVersion1 = false;
}
ListObjectsArgs args = ListObjectsArgs.builder().
bucket(bucketName)
.prefix(prefix)
.recursive(recursive)
.useApiVersion1(useVersion1)
.build();
Iterable<Result<Item>> results = minioClient.listObjects(args);
List<Item> items = new ArrayList<>();
for (Result<Item> result : results) {
items.add(result.get());
}
return items;
}
/**
* 删除默认桶内的指定文件
*
* @param fileName
* @return
* @throws Exception
*/
public void remove(String fileName) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
this.remove(fileName, null);
}
/**
* 删除指定桶内的指定文件
*
* @param fileName
* @return
* @throws Exception
*/
public void remove(String fileName, String bucket) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
if (bucket == null) {
bucket = minioProperties.getBucketName();
}
RemoveObjectArgs args = RemoveObjectArgs.builder()
.bucket(bucket)
.object(fileName)
.build();
minioClient.removeObject(args);
}
/**
* 把文件上传到默认桶,名字为原名字
*
* @param file
* @return
*/
public String updateFileObject(MultipartFile file) {
return this.updateFileObject(file, null, null);
}
/**
* 把文件上传到默认桶
*
* @param file
* @param name 路径和新名字
* @return
*/
public String updateFileObject(MultipartFile file, String name) {
return this.updateFileObject(file, name, null);
}
/**
* 把文件上传到指定桶的指定路径下,桶名为空则上传到默认桶,路径为空则上传到桶的根目录
*
* @param file
* @param name
* @param bucket
* @return
*/
public String updateFileObject(MultipartFile file, String name, String bucket) {
// 桶默认值为配置文件中的默认桶
if (bucket == null || "".equals(bucket)) {
bucket = minioProperties.getBucketName();
}
// 名字默认为文件的原名
if (name == null || "".equals(name)) {
name = file.getOriginalFilename();
}
try {
//构建要上传文件对象的参数,如文件名、类型等
PutObjectArgs putObjectArgs = PutObjectArgs.builder().object(name).bucket(bucket).contentType(file.getContentType()).stream(file.getInputStream(), file.getSize(), -1).build();
//上传文件
minioClient.putObject(putObjectArgs);
return "ok";
} catch (Exception e) {
e.printStackTrace();
return e.getMessage();
}
}
/**
* 从默认的桶里下载文件
*
* @param fileName
* @return
*/
public InputStream downloadFileObject(String fileName) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
return this.downloadFileObject(fileName, null);
}
/**
* 从指定的桶里下载文件
*
* @param fileName
* @param bucket
* @return
*/
public InputStream downloadFileObject(String fileName, String bucket) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
if (bucket == null || "".equals(bucket)) {
bucket = minioProperties.getBucketName();
}
GetObjectArgs getObjectArgs = GetObjectArgs.builder()
.bucket(bucket)
.object(fileName)
.build();
return minioClient.getObject(getObjectArgs);
}
/**
* 获取文件的url
*
* @param fileName
* @return
*/
public String getPresignedObjectUrl(String fileName) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
return this.getPresignedObjectUrl(fileName, null);
}
/**
* 从指定的桶中获取文件的url
*
* @param fileName
* @return
*/
public String getPresignedObjectUrl(String fileName, String bucket) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
if (bucket == null || "".equals(bucket)) {
bucket = minioProperties.getBucketName();
}
GetPresignedObjectUrlArgs build = GetPresignedObjectUrlArgs.builder()
.bucket(bucket)
.object(fileName)
.method(Method.GET)
.build();
return minioClient.getPresignedObjectUrl(build);
}
/**
* 获取公开桶里文件的url
*
* @param name
* @return
*/
public String getPublicUrlByName(String name) {
return this.getPublicUrlByName(name, null);
}
/**
* 获取指定的公开桶里文件的url
*
* @param name
* @return
*/
public String getPublicUrlByName(String name, String bucket) {
if (bucket == null || "".equals(bucket)) {
bucket = minioProperties.getBucketName();
}
return minioProperties.getEndpoint() + "/" + bucket + "/" + name;
}
/**
* 根据图片路径和名字,获取默认桶内对应的二进制数组
*
* @param name
* @return
*/
public byte[] getByteArrByName(String name) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
return this.getByteArrByName(name, null);
}
/**
* 根据图片路径和名字,获取指定桶内对应的二进制数组
*
* @param name
* @param bucket
* @return
*/
public byte[] getByteArrByName(String name, String bucket) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
if (bucket == null || "".equals(bucket)) {
bucket = minioProperties.getBucketName();
}
if (name == null || "".equals(name)) {
return null;
}
InputStream inputStream = this.downloadFileObject(name, bucket);
if (inputStream == null) {
return null;
}
return IOUtils.toByteArray(inputStream);
}
}
1.3.4.MinioUtils工具类
目前工具类中提供了两个静态的工具方法 分别是 压缩图片
和 获取UUID文件路径名
,其中获取文件路径名的方法提供了两种参数形式。
import net.coobird.thumbnailator.Thumbnails;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.mock.web.MockMultipartFile;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class MinioUtils {
/**
* 压缩图片
*
* @param file 原始文件
* @param maxWidth 最大宽
* @param maxHeight 最大高
* @param quality 质量压缩比,范围是(0,1]
* @return
*/
private MultipartFile zipImg(MultipartFile file, Integer maxWidth, Integer maxHeight, Float quality) throws IOException {
String fileName = file.getName();
String originalFilename = file.getOriginalFilename();
String contentType = file.getContentType();
InputStream is = null;
// 通过MultipartFile得到InputStream,从而得到BufferedImage
BufferedImage bufferedImage = ImageIO.read(file.getInputStream());
// 获取图片的真实长和宽
int width = bufferedImage.getWidth();
int height = bufferedImage.getHeight();
if (maxWidth == null) {
maxWidth = width;
}
if (maxHeight == null) {
maxHeight = height;
}
// 计算图片的压缩比
float rate = 1f;
if (width > maxWidth) {
rate = 1f * maxWidth / width;
}
if (height > maxHeight && rate > 1f * maxHeight / height) {
rate = 1f * maxHeight / height;
}
// 质量压缩比
if(quality == null){
quality=1f;
}
is = file.getInputStream();
File tempFile = new File("/" + originalFilename);
Thumbnails.of(is)
.scale(rate)
.outputQuality(quality)
.toFile(tempFile);
FileInputStream fileInputStream = new FileInputStream(tempFile);
MockMultipartFile newFile = new MockMultipartFile(fileName, originalFilename, contentType, fileInputStream);
fileInputStream.close();
boolean success = tempFile.delete();
return newFile;
}
}
Comments NOTHING