package com.lomi.minio;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.http.ContentType;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.DeleteError;
import io.minio.messages.DeleteObject;
import io.minio.messages.Item;
import okhttp3.*;
import org.apache.commons.io.FilenameUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.io.ClassPathResource;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDate;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* minio 测试类
*/
//@RunWith(SpringRunner.class)
//@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MinioTest {
String bucketName = "miniobucket";
//@Resource
MinioClient minioClient;
@Before
public void before(){
MinioClient minioClient = MinioClient.builder()
.endpoint("http://" + "192.168.100.66" + ":" + "9000")
.credentials("minioadmin", "minioadmin")
.build();
this.minioClient = minioClient;
}
/**
* put上传文件
* @throws Exception
*/
@Test
public void putFile() throws Exception {
ClassPathResource classPathResource = new ClassPathResource("temp\\minio\\测试文件1.txt");
File file = classPathResource.getFile();
String oldFileName = file.getName();
//创建bucket
if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
}
//String newFileName = generateNewFileName(oldFileName);
String newFileName = classPathResource.getFilename();
//上传
InputStream inputStream = new FileInputStream( file );
PutObjectArgs putObjectArgs = PutObjectArgs.builder()
.bucket(bucketName)
.contentType(ContentType.TEXT_PLAIN.getValue())
.object(newFileName)
.stream(inputStream, inputStream.available(), -1)
.build();
ObjectWriteResponse objectWriteResponse = minioClient.putObject(putObjectArgs);
System.out.println( "上传的文件地址是:" + newFileName );
//获取文件流
GetObjectArgs objectArgs = GetObjectArgs.builder().bucket(bucketName).object(newFileName).build();
GetObjectResponse response = minioClient.getObject(objectArgs);
String content = IoUtil.read(response, Charset.forName("utf8"));
//获取文件下载地址,并且指定过去时间
GetPresignedObjectUrlArgs getPresignedObjectUrlArgs = GetPresignedObjectUrlArgs.builder()
.method(Method.GET)
.bucket(bucketName)
.object(newFileName)
.expiry(20, TimeUnit.SECONDS)
.build();
String url = minioClient.getPresignedObjectUrl(getPresignedObjectUrlArgs);
System.out.println("文件请求地址:" + url );
//下载downloadObject
//下载到 TestExample\target\classes\temp\minio\测试文件2.txt
String downloadPath = new ClassPathResource("temp\\minio").getFile().getAbsolutePath();
System.out.println("下载路径" + downloadPath );
minioClient.downloadObject(DownloadObjectArgs.builder().bucket(bucketName).object(newFileName )
.filename(downloadPath+"/"+"测试文件2.txt")
.build());
System.out.println( "读取到的文件是:" + content );
}
/**
* upload上传文件(只能通过文件路径上传文件,put方式可以通过流的方式)
* @throws Exception
*/
@Test
public void uploadFile() throws Exception {
ClassPathResource classPathResource = new ClassPathResource("temp\\minio\\测试文件1.txt");
File file = classPathResource.getFile();
//创建bucket
if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
}
//String newFileName = generateNewFileName(oldFileName);
String newFileName = classPathResource.getFilename();
//上传
InputStream inputStream = new FileInputStream( file );
PutObjectArgs putObjectArgs = PutObjectArgs.builder()
.bucket(bucketName)
.contentType(ContentType.TEXT_PLAIN.getValue())
.object(newFileName)
.stream(inputStream, inputStream.available(), -1)
.build();
ObjectWriteResponse objectWriteResponse = minioClient.uploadObject( UploadObjectArgs.builder()
.bucket(bucketName)
.contentType(ContentType.TEXT_PLAIN.getValue())
.object(newFileName)
.filename( file.getAbsolutePath() )
.build() );
System.out.println( "上传的文件地址是:" + newFileName );
}
/**
* 表单预上传文件
* @throws Exception
*/
@Test
public void fromUploadFile() throws Exception {
String objectName = "2023/03/20/无标题图片2.jpg";
// 为存储桶创建一个上传策略,过期时间为7天
PostPolicy policy = new PostPolicy(bucketName, ZonedDateTime.now().plusDays(7));
// 设置一个参数key-value,值为上传对象的名称(保存在桶中的名字)
policy.addEqualsCondition("key", objectName);
// 添加 Content-Type以"image/"开头,表示只能上传照片
policy.addStartsWithCondition("Content-Type", "image/png");
policy.addContentLengthRangeCondition(10 * 1024, 10 * 1024 * 1024);
Map<String, String> formData = minioClient.getPresignedPostFormData(policy);
fromUploadFile2( formData , objectName );
System.out.println(JSONUtil.toJsonStr( formData ));
}
/**
* 代码模拟from上传文件
* @param formData
* @param objectName
* @throws Exception
*/
public void fromUploadFile2(Map<String, String> formData,String objectName) throws Exception {
File localFile = new File("C:\\work\\testCode\\TestExample\\src\\main\\resources\\temp\\minio\\无标题.png");
//拼装from请求参数
MultipartBody.Builder multipartBuilder = new MultipartBody.Builder();
multipartBuilder.setType(MultipartBody.FORM);
multipartBuilder.addFormDataPart("key", objectName);// 必须要和策略参数一样
multipartBuilder.addFormDataPart("Content-Type", "image/png");
//这里是 name = file,value=二进制文件
multipartBuilder.addFormDataPart("file", objectName, RequestBody.create(localFile, null));
//把预上传的值都带上
for (Map.Entry<String, String> entry : formData.entrySet()) {
multipartBuilder.addFormDataPart(entry.getKey(), entry.getValue());
}
//from上传地址是到bucket的
Request request =
new Request.Builder()
.url("http://192.168.100.66:9000/" + bucketName)
.post(multipartBuilder.build())
.build();
OkHttpClient httpClient = new OkHttpClient().newBuilder().build();
Response response = httpClient.newCall(request).execute();
if (response.isSuccessful()) {
System.out.println("uploaded successfully using POST object");
} else {
System.out.println("Failed to upload Pictures");
}
}
/**
* 一些其他方法
* @throws Exception
*/
@Test
public void t2() throws Exception {
//bucket是否存在
boolean bucketExist = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName+1).build());
System.out.println( "bucketExist:" + bucketExist );
//删除bucket
System.out.println("删除指定bucket------------------");
if( bucketExist ){
minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName+"1").build());
}
//创建bucket
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName+"1").build());
//查询所有bucket
List<Bucket> buckets = minioClient.listBuckets( );
System.out.println("查询所有bucket-------------------------------");
buckets.forEach( item-> System.out.println( item.name() ));
//获取所有的文件(需要/结尾表示目录,不然只能取到指定目录)//.recursive
System.out.println("查询指定目录下面的bucket-------------------------------");
Iterable<Result<Item>> myObjects = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix("2023/03/20/").maxKeys(100).build());
for (Result<Item> result : myObjects) {
Item item = result.get();
System.out.println("文件:" + item.objectName() );
}
//删除文件(删除不存在的文件不会报错)
//System.out.println("删除单个文件-------------------------------");
minioClient.removeObject(RemoveObjectArgs.builder().bucket( bucketName ).object("2023/03/20/1bb94970ee61426682a45f8f9105990b.txt").build());
//批量删除
List<DeleteObject> objects = new ArrayList<>();
objects.add(new DeleteObject("2023/03/20/020b26d3b00940828b47ba57c77b454c.txt"));
objects.add(new DeleteObject("2023/03/20/1bb94970ee61426682a45f8f9105990b.txt"));
objects.add(new DeleteObject("2023/03/20/7a874e7e2c1e47a8ae2e22c782926e99.txt"));
System.out.println("批量删除文件(removeObjects 要求强制遍历结果,赖删除可能被丢弃 )-------------------------------");
Iterable<Result<DeleteError>> results = minioClient.removeObjects(RemoveObjectsArgs.builder().bucket(bucketName).objects(objects).build());
results.forEach(item -> {
try {
System.out.println("异常:" + item.get());
} catch (Exception e) {
e.printStackTrace();
}
});
//复制,从一个bucket 复制到另外一个bucket
minioClient.copyObject(CopyObjectArgs.builder()
.source(CopySource.builder()
.bucket(bucketName)
.object("2023/03/20/7caa4813faf042df9c831ee7a2a7ceb6.txt")
.build())
.bucket(bucketName+1)
.object("2023/03/20/7caa4813faf042df9c831ee7a2a7ceb6.txt")
.build());
}
/**
* 生成按照日期存放的随机文件名
* @param oldFileName
* @return
*/
private String generateNewFileName( String oldFileName ){
String datePath = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
String uuid = UUID.randomUUID().toString().replace("-", "");
String extension = FilenameUtils.getExtension(oldFileName);
String newFileName = datePath + "/" + uuid + "." + extension;
return newFileName;
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
- 98.
- 99.
- 100.
- 101.
- 102.
- 103.
- 104.
- 105.
- 106.
- 107.
- 108.
- 109.
- 110.
- 111.
- 112.
- 113.
- 114.
- 115.
- 116.
- 117.
- 118.
- 119.
- 120.
- 121.
- 122.
- 123.
- 124.
- 125.
- 126.
- 127.
- 128.
- 129.
- 130.
- 131.
- 132.
- 133.
- 134.
- 135.
- 136.
- 137.
- 138.
- 139.
- 140.
- 141.
- 142.
- 143.
- 144.
- 145.
- 146.
- 147.
- 148.
- 149.
- 150.
- 151.
- 152.
- 153.
- 154.
- 155.
- 156.
- 157.
- 158.
- 159.
- 160.
- 161.
- 162.
- 163.
- 164.
- 165.
- 166.
- 167.
- 168.
- 169.
- 170.
- 171.
- 172.
- 173.
- 174.
- 175.
- 176.
- 177.
- 178.
- 179.
- 180.
- 181.
- 182.
- 183.
- 184.
- 185.
- 186.
- 187.
- 188.
- 189.
- 190.
- 191.
- 192.
- 193.
- 194.
- 195.
- 196.
- 197.
- 198.
- 199.
- 200.
- 201.
- 202.
- 203.
- 204.
- 205.
- 206.
- 207.
- 208.
- 209.
- 210.
- 211.
- 212.
- 213.
- 214.
- 215.
- 216.
- 217.
- 218.
- 219.
- 220.
- 221.
- 222.
- 223.
- 224.
- 225.
- 226.
- 227.
- 228.
- 229.
- 230.
- 231.
- 232.
- 233.
- 234.
- 235.
- 236.
- 237.
- 238.
- 239.
- 240.
- 241.
- 242.
- 243.
- 244.
- 245.
- 246.
- 247.
- 248.
- 249.
- 250.
- 251.
- 252.
- 253.
- 254.
- 255.
- 256.
- 257.
- 258.
- 259.
- 260.
- 261.
- 262.
- 263.
- 264.
- 265.
- 266.
- 267.
- 268.
- 269.
- 270.
- 271.
- 272.
- 273.
- 274.
- 275.
- 276.
- 277.
- 278.
- 279.
- 280.
- 281.
- 282.
- 283.
- 284.
- 285.
- 286.
- 287.
- 288.
- 289.
- 290.
- 291.
- 292.
- 293.
- 294.
- 295.
- 296.
- 297.
- 298.
- 299.
- 300.
- 301.
- 302.
- 303.
- 304.
- 305.
- 306.
- 307.
- 308.
- 309.
- 310.
- 311.
- 312.
- 313.
- 314.
- 315.
- 316.
- 317.
- 318.
- 319.