Armazenamento de objetos OSS de nível empresarial

Este artigo explica principalmente a produção do Spring Boot Starter, um serviço de armazenamento de objetos OSS de nível empresarial, que pode ser usado imediatamente para capacitar o projeto. Com base no protocolo AmazonS3, é compatível com os serviços de armazenamento de objetos do mercado, como: Alibaba Cloud OSS, Tencent COS, Qiniu Cloud OSS, MINIO, etc.

O que é OSS
OSS (Object Storage Service), serviço de armazenamento de objetos, serviço de armazenamento de objetos é uma ferramenta que usa HTTP API para armazenar e recuperar objetos. É carregar os arquivos necessários ao sistema para o disco rígido da nuvem. O disco rígido da nuvem fornece uma série de serviços, como download, upload e visualização de arquivos. Ele possui recursos de versão, controle de permissão e gerenciamento do ciclo de vida dos dados. serviços e tecnologias podem ser referidos coletivamente como OSS

O uso de OSS em projetos
O armazenamento de objetos OSS é indispensável na maioria dos projetos atualmente, como mostra a figura abaixo.

insira a descrição da imagem aqui

  1. Projetos gerais usam serviços de armazenamento de objetos OSS, principalmente para controle de autoridade de gerenciamento centralizado de objetos, como imagens, arquivos e áudio, e gerenciamento do ciclo de vida dos dados, etc., fornecendo funções como upload, download, visualização e exclusão.
  2. Implante projetos de front-end por meio de OSS.

O que é Amazon S3

https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/userguide/Welcome.html

O Amazon Simple Storage Service (Amazon S3, Amazon Simple Storage Service) é um dos primeiros serviços de nuvem lançados pela AWS. Após anos de desenvolvimento, o protocolo S3 tornou-se o padrão na indústria de armazenamento de objetos.

  • Fornece uma interface unificada REST/SOAP para acessar uniformemente qualquer dado
  • Para S3, os dados armazenados nele são o nome do objeto (chave) e os dados (valor)
  • Ilimitado, um único arquivo pode ter até 5 TB e pode ser expandido dinamicamente.
  • alta velocidade. Até 3.500 solicitações PUT/COPY/POST/DELETE ou 5.500 solicitações GET/HEAD por segundo por bucket.
  • Capaz de controle de versão e autoridade
  • Capaz de gerenciar o ciclo de vida dos dados

Como um serviço de armazenamento de objetos, o S3 tem funções completas e é uma referência do setor. A maioria dos serviços de armazenamento de objetos OSS no mercado oferece suporte ao AmazonS3. Este artigo explica principalmente como implementar nosso próprio Spring Boot Starter com base no AmazonS3.

Alibaba Cloud OSS é compatível com S3.
insira a descrição da imagem aqui
Qiniu Cloud Object Storage é compatível com S3. Tencent .Minio
insira a descrição da imagem aqui
Cloud COS é compatível com S3 Por exemplo, hoje estamos usando o Alibaba Cloud OSS para conectar ao Alibaba Cloud OSS SDK e depois de amanhã estamos usando o Tencent COS para conectar ao Tencent Cloud COS. Por que não nos conectamos diretamente ao Amazon S3 para implementá-lo, então que não há necessidade de ajustar o código no futuro, basta ir para cada nuvem A configuração do servidor está bem.
insira a descrição da imagem aqui

insira a descrição da imagem aqui

Crie um projeto SpringBoot
Conforme mostrado na figura abaixo: Crie um projeto SpringBoot.

Nós o chamamos de oss-spring-boot-starter.
insira a descrição da imagem aqui
Conforme mostra a figura abaixo, a criação foi bem sucedida, vamos entrar no processo de produção.
insira a descrição da imagem aqui
Encontre as dependências de que precisamos
Abra o maven warehouse e procure por minio

