一. window环境安装
1. 安装包下载地址:https://min.io/download#/windows,下载一个可执行文件 minio.exe
2. 在想安装目录新建一个minio文件夹,并把minio.exe文件放入minio文件夹中,并且在该文件夹新建一个data文件夹
3. 进入minio文件夹,在路径输入cmd,输入执行 minio.exe server data 命令
4. 若需要换端口则需要执行 minio.exe server data --console-address ":9100" --address ":9101" 注意代码上配置文件需要设置成9101
5. 浏览器输入域地址:http://ip:9101 账号 minioadmin 密码:minioadmin
2.linux环境安装
1. 使用docker安装minio
2. 下载镜像 docker pull minio/minio
3. 查看镜像 docker images
4. 创建目录,一个用来存放配置,一个用来存储上传文件的目录,启动前需要先创建Minio外部挂载的配置文件( /usr/local/minio/config),和存储上传文件的目录( /usr/local/minio/data)
5. 创建容器并运行,下面运行指令
docker run \
-p 19000:9000 \
-p 9090:9090 \
--net=host \
--name minio \
-d --restart=always \
-e "MINIO_ACCESS_KEY=minioadmin" \
-e "MINIO_SECRET_KEY=minioadmin" \
-v /usr/local/minio/data:/data \
-v /usr/local/minio/config:/root/.minio \
minio/minio server \
/data --console-address ":9090" -address ":19000
命令 | 描述 |
-p 19000:9000 -p 9090:9090 | 这是端口映射,前一个是服务器的端口,后一个是客户端也就是api接口访问的端口地址 |
–name minio | 这是给新创建的容器命名的选项,名字是 “minio” |
–net=host | 这是网络设置,表示容器将使用主机的网络栈,这样就不需要在容器内部配置网络 |
-d --restart=always | 这是运行容器的其他选项,-d使容器在后台运行,–restart=always表示容器总是会在退出后自动重启 |
-e “MINIO_ACCESS_KEY=minioadmin” | 用户名 |
-e “MINIO_SECRET_KEY=minioadmin” | 密码 |
-v /usr/local/minio/data:/data | 这意味着将宿主机上的/usr/local/minio/data 目录挂载到容器内的 /data 目录 |
-v /usr/local/minio/config:/root/.minio | 将宿主机上的 /usr/local/minio/config 目录挂载到容器内的 /root/.minio 目录 |
minio/minio server <br/>/data --console-address ":9090" -address ":19000 | 这是容器内要运行的命令,启动一个名为 “minio” 的服务器,数据存储在 /data 目录下,服务器的控制台地址为 “:9090”,服务地址为 “:19000” |
\ | 换行 |
6.访问操作
http://ip:9090/login 账号:minioadmin 密码:minioadmin
3.MinIO的介绍使用
3.1 MinIO概述
官网地址:https://minio.org.cn
MinIO是一款基于Apache License v2.0开源协议的分布式文件系统(或者叫对象存储服务),可以做为云存储的解决方案用来保存海量的图片、视频、文档等。由于采用Golang实现,服务端可以工作在Windows、Linux、 OS X和FreeBSD上。配置简单,基本是复制可执行程序,单行命令就可以运行起来。
MinIO兼容亚马逊S3(Simple Storage Service,简单存储服务)云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而且每个对象文件可以是任意大小,从几kb到最大5T不等。
3.2 MinIO特点
1. 高性能:作为高性能对象存储,在标准硬件条件下它能达到55GB/s的读、35GB/s的写速率;
2. 可扩容:不同MinIO集群可以组成联邦,并形成一个全局的命名空间,并跨越多个数据中心;
3. SDK支持: 基于Minio轻量的特点,它得到类似Java、Python或Go等语言的sdk支持;
4. 支持纠删码:MinIO使用纠删码、Checksum来防止硬件错误和静默数据污染。在最高冗余度配 置下,即使丢失1/2的磁盘也能恢复数据;
3.3 MinIO基本概念
- bucket(桶) :类似文件系统的目录(文件夹);
- Object : 类似文件系统的文件;
- Keys :类似文件名;
- MINIO_ACCESS_KEY:访问key,类似账号;
- MINIO_SECRET_KEY:秘钥,类似密码。
4. springboot整合MinIO
4.1 项目准备
4.1.1 配置 ACCESS KEYS 获取
4.1.2 新建桶,用来存放文件的位置
4.1.3.点击新建的桶,里面配置公众类型,避免文件地址访问不了
4.2 配置文件设置
4.2.1 导入依赖
<!-- https://mvnrepository.com/artifact/io.minio/minio -->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.2.1</version>
</dependency>
4.2.2 配置yml文件
minio:
#accessKey: FPi1mrIRT7LdkVrVgKyq
#secretKey: f0CLUsOPon8qxMFUmCqicHJFkueyWJzyk4CifsEE
#accessKey ,secretKey值的获取在配置accessKey步骤体现
accessKey: FjFA028O825BZ47II9fT
secretKey: 5AumALef8wccA1caMamfD3U0DxLAQTK4Z54jQd3y
# 存放文件的桶
bucket: test
# 访问路径
endpoint: http://110.42.139.83:19000
readPath: http://110.42.139.83:19000
servlet:
multipart:
max-file-size: 200MB
max-request-size: 200MB
4.3 工具类
@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();
}
}
@Component
@Slf4j
public class MinioFileHelper {
@Autowired
MinioClient minioClient;
@Autowired
MinIOConfigProperties minIOConfigProperties;
final static String separator = "/"; //文件夹分隔符
/**
* 上传文件
*
* @param prefix 文件前缀
* @param filename 文件名
* @param inputStream 文件流
* @return 文件全路径
*/
public String uploadFile(String prefix, String filename, InputStream inputStream) {
String filePath = builderFilePath(prefix, filename);
try {
PutObjectArgs putObjectArgs = PutObjectArgs.builder()
.object(filePath)
.bucket(minIOConfigProperties.getBucket()).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) {
throw new RuntimeException("上传文件失败");
}
}
/**
* minio上传图片
*/
public String uploadPicture(String prefix, String filename, InputStream inputStream) {
String filePath = builderFilePath(prefix, filename);
try {
PutObjectArgs putObjectArgs = PutObjectArgs.builder()
.object(filePath)
.contentType("image/jpg")
.bucket(minIOConfigProperties.getBucket()).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) {
throw new RuntimeException("上传文件失败");
}
}
/**
* 上传html文件
*
* @param prefix 文件前缀
* @param filename 文件名
* @param inputStream 文件流
* @return 文件全路径
*/
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(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) {
ex.printStackTrace();
throw new RuntimeException("上传文件失败");
}
}
/**
* 删除文件
*
* @param pathUrl 文件全路径
*/
public void delete(String pathUrl) {
String key = pathUrl.replace(minIOConfigProperties.getEndpoint() + "/", "");
int index = key.indexOf(separator);
String bucket = key.substring(0, index);
String filePath = key.substring(index + 1);
// 删除Objects
RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder().bucket(bucket).object(filePath).build();
try {
minioClient.removeObject(removeObjectArgs);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 下载文件
*
* @param pathUrl 文件全路径
* @return 文件流
*/
public byte[] downLoadFile(String pathUrl) {
String key = pathUrl.replace(minIOConfigProperties.getEndpoint() + "/", "");
int index = key.indexOf(separator);
String bucket = key.substring(0, index);
String filePath = key.substring(index + 1);
InputStream inputStream = null;
try {
inputStream = minioClient.getObject(GetObjectArgs.builder().bucket(minIOConfigProperties.getBucket()).object(filePath).build());
} catch (Exception e) {
e.printStackTrace();
}
//字节数组输出流
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) {
e.printStackTrace();
}
byteArrayOutputStream.write(buff, 0, rc);
}
return byteArrayOutputStream.toByteArray();
}
/**
* 构建文件的绝对路径
*/
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"); 若使用的是/则访问路径yyyy/MM/dd/文件名
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String todayStr = sdf.format(new Date());
stringBuilder.append(todayStr).append(separator);
stringBuilder.append(filename);
return stringBuilder.toString();
}
4.4 调用
@RestController
@Api(tags = "Minio文件上传")
@Slf4j
public class MinioController implements InterfaceRouteUtils {
@Autowired
private MinioFileService minioFileService;
@PostMapping(MINIO_PICTURE_UPLOAD)
@ApiOperation(value = "文件上传-图片", notes = "文件上传")
public ResponseEntity<String> uploadPicture(MultipartFile file) {
try {
return new ResponseEntity<>(minioFileService.uploadPicture(file));
} catch (BaseDocumentException e) {
return new ResponseEntity<>(e.getCode(), e.getMessage());
}
}
@PostMapping(MINIO_FILE_UPLOAD)
@ApiOperation(value = "文件上传", notes = "文件上传")
public ResponseEntity<String> updateFile(MultipartFile file) {
try {
return new ResponseEntity<>(minioFileService.uploadFile(file));
} catch (BaseDocumentException e) {
return new ResponseEntity<>(e.getCode(), e.getMessage());
}
}
}
public interface MinioFileService {
/**
* minio 文件上传文件
*/
String uploadFile(MultipartFile file) throws BaseDocumentException;
/**
* minio 文件上传图片
*/
String uploadPicture(MultipartFile file) throws BaseDocumentException;
}
@Service
@Slf4j
public class MinioFileServiceImpl implements MinioFileService {
@Autowired
private MinioFileHelper minioFileHelper;
/**
* minio 文件上传
*/
@Override
public String uploadFile(MultipartFile file) throws BaseDocumentException {
try {
// 获取文件名称
String fileName = file.getOriginalFilename();
String extension = "";
int i = fileName.lastIndexOf('.');
if (i > 0) {
extension = fileName.substring(i+1);
}
String uuid = UUID.randomUUID().toString().replaceAll("-", "");
fileName = uuid+"."+extension;
InputStream is = file.getInputStream();
String imgUrl = minioFileHelper.uploadFile("file", fileName, is);
return imgUrl;
}catch (Exception e){
log.error("",e);
throw new BaseDocumentException(ErrorCode.OPERATION_ERR);
}
}
@Override
public String uploadPicture(MultipartFile file) throws BaseDocumentException {
try {
// 获取文件名称
String fileName = file.getOriginalFilename();
String extension = "";
int i = fileName.lastIndexOf('.');
if (i > 0) {
extension = fileName.substring(i+1);
}
String uuid = UUID.randomUUID().toString().replaceAll("-", "");
fileName = uuid+"."+extension;
InputStream is = file.getInputStream();
String imgUrl = minioFileHelper.uploadPicture("img", fileName, is);
return imgUrl;
}catch (Exception e){
log.error("",e);
throw new BaseDocumentException(ErrorCode.OPERATION_ERR);
}
}
}
4.5 运行结果
接口返回路径,若是文件则直接下载,如果是图片则直接访问