一、首先配置MinIO
1、MinIO新建Bucket,访问控制台如图
创建访问密钥(就是账号和密码)
二、集成mino添加Minio客户端依赖
1.maven构建方式在pom.xml引入jar
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.4.3</version>
</dependency>
2.配置Minio连接参数
Springoot配置文件yaml添加minio配置Minio连接参数:
# minio 参数配置
minio:
#是否启用 默认值是true
enabled: true
#是否https ,#如果是true,则用的是https而不是http,默认值是false
secure: false
#文件预览地址 由于我们的MinIO服务运行在9001端口上
preview: http://127.0.0.1:9001
#Minio服务器地址
endpoint: http://127.0.0.1:9001
# 默认存储桶
bucket-name:
#登录账号
access-key: MKBgpZsb7WoLFEUTeR8y
#登录密码
secret-key: VpONfVhjGtPOUd26yPrm3ZskvuPLF4QGSTMtWRLE
(endpoint, access key, secret key,bucket name)主要是就是四个个参数,其他是因为业务需要加的参数
三、编写服务类,实现文件上传、下载等方法
1.创建配置类,初始化MinioClient Bean
import io.minio.MinioClient;
import lombok.Data;
import okhttp3.OkHttpClient;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
@ConfigurationProperties(prefix = "oss.minio")
@Configuration
@Data
public class MinioConfig {
/**
* 服务地址
*/
private String endpoint;
/**
* 文件预览地址
*/
private String preview;
/**
* 存储桶名称
*/
private String bucketName;
/**
* 用户名
*/
private String accessKey;
/**
* 密码
*/
private String secretKey;
/**
* 是否https ,是:true 不是:false
*/
private Boolean secure;
/**
* 初始化客户端,获取 MinioClient
*/
@Bean
public MinioClient minioClient() throws NoSuchAlgorithmException, KeyManagementException {
MinioClient.Builder minioClient = MinioClient.builder()
.endpoint(endpoint)
.credentials(accessKey, secretKey);
//是否https,如果是取消ssl认证
if (secure) {
final TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) {
}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
}
};
X509TrustManager x509TrustManager = (X509TrustManager) trustAllCerts[0];
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new SecureRandom());
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.sslSocketFactory(sslSocketFactory, x509TrustManager);
builder.hostnameVerifier((s, sslSession) -> true);
OkHttpClient okHttpClient = builder.build();
minioClient.httpClient(okHttpClient).region("eu-west-1");
}
return minioClient.build();
}
}
2.文件上传接口
package priv.cl.oss.service;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
/**
* @ClassName MinioFileStorageService
* @Description MinioFileStorageService
* @Author cl
* @Date 2025/2/22 16:40
*/
public interface MinIOFileStorageService {
/**
* 上传图片文件
*
* @param prefix 文件前缀
* @param filename 文件名
* @param inputStream 文件流
* @return 文件url
*/
String uploadImgFile(String prefix, String filename, InputStream inputStream);
/**
* 上传html文件
*
* @param prefix 文件前缀
* @param filename 文件名
* @param inputStream 文件流
* @return 文件url
*/
String uploadHtmlFile(String prefix, String filename, InputStream inputStream);
/**
* 上传文件不分类型
*
* @param prefix 文件前缀
* @param filename 文件名
* @param multipartFile 文件
* @return 文件url
*/
String uploadFileByMultipartFile(String prefix, String filename, MultipartFile multipartFile);
/**
* 上传本地文件
*
* @param prefix 文件前缀
* @param objectName 对象名称
* @param fileName 本地文件路径
*/
String uploadFile(String prefix, String objectName, String fileName);
/**
* 下载文件url到本地指定路径
*
* @param fileUrl 文件url
* @param templatePath 指定路径文件夹
* @return path 本地文件全路径
*/
String downloadFile(String fileUrl, String templatePath);
/**
* 下载文件
*
* @param fileUrl 文件url
* @return
*/
byte[] downloadFile(String fileUrl);
/**
* 删除文件
*
* @param fileUrl 文件url
*/
void deleteFile(String fileUrl);
}
3.文件上传实现类
package priv.cl.oss.service;
import io.minio.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import priv.cl.oss.config.MinioConfig;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @ClassName MinIOFileStorageServiceImpl
* @Description MinIOFileStorageServiceImpl
* @Author cl
* @Date 2025/2/22 16:45
*/
@Slf4j
@Service
public class MinIOFileStorageServiceImpl implements MinIOFileStorageService {
private String separator = "/";
@Autowired
private MinioClient minioClient;
@Autowired
private MinioConfig minioConfig;
/**
* @param dirPath
* @param filename yyyy/mm/dd/file.jpg
* @return
*/
public String builderFilePath(String dirPath, String filename) {
StringBuilder stringBuilder = new StringBuilder(50);
if (!StringUtils.isEmpty(dirPath)) {
stringBuilder.append(dirPath).append(separator);
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
String todayStr = sdf.format(new Date());
stringBuilder.append(todayStr).append(separator);
stringBuilder.append(filename);
return stringBuilder.toString();
}
/**
* 获取文件名
* @param fileUrl
* @return
*/
public String getFilePathByFileUrl(String fileUrl) {
String filePath = fileUrl.replace(minioConfig.getEndpoint() + "/", "");
int index = filePath.indexOf(separator);
filePath = filePath.substring(index + 1);
return filePath;
}
/**
* 上传图片文件
*
* @param prefix 文件前缀
* @param filename 文件名
* @param inputStream 文件流
* @return url
*/
@Override
public String uploadImgFile(String prefix, String filename, InputStream inputStream) {
String filePath = builderFilePath(prefix, filename);
try {
PutObjectArgs putObjectArgs = PutObjectArgs.builder().object(filePath).contentType("image/jpg").bucket(minioConfig.getBucketName()).stream(inputStream, inputStream.available(), -1).build();
minioClient.putObject(putObjectArgs);
StringBuilder urlPath = new StringBuilder(minioConfig.getPreview());
urlPath.append(separator + minioConfig.getBucketName());
urlPath.append(separator);
urlPath.append(filePath);
return urlPath.toString();
} catch (Exception e) {
log.error("minio put file error.", e);
throw new RuntimeException("上传文件失败");
}
}
/**
* 上传html文件
*
* @param prefix 文件前缀
* @param filename 文件名
* @param inputStream 文件流
* @return url
*/
@Override
public String uploadHtmlFile(String prefix, String filename, InputStream inputStream) {
String filePath = builderFilePath(prefix, filename);
try {
PutObjectArgs putObjectArgs = PutObjectArgs.builder().object(filePath).contentType("text/html").bucket(minioConfig.getBucketName()).stream(inputStream, inputStream.available(), -1).build();
minioClient.putObject(putObjectArgs);
StringBuilder urlPath = new StringBuilder(minioConfig.getEndpoint());
urlPath.append(separator + minioConfig.getBucketName());
urlPath.append(separator);
urlPath.append(filePath);
return urlPath.toString();
} catch (Exception e) {
log.error("minio put file error.", e);
throw new RuntimeException("上传文件失败");
}
}
/**
* 上传文件不分类型
*
* @param prefix 文件前缀
* @param filename 文件名
* @param multipartFile 文件流
* @return url
*/
@Override
public String uploadFileByMultipartFile(String prefix, String filename, MultipartFile multipartFile) {
String filePath = builderFilePath(prefix, filename);
try {
// 将MultipartFile转换为InputStream
InputStream inputStream = multipartFile.getInputStream();
PutObjectArgs putObjectArgs = PutObjectArgs.builder().object(filePath).contentType(multipartFile.getContentType()).bucket(minioConfig.getBucketName()).stream(inputStream, multipartFile.getSize(), -1).build();
minioClient.putObject(putObjectArgs);
StringBuilder urlPath = new StringBuilder(minioConfig.getPreview());
urlPath.append(separator + minioConfig.getBucketName());
urlPath.append(separator);
urlPath.append(filePath);
return urlPath.toString();
} catch (Exception e) {
log.error("minio put file error.", e);
throw new RuntimeException("上传文件失败");
}
}
/**
* 上传本地文件
*
* @param prefix 文件前缀
* @param objectName 文件名称
* @param fileName 本地文件全路径
*/
@Override
public String uploadFile(String prefix, String objectName, String fileName) {
String filePath = builderFilePath(prefix, objectName);
try {
UploadObjectArgs uploadObjectArgs = UploadObjectArgs.builder().bucket(minioConfig.getBucketName()).object(filePath).filename(fileName).build();
minioClient.uploadObject(uploadObjectArgs);
StringBuilder urlPath = new StringBuilder(minioConfig.getEndpoint());
urlPath.append(separator + minioConfig.getBucketName());
urlPath.append(separator);
urlPath.append(filePath);
return urlPath.toString();
} catch (Exception e) {
log.error("minio upload file error.", e);
throw new RuntimeException("上传文件失败");
}
}
/**
* 下载文件url到本地指定文件夹
*
* @param fileUrl 文件url
* @param templatePath 指定路径文件夹
* @return path 本地文件全路径
*/
@Override
public String downloadFile(String fileUrl, String templatePath) {
String filePath = getFilePathByFileUrl(fileUrl);
InputStream inputStream = null;
String filename = filePath.substring(filePath.lastIndexOf(separator) + 1);
try {
inputStream = minioClient.getObject(GetObjectArgs.builder().bucket(minioConfig.getBucketName()).object(filePath).build());
FileOutputStream outputStream = null;
outputStream = new FileOutputStream(templatePath + filename);
byte[] buff = new byte[100];
int rc = 0;
while (true) {
try {
if (!((rc = inputStream.read(buff, 0, 100)) > 0)) break;
} catch (IOException e) {
log.error("文件read失败");
e.printStackTrace();
}
outputStream.write(buff, 0, rc);
}
outputStream.close();
inputStream.close();
} catch (Exception e) {
log.error("minio down file error. pathUrl:{}", fileUrl);
throw new RuntimeException("下载文件url到本地指定文件夹失败");
}
return templatePath + filename;
}
/**
* 下载文件
*
* @param fileUrl 文件全路径
* @return 文件流
*/
@Override
public byte[] downloadFile(String fileUrl) {
String filePath = getFilePathByFileUrl(fileUrl);
InputStream inputStream = null;
try {
inputStream = minioClient.getObject(GetObjectArgs.builder().bucket(minioConfig.getBucketName()).object(filePath).build());
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buff = new byte[100];
int rc = 0;
while (true) {
try {
if (!((rc = inputStream.read(buff, 0, 100)) > 0)) break;
} catch (IOException e) {
log.error("文件read失败");
e.printStackTrace();
}
byteArrayOutputStream.write(buff, 0, rc);
}
return byteArrayOutputStream.toByteArray();
} catch (Exception e) {
log.error("minio down file error. pathUrl:{}", fileUrl);
throw new RuntimeException("下载文件失败");
}
}
/**
* 删除文件
*
* @param fileUrl 文件url
*/
@Override
public void deleteFile(String fileUrl) {
String filePath = getFilePathByFileUrl(fileUrl);
// 构建参数
RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder().bucket(minioConfig.getBucketName()).object(filePath).build();
try {
minioClient.removeObject(removeObjectArgs);
} catch (Exception e) {
log.error("minio remove file error. pathUrl:{}", fileUrl);
throw new RuntimeException("删除文件失败");
}
}
}
4.Controller调用
@RestController
@RequestMapping("/minio")
public class MinioController {
@Autowired
private MinIOFileStorageService minIOFileStorageServiceImpl;
@GetMapping("/test")
public String test(){
return "Hello World";
}
@PostMapping("/fileupload")
public String fileupload(@RequestParam MultipartFile file){
// 检查multipartFile是否为空
if (file == null || file.isEmpty()) {
return "文件为空,无法处理。";
}
// 上传到MinIO服务器
// 这里的"common"是前缀
String url = minIOFileStorageServiceImpl.uploadFileByMultipartFile("common", file.getOriginalFilename(), file);
return url;
}
}
四、测试集成
1.postman调用
2.通过minio客户端查看
遇到问题
1.url无法查看
解决方案:
权限问题,设置成pulic,当然为了安全也可以生成访问外链
至此结束 ,有问题欢迎留言指出谢谢!