Endereço: https://mvnrepository.com/
insira a descrição da imagem aqui
Aqui escolhemos a primeira, e após clicar nela escolhemos a versão 1.12.423 para demonstração.
insira a descrição da imagem aqui

<!-- https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-s3 -->
<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-java-sdk-s3</artifactId>
    <version>1.12.423</version>
</dependency>

Arquivo pom para este projeto

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.9</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.qing</groupId>
    <artifactId>oss-spring-boot-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>oss-spring-boot-starter</name>
    <description>Demo oss-spring-boot-starter</description>
    <properties>
        <java.version>1.8</java.version>
        <aws.version>1.12.423</aws.version>
        <hutool.version>5.8.5</hutool.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-s3 -->
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-java-sdk-s3</artifactId>
            <version>${aws.version}</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-core</artifactId>
            <version>${hutool.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>RELEASE</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

</project>

Escreva o
código OssProperties da seguinte maneira, e os comentários serão bem claros. @ConfigurationProperties relatado em vermelho, independentemente da porta dos fundos, será resolvido.

@Data: A anotação é lombok, que gera o método get set.

@ConfigurationProperties(prefix = "oss"): vincule as propriedades que começam com oss no arquivo de configuração a este objeto

Provavelmente se você quiser usar nosso jar, o arquivo de configuração dele tem essas configurações

oss.endpoint=xxx
oss.accessKey=xxx
oss.secretKey=xxx
/**
 * @Author JiaQIng
 * @Description Oss配置类
 * @ClassName OssProperties
 * @Date 2023/3/18 17:51
 **/
@Data
@ConfigurationProperties(prefix = "oss")
public class OssProperties {
    
    
    /**
     * 对象存储服务的URL
     */
    private String endpoint;

    /**
     * 区域
     */
    private String region;

    /**
     * true path-style nginx 反向代理和S3默认支持 pathStyle模式 {
    
    http://endpoint/bucketname}
     * false supports virtual-hosted-style 阿里云等需要配置为 virtual-hosted-style 模式{
    
    http://bucketname.endpoint}
     * 只是url的显示不一样
     */
    private Boolean pathStyleAccess = true;

    /**
     * Access key
     */
    private String accessKey;

    /**
     * Secret key
     */
    private String secretKey;

    /**
     * 最大线程数,默认:100
     */
    private Integer maxConnections = 100;
}

Crie uma interface OssTemplate
OssTemplate: interface de modelo oss, esta interface é principalmente uma interface para métodos de operação oss, definida como uma interface principalmente para atender ao princípio da extensibilidade, ou seja, outras pessoas usaram nosso pacote jar, e a implementação dessa interface pode personalizar operação relacionada.

O código é mostrado abaixo: alguns métodos para operações oss são definidos.

/**
 * @Author JiaQIng
 * @Description oss操作模板
 * @ClassName OssTemplate
 * @Date 2023/3/18 18:15
 **/
public interface OssTemplate {
    
    

    /**
     * 创建bucket
     * @param bucketName bucket名称
     */
    void createBucket(String bucketName);

    /**
     * 获取所有的bucket
     * @return
     */
    List<Bucket> getAllBuckets();

    /**
     * 通过bucket名称删除bucket
     * @param bucketName
     */
    void removeBucket(String bucketName);

    /**
     * 上传文件
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @param stream 文件流
     * @param contextType 文件类型
     * @throws Exception
     */
    void putObject(String bucketName, String objectName, InputStream stream, String contextType) throws Exception;

    /**
     * 上传文件
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @param stream 文件流
     * @throws Exception
     */
    void putObject(String bucketName, String objectName, InputStream stream) throws Exception;

    /**
     * 获取文件
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @return S3Object
     */
    S3Object getObject(String bucketName, String objectName);

    /**
     * 获取对象的url
     * @param bucketName
     * @param objectName
     * @param expires
     * @return
     */
    String getObjectURL(String bucketName, String objectName, Integer expires);

    /**
     * 通过bucketName和objectName删除对象
     * @param bucketName
     * @param objectName
     * @throws Exception
     */
    void removeObject(String bucketName, String objectName) throws Exception;

    /**
     * 根据文件前置查询文件
     * @param bucketName bucket名称
     * @param prefix 前缀
     * @param recursive 是否递归查询
     * @return S3ObjectSummary 列表
     */
    List<S3ObjectSummary> getAllObjectsByPrefix(String bucketName, String prefix, boolean recursive);
}

Crie a classe de implementação de OssTemplate
conforme a figura abaixo: implemente os métodos em OssTemplate e chame os métodos de AmazonS3JavaSDK.

AmazonS3 fornece muitos métodos, então não vou escrever todos eles aqui. Se a empresa precisar usá-los, basta escrever esses métodos e a expansão de acompanhamento está bem.

Endereço da interface AmazonS3: https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateBucket.html

Este tipo de explicação: é para implementar a interface OssTemplate e introduzir a interface correspondente chamada pelo cliente AmazonS3.

Explicação das anotações usadas:

@RequiredArgsConstructor: anotação de Lomnok, substituindo @Autowired.

@SneakyThrows: anotação de lomnok, lançando uma exceção.

/**
 * @Author JiaQIng
 * @Description OssTemplate的实现类
 * @ClassName OssTemplateImpl
 * @Date 2023/3/18 19:02
 **/
@RequiredArgsConstructor
public class OssTemplateImpl implements OssTemplate {
    
    

    private final AmazonS3 amazonS3;

    /**
     * 创建Bucket
     * AmazonS3:https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateBucket.html
     * @param bucketName bucket名称
     */
    @Override
    @SneakyThrows
    public void createBucket(String bucketName) {
    
    
        if ( !amazonS3.doesBucketExistV2(bucketName) ) {
    
    
            amazonS3.createBucket((bucketName));
        }
    }

    /**
     * 获取所有的buckets
     * AmazonS3:https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBuckets.html
     * @return
     */
    @Override
    @SneakyThrows
    public List<Bucket> getAllBuckets() {
    
    
        return amazonS3.listBuckets();
    }

    /**
     * 通过Bucket名称删除Bucket
     * AmazonS3:https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucket.html
     * @param bucketName
     */
    @Override
    @SneakyThrows
    public void removeBucket(String bucketName) {
    
    
        amazonS3.deleteBucket(bucketName);
    }

    /**
     * 上传对象
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @param stream 文件流
     * @param contextType 文件类型
     * AmazonS3:https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html
     */
    @Override
    @SneakyThrows
    public void putObject(String bucketName, String objectName, InputStream stream, String contextType) {
    
    
        putObject(bucketName, objectName, stream, stream.available(), contextType);
    }
    /**
     * 上传对象
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @param stream 文件流
     * AmazonS3:https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html
     */
    @Override
    @SneakyThrows
    public void putObject(String bucketName, String objectName, InputStream stream) {
    
    
        putObject(bucketName, objectName, stream, stream.available(), "application/octet-stream");
    }

    /**
     * 通过bucketName和objectName获取对象
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @return
     * AmazonS3:https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html
     */
    @Override
    @SneakyThrows
    public S3Object getObject(String bucketName, String objectName) {
    
    
        return amazonS3.getObject(bucketName, objectName);
    }

    /**
     * 获取对象的url
     * @param bucketName
     * @param objectName
     * @param expires
     * @return
     * AmazonS3:https://docs.aws.amazon.com/AmazonS3/latest/API/API_GeneratePresignedUrl.html
     */
    @Override
    @SneakyThrows
    public String getObjectURL(String bucketName, String objectName, Integer expires) {
    
    
        Date date = new Date();
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, expires);
        URL url = amazonS3.generatePresignedUrl(bucketName, objectName, calendar.getTime());
        return url.toString();
    }

    /**
     * 通过bucketName和objectName删除对象
     * @param bucketName
     * @param objectName
     * AmazonS3:https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObject.html
     */
    @Override
    @SneakyThrows
    public void removeObject(String bucketName, String objectName) {
    
    
        amazonS3.deleteObject(bucketName, objectName);
    }

    /**
     * 根据bucketName和prefix获取对象集合
     * @param bucketName bucket名称
     * @param prefix 前缀
     * @param recursive 是否递归查询
     * @return
     * AmazonS3:https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjects.html
     */
    @Override
    @SneakyThrows
    public List<S3ObjectSummary> getAllObjectsByPrefix(String bucketName, String prefix, boolean recursive) {
    
    
        ObjectListing objectListing = amazonS3.listObjects(bucketName, prefix);
        return objectListing.getObjectSummaries();
    }


    /**
     *
     * @param bucketName
     * @param objectName
     * @param stream
     * @param size
     * @param contextType
     * @return
     */
    @SneakyThrows
    private PutObjectResult putObject(String bucketName, String objectName, InputStream stream, long size,
                                     String contextType)  {
    
    

        byte[] bytes = IOUtils.toByteArray(stream);
        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentLength(size);
        objectMetadata.setContentType(contextType);
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        // 上传
        return amazonS3.putObject(bucketName, objectName, byteArrayInputStream, objectMetadata);

    }
}

