[SpringBoot アプリケーション] SpringBoot は MinIO オブジェクト ストレージ サービスを統合します
オブジェクトストレージサービス MinIO
MinIO の概要
MinIO は、Apache License v2.0 オープン ソース プロトコルに基づくオブジェクト ストレージ サービスで、大量の写真、ビデオ、ドキュメントを保存するクラウド ストレージ ソリューションとして使用できます。Golang で実装されているため、サーバーは Windows、Linux、OS X、FreeBSD 上で動作できます。構成は単純で、基本的に実行可能プログラムをコピーし、1 行のコマンドで実行します。
MinIO は Amazon S3 クラウド ストレージ サービス インターフェイスと互換性があり、写真、ビデオ、ログ ファイル、バックアップ データ、コンテナ/仮想マシン イメージなどの大容量の非構造化データの保存に非常に適しており、オブジェクト ファイルはkb から最大 5T までの範囲の任意のサイズ。
S3(Simple Storage Service 簡易ストレージサービス)
基本的な考え方
- バケット – ファイル システムに似たディレクトリ
- オブジェクト – ファイル システムに類似したファイル
- キー – アナログファイル名
公式 Web サイトのドキュメント: http://docs.minio.org.cn/docs/
MinIO の機能
一般的なクラウド ストレージの例には、Qiniu Cloud、Alibaba Cloud などが含まれます。デメリットはお金がかかること
プライベートストレージシステム: fastdfs (インストールとデプロイメントが非常に面倒、hadoop をインストールする必要がある、インターフェースがない)、mongodb に付属する GridFS (使用上のデメリットも多い) ため、MinIO と比較すると、次のような利点があります。以下に続きます:
-
SDKのサポート
MinIO は、高性能分散ストレージ ソリューションを開発するための Golang プログラミング言語に基づくオープンソース プロジェクトであり、Minio の軽量な特性に基づいて、Java、Python、Go などの言語の SDK によってサポートされており、非常に完全な公式ウェブサイトのドキュメントがあります。
-
簡単なインストールと展開
Linux 環境では、バイナリ ファイルをダウンロードして実行するだけで、MinIO のインストールと構成が数分で完了します。構成オプションとバリエーションの数は最小限に抑えられるため、構成が失敗する可能性はほぼゼロに減少します。MinIO のアップグレードは簡単なコマンドで完了し、このコマンドにより MinIO のアップグレード作業を中断することなく完了でき、ダウンタイムなしでアップグレード操作を完了できるため、総使用量と運用保守コストが大幅に削減されます。
-
操作ページあり
MinIO サービスをインストールすると、ブラウザから直接システムにログインでき、ユーザーフレンドリーなシンプルな操作インターフェイスにより、バケットとその中のファイル リソースの管理が非常に便利になります。
-
データ保護
Minio は、ハードウェア障害を防ぐために Minio Erasure Code を使用します。ドライバーの半分以上が破損した場合でも、回復することができます。
-
ハイパフォーマンス
高性能オブジェクト ストレージとして、標準的なハードウェア条件下で 55GB/s の読み取り速度と 35GB/s の書き込み速度を達成できます。
-
拡張可能
異なる MinIO クラスターはフェデレーションを形成し、複数のデータセンターにまたがるグローバル名前空間を形成できます。
-
シンプルな機能
この設計原則により、MinIO はエラーが発生しにくくなり、起動が速くなります。
-
豊富なAPI
ファイルリソース共有リンクと共有リンクの有効期限ポリシー、バケット操作、ファイルリストへのアクセス、ファイルのアップロードとダウンロードなどの基本機能をサポートします。
-
ファイル変更のプロアクティブな通知
オブジェクトのアップロードやオブジェクトの削除など、バケット (Bucket) が変更された場合は、バケット イベント通知メカニズムを使用して、AMQP、MQTT、Elasticsearch、Redis、NATS、MySQL、Kafka、Webhook、等
箱から出してそのまま使用
Dockerのインストールが始まります
環境の展開と起動には最新の docker を使用できます2023-08-31T15-31-16Z
docker run -p 9000:9000 -p 9090:9090 --name minio -d --restart=always -e "MINIO_ACCESS_KEY=minio" -e "MINIO_SECRET_KEY=minio123" -v /home/data:/data -v /home/config:/root/.minio minio/minio server /data --console-address ":9090" -address ":9000"
-e
環境変数MINIO_ROOT_USER
と を設定しますMINIO_ROOT_PASSWORD
。これらはroot ユーザーの資格情報を設定します。コンテナに使用されるサンプル値を変更する
管理コンソール
サーバー アドレスが であると仮定し192.168.171.128
、アドレス バーに http://192.168.171.128:9000/ と入力して、ログイン インターフェイスに入ります。
アクセスキーはDocker コンテナ作成時に作成されるminio
Secret_keyminio123
で、システムに入るとメインインターフェイスが表示されます。
バケットを作成するには、「バケットの作成」をクリックします。ここでのバケットは、ファイルが保存されるディレクトリとして理解できます。複数のバケットは、互いに独立して作成できます。
クイックスタート
Java がファイルを minio にアップロードする
pom 依存関係
<dependencies>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>7.1.0</version>
</dependency>
</dependencies>
テストクラスを作成してファイルをアップロードする
public class MinIOTest {
public static void main(String[] args) {
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream("D:\\study\\images\\1.png");;
//1.创建minio链接客户端
MinioClient minioClient = MinioClient.builder().credentials("minio", "minio123").endpoint("http://192.168.171.128:9000").build();
//2.上传
String objectName = UUID.randomUUID().toString();
PutObjectArgs putObjectArgs = PutObjectArgs.builder()
.object(objectName+".png")//文件名
.contentType("image/jpg")//文件类型 MediaType.IMAGE_PNG_VALUE代替
.bucket("miniotest")//桶名词 与minio创建的名词一致
.stream(fileInputStream, fileInputStream.available(), -1) //文件流
.build();
minioClient.putObject(putObjectArgs);
System.out.println("http://192.168.171.128:9000/miniotest/"+objectName+".png");
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
オブジェクト名として UUID を使用します。
-
オブジェクト名の競合を避けるための一意性。
-
実際のファイル情報を非表示にし、プライバシーを向上させます。
-
オブジェクト名は、元のファイル名の長さや特殊文字によって制限されません。
実際のシナリオでは、ファイルの識別と管理にさらに注意を払う場合は、ファイル名の使用を検討できます。一意性とプライバシーにさらに注意を払う場合は、UUID の使用を検討してください。
同時に、ファイル名をオブジェクト プロパティとして保存し、UUID をオブジェクト名として使用するなど、2 つを組み合わせることもできます。これにより、ファイル情報が保存され、一意性が保証されます。
クライアント コンソールにアクセスすると、イメージが正常にアップロードされています。
アクセス許可を構成する
アップロードしたファイルにブラウザでアクセスします アクセスするファイル形式はhttp://minio服务器ip:9090/存储桶/文件名
こちらですhttp://192.168.171.128:9000/miniotest/dc7a7378-eb4e-4622-afd6-32f3b41e14bf.png
アクセスするとエラーになります作成したバケットスペースの設定がプライベートであり、他のユーザーにアクセス権限がないためです
アップロードしたファイルに匿名ユーザーがアクセスできるようにする必要がある場合は、アクセス許可をPublic
権限に変更する必要があります。
ブラウザアクセス成功
MinIO をスターターとしてカプセル化する
モジュール zy-minio-starter を作成する
依存関係をインポートする
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>7.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
構成クラス
MinIOConfigProperties
@Data
@ConfigurationProperties(prefix = "minio") // 文件上传 配置前缀file.oss
public class MinIOConfigProperties implements Serializable {
private String accessKey;
private String secretKey;
private String bucket;
private String endpoint;
private String readPath;
}
MinIOConfig
@Configuration
@EnableConfigurationProperties({
MinIOConfigProperties.class})
//当引入FileStorageService接口时
@ConditionalOnClass(FileStorageService.class)
public class MinIOConfig {
@Autowired
private MinIOConfigProperties minIOConfigProperties;
@Bean
public MinioClient buildMinioClient(){
return MinioClient
.builder()
.credentials(minIOConfigProperties.getAccessKey(), minIOConfigProperties.getSecretKey())
.endpoint(minIOConfigProperties.getEndpoint())
.build();
}
}
カプセル化操作 minIO クラス
ファイルストレージサービス
public interface FileStorageService {
/**
* 上传图片文件
* @param prefix 文件前缀
* @param filename 文件名
* @param inputStream 文件流
* @return 文件全路径
*/
public String uploadImgFile(String prefix, String filename,InputStream inputStream);
/**
* 上传html文件
* @param prefix 文件前缀
* @param filename 文件名
* @param inputStream 文件流
* @return 文件全路径
*/
public String uploadHtmlFile(String prefix, String filename,InputStream inputStream);
/**
* 删除文件
* @param pathUrl 文件全路径
*/
public void delete(String pathUrl);
/**
* 下载文件
* @param pathUrl 文件全路径
* @return
*
*/
public byte[] downLoadFile(String pathUrl);
}
MinIOFileStorageService
@Slf4j
@Import(MinIOConfig.class)
public class MinIOFileStorageService implements FileStorageService {
@Autowired
private MinioClient minioClient;
@Autowired
private MinIOConfigProperties minIOConfigProperties;
private final static String separator = "/";
/**
* @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 prefix 文件前缀
* @param filename 文件名
* @param inputStream 文件流
* @return 文件全路径
*/
@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(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){
log.error("minio put file error.",ex);
throw new RuntimeException("上传文件失败");
}
}
/**
* 上传html文件
* @param prefix 文件前缀
* @param filename 文件名
* @param inputStream 文件流
* @return 文件全路径
*/
@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(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){
log.error("minio put file error.",ex);
ex.printStackTrace();
throw new RuntimeException("上传文件失败");
}
}
/**
* 删除文件
* @param pathUrl 文件全路径
*/
@Override
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) {
log.error("minio remove file error. pathUrl:{}",pathUrl);
e.printStackTrace();
}
}
/**
* 下载文件
* @param pathUrl 文件全路径
* @return 文件流
*
*/
@Override
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) {
log.error("minio down file error. pathUrl:{}",pathUrl);
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();
}
}
自動構成を外部から参加する
リソースに新規作成META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.zysheep.file.service.impl.MinIOFileStorageService
他のマイクロサービスによる使用
まず、zy-minio-starter の依存関係をインポートします。
次に、minio に必要な構成をマイクロサービスに追加します。
minio:
accessKey: minio
secretKey: minio123
bucket: miniotest
endpoint: http://192.168.171.128:9000
readPath: http://192.168.171.128:9000
3 番目に、対応するビジネス クラスに FileStorageService を挿入します。例は次のとおりです。
@SpringBootTest(classes = MinIOApplication.class)
public class MinioBootTest {
@Autowired
private FileStorageService fileStorageService;
@Test
public void testUpdateImgFile() {
try {
FileInputStream fileInputStream = new FileInputStream("D:\\study\\images\\docker3.png");
String fileName = UUID.randomUUID().toString();
String filePath = fileStorageService.uploadImgFile("", fileName+".jpg", fileInputStream);
System.out.println(filePath);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}