前面说了下minio的安装和配置,这次,我们来看看怎么和springboot进行集成使用。
首先说一下版本:
Springboot版本:2.2.5.RELEASE
minio版本:8.x
官方文档:https://docs.min.io/docs/java-client-quickstart-guide.html
依赖
添加依赖,官方给出的版本是8.3.0,但是用这个版本后会报错:
然后我们将版本稍微降低下:
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.2.1</version>
</dependency>
创建minioClient对象
由官方的文档可以看出,创建minioClient的方式有很多种。
要的参数无非就是:
- url ip地址
- port 端口号
- access key 用户名
- secret key 密码
- bucketName 桶名称
- userSSL 是否使用ssl
那我们首先就创建一个MinioClientProp文件,把这些参数写在配置文件中,然后通过参数注入的方式来加载参数:
@Configuration
@ConfigurationProperties("bearweb.minio")
@Slf4j
@Data
public class MinioClientProp implements InitializingBean {
private String url;
private Integer port;
private String accessKey;
private String secretKey;
private Boolean userSSL;
private String bucketName;
@Bean
public MinioClient minioClient() {
MinioClient minioClient;
try {
// 创建minioClient
minioClient = MinioClient.builder().endpoint(url, port, userSSL).credentials(accessKey, secretKey).build();
// 判断是否存在桶,不存在则创建桶
boolean hasBucket = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
if (!hasBucket) {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
}
} catch (Exception e) {
log.error(e.getMessage());
throw new RuntimeException("minioClient初始化失败");
}
return minioClient;
}
@Override
public void afterPropertiesSet() throws Exception {
log.info("-------minio初始化完成---------");
}
}
yaml中的配置文件如下:
spring:
minio:
url: 192.168.0.3
port: 9002
accessKey: 用户名
secretKey: 密码
userSSL: false
bucketName: bearweb
当项目启动没有问题,就说明配置没有问题,如果启动报错,ip或者端口或者用户名密码错误,需要按照按照启动的配置填写正确后可启动正常。
封装自己常用的工具类
官方地址:https://docs.min.io/docs/java-client-api-reference.html
其实官方地址已经给出了操作文档和demo,我们只需要按照自己的需要封装即可:
@Component
@Slf4j
public class MinioOpsUtil {
@Autowired
private MinioClientProp minioClientConfig;
@Autowired
private MinioClient minioClient;
public StatObjectResponse getFileInfo(String objectName, String bucketName){
try {
if (StringUtils.isBlank(bucketName)){
bucketName = minioClientConfig.getBucketName();
} else {
throw new Exception("操作失败!桶不存在!");
}
return minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
} catch (Exception e) {
return null;
}
}
public void download(String objectName, String bucketName, String fileName, HttpServletResponse response) throws Exception{
if (StringUtils.isNotBlank(bucketName)){
if (!this.bucketExists(bucketName)){
throw new Exception("操作失败!桶不存在!");
}
} else {
bucketName = minioClientConfig.getBucketName();
}
InputStream stream = minioClient.getObject(GetObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.build());
response.setContentType("application/force-download");
response.setHeader("Content-Disposition", "attachment;filename="+ fileName);
response.setCharacterEncoding("UTF-8");
IOUtils.copy(stream, response.getOutputStream());
}
/**
* 上传单个文件到指定的桶
* @param file MultipartFile
* @param bucketName 桶名称,如果不存在,则系统配置的桶
* @throws Exception
*/
public String upload(MultipartFile file, String bucketName) throws Exception{
// 判断是否传入桶名称
if (StringUtils.isNotBlank(bucketName)){
if (!this.bucketExists(bucketName)){
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
}
} else {
bucketName = minioClientConfig.getBucketName();
}
// 获取原始,名称
String fileName = file.getOriginalFilename();
// 截取新的名称
String objectName = UUID.randomUUID().toString().replaceAll("-", "") +
fileName.substring(fileName.lastIndexOf("."), fileName.length());
// 日期前缀
String folderPrefix = this.timeFolder();
objectName = folderPrefix + "/" +objectName;
// 上传
minioClient.putObject(PutObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.stream(file.getInputStream(), file.getSize(), -1)
.contentType(file.getContentType())
.build());
String url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs
.builder().method(Method.GET).bucket(bucketName).object(objectName).build());
// 原始路径为 ip:port/bucketName/objectName?minio自带参数
// 截取后只保留 ip:port/bucketName/objectName
url = url.split("\\?")[0];
return url;
}
/**
* 上传多个文件到系统配置的桶
* @param files MultipartFile
* @param bucketName 桶名称,如果不存在,则系统配置的桶
* @throws Exception
*/
public List<String> uploadBatch(MultipartFile[] files, String bucketName) throws Exception{
// 判断是否传入桶名称
if (StringUtils.isNotBlank(bucketName)){
if (!this.bucketExists(bucketName)){
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
}
} else {
bucketName = minioClientConfig.getBucketName();
}
String finalBucketName = bucketName;
List<String> urlList = Collections.synchronizedList(new ArrayList<>());
Arrays.asList(files).parallelStream().forEach(file -> {
try {
String filePath = this.upload(file, finalBucketName);
urlList.add(filePath);
} catch (Exception e) {
log.info("文件上传失败,文件名:{}",file.getOriginalFilename());
throw new RuntimeException("文件上传失败", e);
}
});
return urlList;
}
/**
* 从指定的桶删除文件
* @param objectName 文件名称
* @param bucketName 桶名称,如果不存在,则系统配置的桶
* @throws Exception
*/
public void delete(String objectName, String bucketName) throws Exception{
// 判断是否传入桶名称
if (StringUtils.isBlank(bucketName)){
bucketName = minioClientConfig.getBucketName();
} else {
if (!this.bucketExists(bucketName)){
throw new Exception("操作失败!桶不存在!");
}
}
minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());
}
/**
* 批量从指定的桶删除文件
* @param objectNames 文件名称
* @param bucketName 桶名称,如果不存在,则系统配置的桶
* @throws Exception
*/
public void deleteBatch(String[] objectNames, String bucketName) throws Exception{
// 判断是否传入桶名称
if (StringUtils.isBlank(bucketName)){
bucketName = minioClientConfig.getBucketName();
} else {
if (!this.bucketExists(bucketName)){
throw new Exception("操作失败!桶不存在!");
}
}
String finalBucketName = bucketName;
Arrays.stream(objectNames).parallel().forEach(objectName ->{
try {
minioClient.removeObject(RemoveObjectArgs.builder().bucket(finalBucketName).object(objectName).build());
} catch (Exception e) {
log.info("文件删除失败,文件名:{}", objectName);
throw new RuntimeException("文件上传失败", e);
}
});
}
/**
* 获取当前时间转换成字符串
* @return
*/
private String timeFolder(){
LocalDate time = LocalDate.now();
String format = time.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
return format;
}
/**
* 判断是否存在传入的桶,不存在创建
* @param bucketName
* @throws IOException
* @throws InvalidKeyException
* @throws InvalidResponseException
* @throws InsufficientDataException
* @throws NoSuchAlgorithmException
* @throws ServerException
* @throws InternalException
* @throws XmlParserException
* @throws ErrorResponseException
*/
private Boolean bucketExists(String bucketName) throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException,
NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, ErrorResponseException {
boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
return found;
}
}
测试
首先控制台是没有今天的数据的:
首先是文件的上传,由于我们没有指定桶,默认上传到系统配置文件配置的桶里面:
@Autowired
private MinioOpsUtil minioOpsUtil;
@PostMapping("/uploadUserPicture")
public CommonResult uploadUserPicture(@RequestParam("file") MultipartFile file) throws Exception {
String filePath = minioOpsUtil.upload(file, null);
return CommonResult.success(filePath);
}
这个就是刚才上传的文件:
其他我也不演示了,应该没啥问题。
小弟我也是第一次接触minio,如有纰漏,欢迎各位大佬指出。
评论区