Criar OssAutoConfiguration
insira a descrição da imagem aqui
OssAutoConfiguration: classe de configuração de montagem automática, os beans de montagem automáticos são AmazonS3 e OssTemplate

Anotações usadas:

@RequiredArgsConstructor: anotação de Lomnok, substituindo @Autowired.

@EnableConfigurationProperties(OssProperties.class): Ligue automaticamente nossa classe de configuração

@Bean: Bean declarativo.

@ConditionalOnMissingBean: Uma anotação para modificar o bean. Quando seu bean estiver registrado, registrar o mesmo tipo de bean não terá sucesso. Isso garantirá que haja apenas um bean, ou seja, apenas uma instância sua. Mais de um irá relatar um erro.

@ConditionalOnBean(AmazonS3.class): quando o bean fornecido existir, instancia o bean atual.

/**
 * @Author JiaQIng
 * @Description oss配置bean
 * @ClassName OssAConfiguration
 * @Date 2023/3/18 18:23
 **/
@Configuration
@RequiredArgsConstructor
@EnableConfigurationProperties(OssProperties.class)
public class OssAutoConfiguration {
    
    

    @Bean
    @ConditionalOnMissingBean
    public AmazonS3 ossClient(OssProperties ossProperties) {
    
    
        // 客户端配置,主要是全局的配置信息
        ClientConfiguration clientConfiguration = new ClientConfiguration();
        clientConfiguration.setMaxConnections(ossProperties.getMaxConnections());
        // url以及region配置
        AwsClientBuilder.EndpointConfiguration endpointConfiguration = new AwsClientBuilder.EndpointConfiguration(
                ossProperties.getEndpoint(), ossProperties.getRegion());
        // 凭证配置
        AWSCredentials awsCredentials = new BasicAWSCredentials(ossProperties.getAccessKey(),
                ossProperties.getSecretKey());
        AWSCredentialsProvider awsCredentialsProvider = new AWSStaticCredentialsProvider(awsCredentials);
        // build amazonS3Client客户端
        return AmazonS3Client.builder().withEndpointConfiguration(endpointConfiguration)
                .withClientConfiguration(clientConfiguration).withCredentials(awsCredentialsProvider)
                .disableChunkedEncoding().withPathStyleAccessEnabled(ossProperties.getPathStyleAccess()).build();
    }

