Almacenamiento de objetos OSS de nivel empresarial

Este artículo explica principalmente la producción de Spring Boot Starter, un servicio de almacenamiento de objetos OSS de nivel empresarial, que se puede usar de forma inmediata para potenciar el proyecto. Basado en el protocolo AmazonS3, es compatible con los servicios de almacenamiento de objetos del mercado como: Alibaba Cloud OSS, Tencent COS, Qiniu Cloud OSS, MINIO, etc.

¿Qué es OSS?
OSS (Object Storage Service), servicio de almacenamiento de objetos, servicio de almacenamiento de objetos es una herramienta que utiliza API HTTP para almacenar y recuperar objetos. Es para cargar los archivos que necesita el sistema en el disco duro de la nube. El disco duro de la nube proporciona una serie de servicios, como descarga, carga y vista previa de archivos. Tiene capacidades de control de versiones, permisos y capacidades de gestión del ciclo de vida de los datos. Tales los servicios y tecnologías pueden denominarse colectivamente OSS

El uso de OSS en proyectos
El almacenamiento de objetos OSS es indispensable en la mayoría de los proyectos en la actualidad, como se muestra en la siguiente figura.

inserte la descripción de la imagen aquí

  1. Los proyectos generales utilizan los servicios de almacenamiento de objetos OSS, principalmente para el control de la autoridad de gestión centralizada de objetos como imágenes, archivos y audio, y la gestión del ciclo de vida de los datos, etc., proporcionando funciones como carga, descarga, vista previa y eliminación.
  2. Implemente proyectos front-end a través de OSS.

¿Qué es Amazon S3?

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

Amazon Simple Storage Service (Amazon S3, Amazon Simple Storage Service) es uno de los primeros servicios en la nube lanzados por AWS. Después de años de desarrollo, el protocolo S3 se ha convertido en el estándar en la industria del almacenamiento de objetos.

  • Proporciona una interfaz unificada REST/SOAP para acceder uniformemente a cualquier dato
  • Para S3, los datos almacenados en él son el nombre del objeto (clave) y los datos (valor)
  • Ilimitado, un solo archivo puede tener hasta 5 TB y se puede expandir dinámicamente.
  • alta velocidad. Hasta 3500 solicitudes PUT/COPY/POST/DELETE o 5500 GET/HEAD por segundo por depósito.
  • Capaz de control de versión y autoridad
  • Capaz de administrar el ciclo de vida de los datos

Como servicio de almacenamiento de objetos, S3 tiene funciones completas y es un punto de referencia en la industria. La mayoría de los servicios de almacenamiento de objetos OSS en el mercado son compatibles con Amazon S3. Este artículo explica principalmente cómo implementar nuestro propio Spring Boot Starter basado en Amazon S3.

Alibaba Cloud OSS es compatible con S3.
inserte la descripción de la imagen aquí
Qiniu Cloud Object Storage es compatible con S3. Tencent .Minio
inserte la descripción de la imagen aquí
Cloud COS es compatible con S3 Por ejemplo, hoy estamos usando Alibaba Cloud OSS para conectarnos a Alibaba Cloud OSS SDK, y pasado mañana estamos usando Tencent COS para conectarnos a Tencent Cloud COS. ¿Por qué no nos conectamos directamente a Amazon S3 para implementarlo? que no hay necesidad de ajustar el código en el futuro, solo ve a cada nube La configuración del servidor está bien.
inserte la descripción de la imagen aquí

inserte la descripción de la imagen aquí

Cree un proyecto SpringBoot
Como se muestra en la siguiente figura: Cree un proyecto SpringBoot.

Lo llamamos oss-spring-boot-starter.
inserte la descripción de la imagen aquí
Como se muestra en la figura a continuación, la creación es exitosa, ingresemos al proceso de producción.
inserte la descripción de la imagen aquí
Encuentra las dependencias que necesitamos
Abre el almacén de maven y busca minio

Dirección: https://mvnrepository.com/
inserte la descripción de la imagen aquí
Aquí elegimos el primero, y luego de hacer clic, elegimos la versión 1.12.423 para una demostración.
inserte la descripción de la imagen aquí

<!-- 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>

Archivo pom para este proyecto

<?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>

Escriba el
código OssProperties de la siguiente manera, y los comentarios son muy claros. @ConfigurationProperties informó en rojo, independientemente de la puerta trasera, se resolverá.

@Data: la anotación es lombok, que genera el método get set.

@ConfigurationProperties(prefix = "oss"): vincula las propiedades que comienzan con oss en el archivo de configuración a este objeto

Probablemente si quieres usar nuestro jar, su archivo de configuración tiene estas configuraciones

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;
}

Cree una interfaz OssTemplate
OssTemplate: interfaz de plantilla oss, esta interfaz es principalmente una interfaz para métodos de operación oss, definida como una interfaz principalmente para cumplir con el principio de extensibilidad, es decir, otras personas han usado nuestro paquete jar, e implementar esta interfaz puede personalizar operación relacionada.

