首先我们先需要在服务器上搭建minio,目前我是在linux用docker搭建的minio服务:
搭建minio服务:
1. 拉取镜像,下载指定版本的minio
docker pull minio/minio:RELEASE.2021-04-06T23-11-00Z
2. 指定镜像版本创建minio容器并运行
docker run -p 4007:9000 --name minio -d --restart=always -e "MINIO_ACCESS_KEY=minio" -e "MINIO_SECRET_KEY=minio111" -v /minio/data:/data -v /minio/config:/root/.minio minio/minio:RELEASE.2021-04-06T23-11-00Z server /data
命令行翻译:
-p 4007:9000 ,端口映射
-e,环境变量
-d,后台运行
–name,给容器起名字
–restart=always,开机自启
-e “MINIO_ACCESS_KEY=minio”,设置账号
-e “MINIO_SECRET_KEY=minio123”,设置密码
-v 挂载数据卷
我自己设置成了4007的端口
3. 测试访问minio后台登录系统,直接访问服务器IP:4007(刚设置的端口即可),进行登录
管理页面:正常一进来是没有buket桶的 需要自行点击右下角的加号创建
输入桶的名称创建桶
刚刚创建的桶test,以及右侧框住的桶结构
4. SpringBoot整合minio
导入相关依赖
<dependencies>
<!--minio-->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>7.1.0</version>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!--knife4j(swagger) -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.2</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
编写minio属性配置类
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.io.Serializable;
@Data
@Component
@ConfigurationProperties(prefix = "minio") //自动注入属性前缀为minio的配置
public class MinIOConfigProperties implements Serializable {
private String accessKey; // 访问key
private String secretKey; // 秘钥
private String bucket; // 桶
private String endpoint; // 地域节点
private String readPath; // 读取路径
}
编写MinIO配置类,注册MinioClient客户端的Bean对象
import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* MinIO配置类
*
* @author 白豆五
* @version 2023/04/21
* @since JDK8
*/
@Configuration
public class MinIOConfig {
@Autowired
private MinIOConfigProperties minIOConfigProperties;
// 注册MinIO实例
@Bean
public MinioClient buildMinioClient(){
return MinioClient
.builder()
.credentials(minIOConfigProperties.getAccessKey(), minIOConfigProperties.getSecretKey())
.endpoint(minIOConfigProperties.getEndpoint())
.build();
}
}
在application.yml文件中配置minio自定义属性和文件上传大小
minio:
accessKey: minio
secretKey: minio123
bucket: testminio
endpoint: http://192.168.200.128:9000
readPath: http://192.168.200.128:9000
servlet:
multipart:
# 单个上传文件的最大值是200mb
max-file-size: 200MB
# 单次请求的最大值
max-request-size: 200MB
编写操作minio相关业务接口
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
/**
* 操作minio相关业务接口
*
* @author Jx
* @version 2023-11-14
* @since JDK8
*/
public interface IFileStorageService{
/**
* 上传文件
*
* @param prefix 文件前缀
* @param filename 文件名
* @param inputStream 文件流
* @return 文件全路径
*/
public String uploadFile(String prefix, String filename, InputStream inputStream);
/**
* 删除文件
*
* @param pathUrl 文件全路径
*/
public void delete(String pathUrl);
/**
* 下载文件
*
* @param pathUrl 文件全路径
* @return
*/
public void downLoad(HttpServletResponse response, String pathUrl);
/**
* 在线预览文件
* @param filePath
* @return
*/
public String getPreviewUrl(String filePath);
}
业务接口实现类:
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.geb.common.config.MinIOConfigProperties;
import com.geb.system.service.IFileStorageService;
import io.minio.*;
import io.minio.http.Method;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
@Slf4j
@Service
public class MinIOFileStorageServiceImpl implements IFileStorageService {
@Autowired
private MinioClient minioClient;
@Autowired
private MinIOConfigProperties minIOConfigProperties;
private final static String separator = "/"; //文件夹分隔符
private final static String endPointUrl = "http://219.159.22.22:4007";
private final static String endPointUrl1 = "http://minio:9000";
/**
* 构建文件的绝对路径 -- 按需构建 如无需则可省略此步骤
*
* @param dirPath 文件路径
* @param filename 文件名 yyyy/mm/dd/file.jpg
* @return /test
*/
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 prefix 文件前缀
* @param filename 文件名
* @param inputStream 文件流
* @return 文件全路径
*/
@Override
public String uploadFile(String prefix, String filename, InputStream inputStream) {
String filePath = builderFilePath(prefix, filename);
try {
PutObjectArgs putObjectArgs = PutObjectArgs.builder()
.object(filePath) //文件名
.contentType("text/json")//文件类型
.bucket(minIOConfigProperties.getBucket())//桶名称与minio创建的桶一致
.stream(inputStream, inputStream.available(), -1)//文件流
.build();
minioClient.putObject(putObjectArgs);
StringBuilder urlPath = new StringBuilder(minIOConfigProperties.getReadPath());
urlPath.append(separator + minIOConfigProperties.getBucket());
urlPath.append(separator);
urlPath.append(filePath);
return urlPath.toString(); //文件全路径
} catch (Exception ex) {
log.error("minio put file error.", ex);
ex.printStackTrace();
throw new RuntimeException("上传文件失败");
}
}
/**
* 删除文件 -- 能获取到根节点endpoint即可 如果可直接获取到则可无需重新构建根节点endpoint
*
* @param pathUrl 文件全路径
*/
@Override
public void delete(String pathUrl) {
/** 获取桶后面的删除路径 */
String delUrl = pathUrl.substring(pathUrl.lastIndexOf("/json"), pathUrl.length());
/** 重新构建根节点endpoint */
minioClient = MinioClient.builder()
.endpoint(endPointUrl1)
.credentials(minIOConfigProperties.getAccessKey(), minIOConfigProperties.getSecretKey())
.build();
/** 删除文件 */
RemoveObjectArgs removeObjectArgs = RemoveObjectArgs
.builder()
.bucket(minIOConfigProperties.getBucket())
.object(separator + delUrl).build();
try {
minioClient.removeObject(removeObjectArgs);
} catch (Exception e) {
log.error("minio remove file error. pathUrl:{}", pathUrl);
e.printStackTrace();
}
}
/**
* 下载文件 -- 走浏览器下载
*
* @param pathUrl 文件全路径
* @return 文件流 byte[]
*/
@Override
public void downLoad(HttpServletResponse response, String pathUrl) {/** 拼接完整的下载路径 pathUrl+minio */
/** 获取文件名称 */
String fileName = pathUrl.substring(pathUrl.lastIndexOf("/") + 1, pathUrl.length()) + ".json";
/** 获取桶后面的下载路径 */
String downUrl = pathUrl.substring(pathUrl.lastIndexOf("/json"), pathUrl.length());
/** 获取本地文件默认下载路径 */
InputStream inputStream = null;
try {
/** 重新构建根节点endpoint */
minioClient = MinioClient.builder()
.endpoint(endPointUrl1)
.credentials(minIOConfigProperties.getAccessKey(), minIOConfigProperties.getSecretKey())
.build();
inputStream = minioClient.getObject(GetObjectArgs.builder()
.bucket(minIOConfigProperties.getBucket())
.object(downUrl).build());
/*** text/json */
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
response.setCharacterEncoding("UTF-8");
/*** 用文件流的方式读取到下载文件中 */
OutputStream outputStream = response.getOutputStream();
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
inputStream.close();
outputStream.close();
} catch (Exception e) {
log.error("minio down file error. pathUrl:{}", pathUrl);
e.printStackTrace();
}
}
/**
* 在线预览文件
* @param pathUrl
* @return
*/
@Override
@SneakyThrows(Exception.class)
public String getPreviewUrl(String pathUrl) {
/** 获取文件名称 */
String fileName = pathUrl.substring(pathUrl.lastIndexOf("/") + 1, pathUrl.length());
/** 获取桶后面的下载路径 */
String downUrl = pathUrl.substring(pathUrl.lastIndexOf("/json"), pathUrl.length());
/** 重新构建根节点endpoint */
minioClient = MinioClient.builder()
.endpoint(endPointUrl)
.credentials(minIOConfigProperties.getAccessKey(), minIOConfigProperties.getSecretKey())
.build();
/** 获取预览的路径 */
String url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
.method(Method.GET)
.bucket(minIOConfigProperties.getBucket())
.object(downUrl)
.build());
System.out.println("previewUrl===" + url);
return url;
}
}
编写controller
package com.baidou.controller;
import com.baidou.dto.Result;
import com.baidou.service.FileStorageService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
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 java.io.IOException;
import java.io.InputStream;
import java.util.UUID;
/**
* 操作minio的控制器类
*
* @author 白豆五
* @version 2023/04/21
* @since JDK8
*/
@RestController
@RequestMapping("/minio")
@Api(tags = "minio相关接口")
public class MinioController {
@Autowired
private FileStorageService fileStorageService;
/**
* 上传图片到minio
*
* @param file
* @return
*/
@PostMapping("upload")
@ApiOperation(value = "图片上传接口")
public Result uploadFile(MultipartFile file) throws IOException {
try {
// 获取文件名称
String fileName = file.getOriginalFilename();
/*解决多次上传同名文件覆盖问题*/
// 在文件名称里面添加随机唯一的值
String uuid = UUID.randomUUID().toString().replaceAll("-", "");
fileName = uuid + fileName;
// 获取文件输入流
InputStream is = file.getInputStream();
String imgUrl = fileStorageService.uploadImgFile("img", fileName, is);
return Result.success(imgUrl, "上传成功");
} catch (IOException e) {
e.printStackTrace();
return Result.error("上传失败");
}
}
}
启动项目,然后用postman测试
如果想上传其它格式的文件,可以在上传接口更换文件格式,由于我自己做的上传是通过读取数据库表数据进行prompt格式转换后的输入流,下面把Controller以及实现类的代码po出来
Controller如下:
/**
* 新增数据格式转换
*/
@Log(title = "数据格式转换-创建转换记录", businessType = BusinessType.INSERT)
@ApiOperation(value = "创建转换记录(上传文件数据)")
@PostMapping("/save")
public R<String> save(@Validated @RequestBody AddDataFormatConversionDto addDataFormatConversionDto) {
/** 获取数据表的字段列名称 */
List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(addDataFormatConversionDto.getDataId());
List<String> columnList = new ArrayList<>();
for (GenTableColumn genTableColum : list) {
columnList.add(genTableColum.getColumnName());
}
String filePath = dataFormatConversionService.insertDataFormatConversion(addDataFormatConversionDto, columnList, getUsername(), getUserId());
return R.ok(filePath);
}
serviceImpl层代码:
/** 区分不同文件名称 */
String fileName = "fine_tune_data_" + dataFormatConversion.getId() + ".json";
byte[] bytes = dataContent.toString().getBytes();
InputStream inputStream = new ByteArrayInputStream(bytes);
String filePath = uploadFile("json", fileName, inputStream, dataFormatConversion.getId());
/**
* 上传文件
*
* @param prefix 文件前缀
* @param filename 文件名
* @param inputStream 文件流
* @return 文件全路径
*/
public String uploadFile(String prefix, String filename, InputStream inputStream, Long id) {
String filePath = JsonUtil.builderFilePath(prefix, filename);
try {
PutObjectArgs putObjectArgs = PutObjectArgs.builder()
.object(filePath) //文件名
.contentType("text/json")//文件类型
.bucket(minIOConfigProperties.getBucket())//桶名称与minio创建的桶一致
.stream(inputStream, inputStream.available(), -1)//文件流
.build();
minioClient.putObject(putObjectArgs);
StringBuilder urlPath = new StringBuilder(minIOConfigProperties.getReadPath());
urlPath.append(separator + minIOConfigProperties.getBucket());
urlPath.append(separator);
urlPath.append(filePath);
return urlPath.toString(); //文件全路径
} catch (Exception ex) {
DataFormatConversion updateDfa = new DataFormatConversion();
updateDfa.setId(id);
updateDfa.setTransisionStatus(3L); // 设置数据格式转换失败状态
dataFormatConversionMapper.updateById(updateDfa);
log.error("minio put file error. && 文件格式转换失败", ex);
ex.printStackTrace();
throw new RuntimeException("上传文件失败");
}
}
共用的上传,预览,下载,删除文件接口都在minio serviceImpl实现类中,可自行使用,感谢阅读,有不足欢迎补充~希望跟大家多多交流!