    @Bean
    @ConditionalOnBean(AmazonS3.class)
    public OssTemplate ossTemplate(AmazonS3 amazonS3){
    
    
        return new OssTemplateImpl(amazonS3);
    }
}

Objeto ClientConfiguration
Configuração do cliente, principalmente informações de configuração global

Observe a figura abaixo, existem muitas configurações, algumas especificam valores padrão e outras não. Você pode acessar a documentação oficial do AmazonS3 para se familiarizar com as configurações relevantes e definir as informações de configuração que você precisa especificar.

Somente se você realmente entender o papel dessas configurações, poderá evitar bugs online. Os alunos interessados ​​podem dar uma olhada.
insira a descrição da imagem aqui
Crie nosso spring.factories
e adicione um novo pacote META-INF no diretório de recursos e crie um novo arquivo spring.factories abaixo.

Esta forma também é a personificação de "convenção é maior que configuração". Os alunos que leram o código-fonte do spring-boot devem conhecê-lo, então não vou explicá-lo aqui.

Como mostrado abaixo:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.qing.oss.OssAutoConfiguration

Execute a instalação e empacote-o em nosso depósito local.
Elimine a classe de inicialização e o arquivo de configuração do projeto springboot e elimine o pacote de teste.

O mais importante é matar o plugin spring-boot-maven do arquivo pom, ou a instalação reportará um erro.
insira a descrição da imagem aqui

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