El código se muestra a continuación: se definen algunos métodos para las operaciones de oss.

/**
 * @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);
}

Cree la clase de implementación de OssTemplate
como se muestra en la siguiente figura: implemente los métodos en OssTemplate y llame a los métodos de AmazonS3JavaSDK.

AmazonS3 proporciona muchos métodos, por lo que no los escribiré todos aquí. Si la empresa necesita usarlos, solo escriba esos métodos y la expansión de seguimiento está bien.

Dirección de interfaz de AmazonS3: https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateBucket.html

Este tipo de explicación: es implementar la interfaz OssTemplate e introducir la interfaz correspondiente llamada por el cliente AmazonS3.

Explicación de las anotaciones utilizadas:

@RequiredArgsConstructor: anotación de Lomnok, reemplazando @Autowired.

@SneakyThrows: anotación de lomnok, lanzando una excepción.

/**
 * @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);

    }
}

Crear OssAutoConfiguration
inserte la descripción de la imagen aquí
OssAutoConfiguration: clase de configuración de ensamblaje automático, los beans de ensamblaje automático son AmazonS3 y OssTemplate

Anotaciones utilizadas:

@RequiredArgsConstructor: anotación de Lomnok, reemplazando @Autowired.

@EnableConfigurationProperties(OssProperties.class): Conectar automáticamente nuestra clase de configuración

@Bean: frijol declarativo.

@ConditionalOnMissingBean: una anotación para modificar el bean. Cuando su bean está registrado, el registro del mismo tipo de bean no tendrá éxito. Se asegurará de que solo haya un bean, es decir, solo haya una instancia de usted. Más de uno reportará un error.

@ConditionalOnBean(AmazonS3.class): cuando existe el bean dado, crea una instancia del bean actual.

/**
 * @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
Configuración del cliente, principalmente información de configuración global

Mire la figura a continuación, hay muchas configuraciones, algunas especifican valores predeterminados y otras no. Puede ir a la documentación oficial de AmazonS3 para familiarizarse con las configuraciones relevantes y configurar la información de configuración que necesita especificar.

Solo si realmente comprende el papel de esas configuraciones puede evitar errores en línea. Los estudiantes interesados ​​pueden echar un vistazo.
inserte la descripción de la imagen aquí
Cree nuestro spring.factories
y agregue un nuevo paquete META-INF en el directorio de recursos, y cree un nuevo archivo spring.factories a continuación.

Esta forma es también la encarnación de "la convención es mayor que la configuración". Los estudiantes que hayan leído el código fuente de Spring-Boot deberían conocerlo, así que no se lo explicaré aquí.

Como se muestra abajo:

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

Ejecute install y empaquetelo en nuestro almacén local.Elimine
la clase de inicio y el archivo de configuración del proyecto springboot, y elimine el paquete Test.

Lo más importante es eliminar el complemento spring-boot-maven del archivo pom, o la instalación informará un error.
inserte la descripción de la imagen aquí

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

De esta forma, se completa uno de nuestros oss-spring-boot-starter.
inserte la descripción de la imagen aquí
Ejecute la instalación y empáquelo en un contenedor en nuestro almacén local.
inserte la descripción de la imagen aquí
Vaya a nuestro almacén local para ver nuestra
inserte la descripción de la imagen aquí
prueba oss-spring-boot-starter
. Cree un proyecto spring-boot como nuestro proyecto de prueba.
Aquí no demostraremos cómo crear un proyecto. Solo mire la imagen a continuación.
inserte la descripción de la imagen aquí
Agregue nuestra dependencia oss-spring-boot-starter al archivo pom.
Agregue una nueva versión de la configuración global.

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

Agregar dependencia oss-spring-boot-starter

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

Después de actualizar maven, podemos ver que se agregaron nuestras dependencias.
inserte la descripción de la imagen aquí
Resolver el problema del empaquetado sin comentarios
Se puede encontrar que nuestras dependencias no tienen comentarios ni comentarios de Javadoc.

Agregue el siguiente complemento en el archivo pom de nuestro oss-string-boot-starter e instálelo nuevamente.

<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>

Actualice maven en nuestro proyecto de prueba para ver que se ha anotado.
inserte la descripción de la imagen aquí
Agregue la configuración requerida por oss-spring-boot-starter al archivo de configuración
Complete su Aliyun, Tencent cos, Qiniuyun, minio y otras configuraciones aquí.

A continuación les mostraré Minio

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

Escriba el método de prueba
Como se muestra en la figura a continuación, escriba el método de prueba y ejecútelo con éxito.

@SpringBootTest
class TestOssSpringBpptStarterApplicationTests {
    
    
    @Autowired
    private OssTemplate ossTemplate;

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

}

inserte la descripción de la imagen aquí
Vaya a mi Minio para verificar y ver si la prueba es exitosa.
inserte la descripción de la imagen aquí
Código fuente: https://github.com/hujiaqing789/test-spring-boot-starter.git

Supongo que te gusta

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