学习
未学
Minio_云烟成雨TD的博客-CSDN博客 https://blog.csdn.net/qq_43437874/category_10562215.html
千锋教育首发MinIO免费中文视频教程 https://www.bilibili.com/video/BV1uB4y1F7eK?from=search&seid=1307822534653799596
对象存储MInIO(免费开源对象存储服务)-阿里云OSS太贵?FastDFS配置太麻烦?MinIO帮助您解决一切问题.https://www.bilibili.com/video/BV1Ht4y1S79P
MinIo新旧版本工具类和部署文档 https://blog.csdn.net/panpeichang/article/details/116235058
MinIO客户端mc使用
https://blog.csdn.net/qq_42402854/article/details/121474018
Windows安装
下载exe后,cd到exe路径,执行
.\minio.exe server C:\minio
会出现如下内容,包括访问地址、ACCESS-KEY、SECRET-KEY
C:\Users\vaynexiao\Desktop> .\minio.exe server C:\minio
API: http://192.168.31.63:9000 http://192.168.131.1:9000 http://192.168.78.1:9000 http://127.0.0.1:9000
RootUser: minioadmin
RootPass: minioadmin
Console: http://192.168.31.63:49343 http://192.168.131.1:49343 http://192.168.78.1:49343 http://127.0.0.1:49343
RootUser: minioadmin
RootPass: minioadmin
Command-line: https://docs.min.io/docs/minio-client-quickstart-guide
$ mc.exe alias set myminio http://192.168.31.63:9000 minioadmin minioadmin
Documentation: https://docs.min.io
WARNING: Console endpoint is listening on a dynamic port (49343), please use --console-address ":PORT" to choose a static port.
+---------------------------------------------------------------+
| You are running an older version of MinIO released 4 days ago |
| Update: Run `mc admin update` |
+---------------------------------------------------------------+
MC下载
https://dl.minio.io/client/mc/release/
pom.xml
<dependencies>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.3.7</version>
</dependency>
</dependencies>
可视化客户端
windows客户端:https://s3browser.com/download.aspx
S3 Compatible Storage
AK
SK
Java使用Minio
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.2.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
application.yml
server:
port: 8080
servlet:
context-path: /
spring:
application:
name: minio-demo
#设置请求文件大小,可自行修改
servlet:
multipart:
max-file-size: 5000MB
max-request-size: 5000MB
minio:
endpoint: http://127.0.0.1:9000
accessKey: minioadmin
secretKey: minioadmin
filHost: http://file.songshijun.top
logging:
level:
ROOT: info
com.minio: debug
pattern:
file: '%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread] %logger{50} - %msg%n'
file:
name: ${logging.file.path}/${spring.application.name}.log
path: /home/logs/${spring.application.name}
max-size: 10MB
max-history: 30
MinioProperties.java
@Data
@Component
@ConfigurationProperties(prefix = "minio")
public class MinioProperties {
private String endpoint;
private String accessKey;
private String secretKey;
private String filHost;
}
MinioConfig.java
@Configuration
public class MinioConfig {
@Autowired
private MinioProperties minioProperties;
@Bean
public MinioClient minioClient() {
return MinioClient.builder()
.endpoint(minioProperties.getEndpoint())
.credentials(minioProperties.getAccessKey(), minioProperties.getSecretKey())
.build();
}
}
FileUploadResponse.java
@Data
@AllArgsConstructor
public class FileUploadResponse {
private String urlHttp;
private String urlPath;
}
MinioUtil.java
import io.minio.*;
import io.minio.errors.*;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLDecoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@Slf4j
@Component
public class MinioUtil {
@Autowired
private MinioProperties minioProperties;
@Autowired
private MinioClient client;
public void createBucket(String bucketName) throws Exception {
if (!client.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
}
}
public FileUploadResponse upload(MultipartFile file, String bucketName) throws Exception {
//判断文件是否为空
if (null == file || 0 == file.getSize()) {
new FileUploadResponse("", "file's size is null");
}
createBucket(bucketName);
String fileName = file.getOriginalFilename();
client.putObject(
PutObjectArgs.builder().bucket(bucketName).object(fileName).stream(
file.getInputStream(), file.getSize(), -1)
.contentType(file.getContentType())
.build());
String url = minioProperties.getEndpoint() + "/" + bucketName + "/" + fileName;
String urlHost = minioProperties.getFilHost() + "/" + bucketName + "/" + fileName;
log.info("上传文件成功url :[{}], urlHost :[{}]", url, urlHost);
return new FileUploadResponse(url, urlHost);
}
public List<String> getAllBuckets() throws Exception {
List<Bucket> buckets = client.listBuckets();
List<String> names = new ArrayList<>();
System.out.println(buckets.size());
for (int i = 0; i < buckets.size(); i++) {
names.add(buckets.get(i).name());
}
return names;
}
public Optional<Bucket> getBucketInfo(String bucketName) throws IOException, InvalidKeyException,
NoSuchAlgorithmException, InsufficientDataException, InvalidResponseException, InternalException,
ErrorResponseException, ServerException, XmlParserException {
return client.listBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();
}
public boolean removeBucket(String bucketName) throws Exception {
try{
client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
} catch (Exception e){
return false;
}
return true;
}
/**
* 获取⽂件外链
*
* @param bucketName bucket名称
* @param objectName ⽂件名称
* @param expires 过期时间 <=7
* @return url
*/
public String getObjectURL(String bucketName, String objectName, Integer expires) throws Exception {
return client.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().bucket(bucketName).object(objectName).expiry(expires).build());
}
/**
* 获取⽂件
*
* @param bucketName bucket名称
* @param objectName ⽂件名称
* @return ⼆进制流
*/
public InputStream getObject(String bucketName, String objectName) throws Exception {
return client.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());
}
/**
* 上传⽂件
*
* @param bucketName bucket名称
* @param objectName ⽂件名称
* @param stream ⽂件流
* @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#putObject
*/
public void putObject(String bucketName, String objectName, InputStream stream) throws
Exception {
client.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(stream, stream.available(), -1)
.contentType(objectName.substring(objectName.lastIndexOf("."))).build());
}
/**
* 上传⽂件
*
* @param bucketName bucket名称
* @param objectName ⽂件名称
* @param stream ⽂件流
* @param size ⼤⼩
* @param contextType 类型
* @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#putObject
*/
public void putObject(String bucketName, String objectName, InputStream stream, long
size, String contextType) throws Exception {
client.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(stream, size, -1)
.contentType(contextType).build());
}
/**
* 获取⽂件信息
*
* @param bucketName bucket名称
* @param objectName ⽂件名称
* @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#statObject
*/
public StatObjectResponse getObjectInfo(String bucketName, String objectName) throws Exception {
return client.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
}
public boolean removeObject(String bucketName, String objectName) throws Exception {
try{
client.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());
} catch (Exception e){
return false;
}
return true;
}
/**
* 查看文件对象
* @param bucketName 存储bucket名称
* @return 存储bucket内文件对象信息
*/
public List<MinIOFile> listObjects(String bucketName) {
Iterable<Result<Item>> results = client.listObjects(
ListObjectsArgs.builder().bucket(bucketName).build());
List<MinIOFile> files = new ArrayList<>();
try {
for (Result<Item> result : results) {
Item item = result.get();
MinIOFile minIOFile = new MinIOFile();
minIOFile.setObjectName(URLDecoder.decode(item.objectName(), "utf-8"));
minIOFile.setIsDir(item.isDir());
minIOFile.setOwner(item.owner().displayName());
minIOFile.setSize(item.size());
minIOFile.setLastModified(item.lastModified().toString());
files.add(minIOFile);
}
} catch (Exception e) {
e.printStackTrace();
return new ArrayList<>();
}
return files;
}
}
MinIOFile.java
@Data
@ToString
public class MinIOFile {
private String objectName;
private String lastModified;
private String owner;
private Long size;
private Boolean isDir;
}
MinioController.java
package com.example.demo4;
import io.minio.errors.MinioException;
import io.minio.messages.Bucket;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.*;
@Slf4j
@RestController
@RequestMapping("/file")
public class MinioController {
@Autowired
private MinioUtil minioUtil;
@RequestMapping("/makeBucket/{bucketName}")
public void makeBucket(@PathVariable String bucketName) throws Exception {
minioUtil.createBucket(bucketName);
}
@RequestMapping("/removeBucket/{bucketName}")
public String removeBucket(@PathVariable String bucketName) throws Exception {
Boolean aBoolean = minioUtil.removeBucket(bucketName);
return aBoolean.toString();
}
@PostMapping("/getBucketInfo")
public HashMap<String, String> getBucketInfo(String bucketName) throws Exception {
Optional<Bucket> bucket = minioUtil.getBucketInfo(bucketName);
HashMap<String, String> bucketInfo = new HashMap<String, String>();
bucketInfo.put("name", bucket.get().name());
bucketInfo.put("createDate", bucket.get().creationDate().toString());
return bucketInfo;
}
// todo 当有文件夹时候查不出来数据???
@PostMapping("/listObjects/{bucketName}")
public List<MinIOFile> listObjects(@PathVariable String bucketName) throws Exception {
return minioUtil.listObjects(bucketName);
}
@PostMapping("/getAllBuckets")
public List<String> getAllBuckets() throws Exception {
return minioUtil.getAllBuckets();
}
@PostMapping("/upload")
public FileUploadResponse upload(@RequestParam(name = "file") MultipartFile file, @RequestParam String bucketName) {
FileUploadResponse response = null;
try {
response = minioUtil.upload(file, bucketName);
} catch (Exception e) {
log.error("上传失败 : [{}]", Arrays.asList(e.getStackTrace()));
}
return response;
}
@DeleteMapping("/delete/{objectName}")
public boolean delete(@PathVariable("objectName") String objectName, @RequestParam String bucketName) throws Exception {
// todo 先看有没有这文件,没有报错
boolean result = minioUtil.removeObject(bucketName, objectName);
System.out.println("删除成功");
return result;
}
@GetMapping("/download/{bucketName}/{objectName}")
public ResponseEntity<byte[]> downloadToLocal(@PathVariable("objectName") String objectName,
@PathVariable("bucketName") String bucketName,
HttpServletResponse response) throws Exception {
ResponseEntity<byte[]> responseEntity = null;
InputStream stream = null;
ByteArrayOutputStream output = null;
try {
// 获取"myobject"的输入流。
stream = minioUtil.getObject(bucketName, objectName);
//用于转换byte
output = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int n = 0;
while (-1 != (n = stream.read(buffer))) {
output.write(buffer, 0, n);
}
byte[] bytes = output.toByteArray();
//设置header
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Accept-Ranges", "bytes");
httpHeaders.add("Content-Length", bytes.length + "");
// objectName = new String(objectName.getBytes("UTF-8"), "ISO8859-1");
//把文件名按UTF-8取出并按ISO8859-1编码,保证弹出窗口中的文件名中文不乱码,中文不要太多,最多支持17个中文,因为header有150个字节限制。
httpHeaders.add("Content-disposition", "attachment; filename=" + objectName);
httpHeaders.add("Content-Type", "text/plain;charset=utf-8");
// httpHeaders.add("Content-Type", "image/jpeg");
responseEntity = new ResponseEntity<byte[]>(bytes, httpHeaders, HttpStatus.CREATED);
} catch (MinioException e) {
e.printStackTrace();
} finally {
if (stream != null) {
stream.close();
}
if (output != null) {
output.close();
}
}
return responseEntity;
}
/**
* 在浏览器预览图片
*/
@GetMapping("/preViewPicture/{objectName}")
public void preViewPicture(@PathVariable("objectName") String objectName, HttpServletResponse response) throws Exception {
response.setContentType("image/jpeg");
try (ServletOutputStream out = response.getOutputStream()) {
InputStream stream = minioUtil.getObject("salt", objectName);
ByteArrayOutputStream output = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int n = 0;
while (-1 != (n = stream.read(buffer))) {
output.write(buffer, 0, n);
}
byte[] bytes = output.toByteArray();
out.write(bytes);
out.flush();
}
}
}