Desta forma, um dos nossos oss-spring-boot-starter é concluído.
insira a descrição da imagem aqui
Execute a instalação e empacote-o em jar para nosso armazém local.
insira a descrição da imagem aqui
Vá para nosso warehouse local para ver nosso
insira a descrição da imagem aqui
teste oss-spring-boot-starter
Crie um projeto spring-boot como nosso projeto de teste
Aqui não demonstraremos como criar um projeto. Basta olhar para a figura abaixo.
insira a descrição da imagem aqui
Adicione nossa dependência oss-spring-boot-starter ao arquivo pom.
Adicione uma nova versão da configuração global.

<properties>
    <oss.version>0.0.1-SNAPSHOT</oss.version>
</properties>

Adicionar dependência oss-spring-boot-starter

<dependency>
    <groupId>com.qing</groupId>
    <artifactId>oss-spring-boot-starter</artifactId>
    <version>${oss.version}</version>
</dependency>

Depois de atualizar o maven, podemos ver que nossas dependências foram adicionadas.
insira a descrição da imagem aqui
Resolva o problema de empacotamento sem comentários
Pode-se descobrir que nossas dependências não possuem comentários e nem comentários Javadoc.

Adicione o seguinte plug-in no arquivo pom do nosso oss-string-boot-starter e instale-o novamente.

<build>
        <plugins>
            <!-- 在打好的jar包中保留javadoc注释,实际会另外生成一个xxxxx-sources.jar -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-source-plugin</artifactId>
                <executions>
                    <execution>
                        <id>attach-sources</id>
                        <goals>
                            <goal>jar</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

Atualize o maven em nosso projeto de teste para ver se ele foi anotado.
insira a descrição da imagem aqui
Adicione a configuração exigida pelo oss-spring-boot-starter ao arquivo de configuração
Preencha seu Aliyun, Tencent cos, Qiniuyun, minio e outras configurações aqui.

Abaixo vou te mostrar o Minio

oss.endpoint=xxx
oss.accessKey=xxx
oss.secretKey=xxx

Escreva o método de teste
Conforme mostrado na figura abaixo, escreva o método de teste e execute-o com sucesso.

@SpringBootTest
class TestOssSpringBpptStarterApplicationTests {
    
    
    @Autowired
    private OssTemplate ossTemplate;

    @Test
    void contextLoads() {
    
    
        ossTemplate.createBucket("oss02");
    }

}

insira a descrição da imagem aqui
Vá para o meu Minio para verificar e descobrir se o teste foi bem-sucedido.
insira a descrição da imagem aqui
Código-fonte: https://github.com/hujiaqing789/test-spring-boot-starter.git

Acho que você gosta

Origin blog.csdn.net/qq_38747892/article/details/130482311
Recomendado
Clasificación