При ежедневной разработке служб, связанных с загрузкой файлов, в качестве системы хранения файлов обычно выбираются службы oss, предоставляемые Tencent Cloud, Alibaba Cloud, Qiniu Cloud и т. д. Если вам нужно создать собственную систему хранения файлов, проекты с открытым исходным кодом. обычно используются такие, как minio.
Но задумывались ли вы когда-нибудь, что клиентские SDK, предоставляемые разными производителями или проектами с открытым исходным кодом, различаются. Если базовую файловую систему необходимо переключить во время разработки проекта, это обычно означает, что нам необходимо полностью заменить соответствующий код загрузки файлов. это проект микросервиса, вам необходимо заменить весь код, который использует микросервис загрузки файлов SDK, что, очевидно, принесет огромную рабочую нагрузку.
Для решения вышеуказанной проблемы у нас есть следующие две идеи:
Эту идею легко придумать, используя фасадную модель для защиты базовой реализации от вызывающей стороны, но на самом деле существует более краткий метод реализации.
Здесь мы используем Minio в качестве демонстрационного примера. Если вы не знаете minio, вы можете узнать о нем из официальной документации minio. Давайте сначала установим minio с помощью docker:
docker pull minio/minio
docker run --name minio \
-p 9000:9000 \
-p 9090:9090 \
-d --restart=always \
-e "MINIO_ROOT_USER=admin" \
-e "MINIO_ROOT_PASSWORD=admin123" \
-v /usr/local/minio/data:/data \
-v /usr/local/minio/config:/root/.minio \
minio/minio server /data \
--console-address '0.0.0.0:9090'
Обратите внимание, что консольный порт здесь необходимо задать отдельно, иначе будет выдано сообщение об ошибке и доступ будет недоступен.
В этом методе установки пользовательские ключи доступа и секретные ключи MinIO перезапишут автоматически сгенерированные ключи MinIO.
Вход в клиент(Браузер):Уведомление—>порт здесь,Это консольный порт, который вы установили: 9090.
Логином и паролем здесь являются имя пользователя и пароль, установленные при запуске службы: admin admin123.
Основные операции с бакетами minio подробно описываться не будут, они такие же, как и обычные сервисы oss.
https://gitee.com/DaHuYuXiXi/common-oss-service
<dependencies>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-s3</artifactId>
<version>1.12.267</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>2.7.3</version>
<optional>true</optional>
</dependency>
</dependencies>
package com.oss.client;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.PutObjectResult;
import com.amazonaws.services.s3.model.S3Object;
import java.io.IOException;
import java.io.InputStream;
/**
* Oss Основные операции
* Если вам нужны более сложные операции, вы можете напрямую получить AmazonS3 через AmazonS3. выполнять сложные операции
* https://docs.aws.amazon.com/zh_cn/sdk-for-java/v1/developer-guide/examples-s3-buckets.html
*/
public interface OssClient{
/**
* Создать сегмент
* @param bucketName
*/
void createBucket(String bucketName);
/**
* Получить URL
* @param bucketName
* @param objectName
* @return
*/
String getObjectURL(String bucketName, String objectName);
/**
* Получить информацию об объекте хранения
* @param bucketName
* @param objectName
* @return
*/
S3Object getObjectInfo(String bucketName, String objectName);
/**
* Загрузить файлы
* @param bucketName
* @param objectName
* @param stream
* @param size
* @param contextType
* @return
* @throws IOException
*/
PutObjectResult putObject(String bucketName, String objectName, InputStream stream, long size, String contextType) throws IOException;
default PutObjectResult putObject(String bucketName, String objectName, InputStream stream) throws IOException{
return putObject(bucketName,objectName,stream, stream.available(), "application/octet-stream");
}
AmazonS3 getS3Client();
}
package com.oss.client;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.amazonaws.services.s3.model.PutObjectResult;
import com.amazonaws.services.s3.model.S3Object;
import lombok.RequiredArgsConstructor;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
/**
* s3 это соглашение
* S3 – это просто Storage Аббревиатура Service, то есть простая служба хранения.
* @author zdh
*/
@RequiredArgsConstructor
public class S3OssClient implements OssClient {
private final AmazonS3 amazonS3;
@Override
public void createBucket(String bucketName) {
if (!amazonS3.doesBucketExistV2(bucketName)) {
amazonS3.createBucket((bucketName));
}
}
@Override
public String getObjectURL(String bucketName, String objectName) {
URL url = amazonS3.getUrl(bucketName, objectName);
return url.toString();
}
@Override
public S3Object getObjectInfo(String bucketName, String objectName) {
return amazonS3.getObject(bucketName, objectName);
}
@Override
public PutObjectResult putObject(String bucketName, String objectName, InputStream stream, long size, String contextType) throws IOException {
ObjectMetadata objectMetadata = new ObjectMetadata();
objectMetadata.setContentLength(size);
objectMetadata.setContentType(contextType);
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, stream, objectMetadata);
putObjectRequest.getRequestClientOptions().setReadLimit(Long.valueOf(size).intValue() + 1);
return amazonS3.putObject(putObjectRequest);
}
@Override
public AmazonS3 getS3Client() {
return amazonS3;
}
}
package com.oss.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "oss")
@Data
public class OssProperties {
private boolean enable = true;
private String accessKey;
private String accessSecret;
/**
* endpoint Формат конфигурации:
* При доступе к OSS-сервисам через внешнюю сеть доступные OSS-ресурсы представляются в виде URL-адресов. Подробнее см. в правилах использования доменных имен для OSS-доступа. Структура URL OSS: [$Schema]://[$Bucket].[$Endpoint]/[$Object]
* . Например, ваш регион — Восточный Китай 1 (Ханчжоу), имя сегмента — examplebucket, а путь доступа к объекту — destfolder/example.txt.
* Адрес внешнего доступа: https://examplebucket.oss-cn-hangzhou.aliyuncs.com/destfolder/example.txt.
* https://help.aliyun.com/document_detail/375241.html
*/
private String endpoint;
/**
* refer com.amazonaws.regions.Regions;
* Облачный регион Alibaba Таблица соответствия
* https://help.aliyun.com/document_detail/31837.htm?spm=a2c4g.11186623.0.0.695178eb0nD6jp
*/
private String region;
private boolean pathStyleAccess = true;
package com.oss;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;
import com.oss.client.OssClient;
import com.oss.client.S3OssClient;
import com.oss.config.OssProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Objects;
import java.util.stream.Stream;
/**
* OSS-сервис Класс автоматической настройки
* @author zdh
*/
@Configuration
@EnableConfigurationProperties(OssProperties.class)
public class OssAutoConfiguration {
@Bean
@ConditionalOnMissingBean(S3OssClient.class)
public OssClient ossClient(AmazonS3 amazonS3) {
return new S3OssClient(amazonS3);
}
/**
* Справочная документация
* https://docs.aws.amazon.com/zh_cn/sdk-for-java/v1/developer-guide/credentials.html
* Выберите эту область
* https://docs.aws.amazon.com/zh_cn/sdk-for-java/v1/developer-guide/java-dg-region-selection.html
* @param ossProperties
* @return
*/
@Bean
@ConditionalOnMissingBean(AmazonS3.class)
@ConditionalOnProperty(prefix = "oss", name = "enable", havingValue = "true")
public AmazonS3 amazonS3(OssProperties ossProperties) {
long nullSize = Stream.<String>builder()
.add(ossProperties.getEndpoint())
.add(ossProperties.getAccessSecret())
.add(ossProperties.getAccessKey())
.build()
.filter(s -> Objects.isNull(s))
.count();
if (nullSize > 0) {
throw new RuntimeException("oss Ошибка конфигурации, проверьте");
}
AWSCredentials awsCredentials = new BasicAWSCredentials(ossProperties.getAccessKey(),
ossProperties.getAccessSecret());
AWSCredentialsProvider awsCredentialsProvider = new AWSStaticCredentialsProvider(awsCredentials);
return AmazonS3Client.builder()
.withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(ossProperties.getEndpoint(), ossProperties.getRegion()))
.withCredentials(awsCredentialsProvider)
.disableChunkedEncoding()
.withPathStyleAccessEnabled(ossProperties.isPathStyleAccess())
.build();
}
}
При упаковке вы можете удалить зависимость Lombok в стартовом проекте.
#Для minio конфигурация следующая
oss:
endpoint: http://минио-сервер IP:9000
access-key: admin
access-secret: admin123
enable: true
@Test
public void testCreateBucket(){
// инструмент быстрого доступа Spring, предоставленный hutool
OssClient ossClient = SpringUtil.getBean(OssClient.class);
ossClient.createBucket("sale");
}
@Test
public void testUploadImg() throws IOException {
// инструмент быстрого доступа Spring, предоставленный hutool
OssClient ossClient = SpringUtil.getBean(OssClient.class);
ossClient.putObject("sale","dhy.img",new FileInputStream("xpy.png"));
}
@Test
public void testgetImgUrl() throws IOException {
// инструмент быстрого доступа Spring, предоставленный hutool
OssClient ossClient = SpringUtil.getBean(OssClient.class);
String objectURL = ossClient.getObjectURL("sale", "dhy.img");
System.out.println(objectURL);
}