Cargue el archivo a GCS, cree una URL que caduque usando Spring Cloud

Cargue el archivo a GCS, acceda con la URL que caduca usando Spring Cloud

Si desea cargar un archivo en Google Cloud Storage (GCS), dentro o fuera de GCP, y acceder al archivo cargado con una URL que caduca, esta es la publicación para usted.

Utilizaremos la biblioteca Spring Boot Reactive Webflux junto con las bibliotecas Spring Cloud para acceder a Google Cloud Storage.

Crearemos un Bucket y una clave privada para acceder al Bucket. Luego usamos esta clave para acceder al depósito desde fuera del GCP.

Implementación

Parte 1: crear el depósito, descargar la clave de la cuenta de servicio

Inicie sesión en su consola de GCP. Abra Google Shell y cree un depósito.

 gsutil mb gs: // some-bucket

Después de asegurarse de que se crea el depósito, vaya a la sección Cuenta de servicio.

Busque la cuenta de servicio asociada con el depósito recién creado.

Agregar una nueva clave:

La clave se descargará automáticamente en el navegador.

El contenido del json se verá así.

 {
"tipo" : "cuenta_servicio" ,
"project_id" : "alguna cuenta-gcp-01-7f11684e7047" ,
"private_key_id" : "..." ,
"clave_privada" : "..." ,
"client_email" : "someaccount-gcp-01-7f11684e7047@someaccount-gcp-01-7f11684e7047.iam.gserviceaccount.com" ,
"client_id" : "..." ,
"auth_uri" : "https://accounts.google.com/o/oauth2/auth" ,
"token_uri" : "https://oauth2.googleapis.com/token" ,
"auth_provider_x509_cert_url" : "https://www.googleapis.com/oauth2/v1/certs" ,
"client_x509_cert_url" : "https://www.googleapis.com/robot/v1/metadata/x509/someaccount-gcp-01-7f11684e7047%40someaccount-gcp-01-7f11684e7047.iam.gserviceaccount.com"
}

Parte 2: Cree una aplicación Spring Boot

pom.xml

 xml versión = "1.0" codificación = "UTF-8" ?>
< proyecto 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>
< padre >
< groupId > org.springframework.boot
groupId>
< artifactId > spring-boot-starter-parent
artifactId>
< versión > 2.3.5.RELEASE
versión>
<ruta relativa />

padre>
< groupId > com.example
groupId>
< artifactId > springboot-gcs-firmado-url
artifactId>
< versión > 0.0.1-SNAPSHOT
versión>
< nombre > springboot-gcs -igned-url
nombre>
< descripción > Para cargar un documento en GCS y crear una URL firmada a partir de él
descripción>
 < propiedades >
< versión java > 1.8 java.version>
< spring-cloud.version > Hoxton.SR9 spring-cloud.version>
propiedades>
 < dependencias >
< dependencia >
< groupId > org.springframework.boot groupId>
< artifactId > spring-boot-starter-webflux artifactId>
dependencia>
< dependencia >
< groupId > org.springframework.cloud groupId>
< artifactId > spring-cloud-gcp-starter-storage artifactId>
dependencia>
 < dependencia >
< groupId > org.springframework.boot groupId>
< artifactId > prueba de arranque de arranque de primavera artifactId>
prueba de < alcance > alcance>
< exclusiones >
< exclusión >
< groupId > org.junit.vintage groupId>
< artifactId > motor-antiguo-junit artifactId>
exclusión>
exclusiones>
dependencia>
< dependencia >
< groupId > io.projectreactor groupId>
< artifactId > prueba-reactor artifactId>
prueba de < alcance > alcance>
dependencia>
< dependencia >
< groupId > org.projectlombok groupId>
< artifactId > lombok artifactId>
dependencia>
dependencias>
 < gestión de dependencias >
< dependencias >
< dependencia >
< groupId > org.springframework.cloud groupId>
< artifactId > dependencias de Spring-Cloud artifactId>
< versión > $ {spring-cloud.version} versión>
< tipo > pom tipo>
< alcance > importación alcance>
dependencia>
dependencias>
gestión de dependencias>
 < construir >
< complementos >
< complemento >
< groupId > org.springframework.boot groupId>
< artifactId > plugin de spring-boot-maven artifactId>
complemento>
complementos>
construir>
 proyecto>

La biblioteca de claves aquí es:

 spring-cloud-gcp-starter-storage

Cree el archivo key.json en la carpeta de recursos y agregue el contenido del archivo descargado en el navegador en la Parte 1.

Dile a las bibliotecas de GCP que carguen las credenciales de key.json de esta manera:

 spring.cloud.gcp.credentials.location = classpath: key.json

Cree StorageController.

 @RestController
@ Slf4j
class StorageController {

@Getter (AccessLevel. PROTEGIDO )
@Setter (AccessLevel. PROTEGIDO )
@Autowired
almacenamiento de almacenamiento privado ;

@Value ( "nombre del depósito" )
String bucketName ;
@Value ( "subdirectorio" )
Subdirectorio de cadena;

@PostMapping (valor = "/ upload" , consumes = MediaType. MULTIPART_FORM_DATA_VALUE )
público mono uploadFile (@RequestPart ( "archivo" ) FilePart filePart) {
// Convierte el archivo en una matriz de bytes
byte final [] byteArray = convertToByteArray (filePart);

// Prepara el blobId
// BlobId es una combinación de bucketName + subdirectiory (opcional) + fileName
BlobId final blobId = constructBlobId (nombre del cubo , subdirectorio , parte del archivo nombre del archivo ());

volver Mono. solo (blobId)
// Crea el blobInfo
.map (bId -> BlobInfo. newBuilder (blobId)
.setContentType ( "texto / sin formato" )
.construir())
// Sube el blob a GCS
.doOnNext (blobInfo -> getStorage (). create (blobInfo, byteArray))
// Cree una URL de "estilo de ruta" firmada para acceder al Blob recién creado
// Establezca la caducidad de la URL en 10 minutos
.map (blobInfo -> createSignedPathStyleUrl (blobInfo, 10, TimeUnit. MINUTES ));
}

URL privada createSignedPathStyleUrl (BlobInfo blobInfo,
int duración, TimeUnit timeUnit) {
return getStorage ()
.signUrl (blobInfo, duración, timeUnit, Storage.SignUrlOption. withPathStyle ());
}

/ **
* Construir ID de blob
*
*
@param bucketName
* @param subdirectorio opcional
*
@param fileName
* @return
* /
private BlobId constructBlobId (String bucketName, subdirectorio @Nullable String,
String fileName) {
volver Opcional. ofNullable (subdirectorio)
.map (s -> BlobId. de (bucketName, subdirectory + "/" + fileName))
.oElse (BlobId. de (nombreCubo, nombreArchivo));
}

/ **
* Aquí, convertimos el archivo a una matriz de bytes para enviarlo a las bibliotecas GCS
*
*
@param filePart Archivo que se utilizará
*
@return Byte Array con todo el contenido del archivo
* /
@SneakyThrows
byte privado [] convertToByteArray (FilePart filePart) {
try (ByteArrayOutputStream bos = new ByteArrayOutputStream ()) {
filePart.content ()
.subscribe (dataBuffer -> {
byte [] bytes = nuevo byte [dataBuffer.readableByteCount ()];
log .trace ( "recuento de bytes legibles:" + dataBuffer.readableByteCount ());
dataBuffer.read (bytes);
DataBufferUtils. liberación (dataBuffer);
prueba {
bos.write (bytes);
} captura (IOException e) {
log .error ( "error de cuerpo de solicitud de lectura ..." , e);
}
});

return bos.toByteArray ();
}
}

}

Analicemos el código anterior y entendamos cada parte.

Primero, convertimos el archivo FilePart en una matriz de bytes.

 / **
* Aquí, convertimos el archivo a una matriz de bytes para enviarlo a las bibliotecas GCS
*
*
@param filePart Archivo que se utilizará
*
@return Byte Array con todo el contenido del archivo
* /
@SneakyThrows
byte privado [] convertToByteArray (FilePart filePart) {
try (ByteArrayOutputStream bos = new ByteArrayOutputStream ()) {
filePart.content ()
.subscribe (dataBuffer -> {
byte [] bytes = nuevo byte [dataBuffer.readableByteCount ()];
log .trace ( "recuento de bytes legibles:" + dataBuffer.readableByteCount ());
dataBuffer.read (bytes);
DataBufferUtils. liberación (dataBuffer);
prueba {
bos.write (bytes);
} captura (IOException e) {
log .error ( "error de cuerpo de solicitud de lectura ..." , e);
}
});

return bos.toByteArray ();
}
}

Luego, construimos el BlobId.

 / **
* Construir ID de blob
*
*
@param bucketName
* @param subdirectorio opcional
*
@param fileName
* @return
* /
private BlobId constructBlobId (String bucketName, subdirectorio @Nullable String,
String fileName) {
volver Opcional. ofNullable (subdirectorio)
.map (s -> BlobId. de (bucketName, subdirectory + "/" + fileName))
.oElse (BlobId. de (nombreCubo, nombreArchivo));
}

Este BlobId se usa para crear un BlobInfo. Esta BlobInfo se usa para cargar el archivo en GCS.

 Mononucleosis infecciosa. solo (blobId)
// Crea el blobInfo
.map (bId -> BlobInfo. newBuilder (blobId)
.setContentType ( "texto / sin formato" )
.construir())
// Sube el blob a GCS
.doOnNext (blobInfo -> getStorage (). create (blobInfo, byteArray))
// Cree una URL de "estilo de ruta" firmada para acceder al Blob recién creado
// Establezca la caducidad de la URL en 10 minutos
.map (blobInfo -> createSignedPathStyleUrl (blobInfo, 10, TimeUnit. MINUTES ));

Luego procedemos a crear una URL con vencimiento establecido.

 URL privada createSignedPathStyleUrl (BlobInfo blobInfo,
int duración, TimeUnit timeUnit) {
return getStorage ()
.signUrl (blobInfo, duración, timeUnit, Storage.SignUrlOption. withPathStyle () );
}

Nota: Estamos creando una URL usando "Estilo de ruta".

 Storage.SignUrlOption. withPathStyle ()

Genera una URL de estilo de ruta, que coloca el nombre del depósito en la parte de la ruta de la URL en lugar de en el nombre de host, por ejemplo, ' https: //storage.googleapis.com/mybucket / ...' .

Alternativamente, puede usar otros estilos como Estilo alojado virtual, que agrega el depósito a la parte del host del URI en lugar de la ruta, por ejemplo, ' https: //mybucket.storage.googleapis.com / ...'

Finalmente, agregue las siguientes propiedades en application.properties

 bucketname = bucketName 
subdirectorio
= medios
spring.cloud.gcp.credentials.location
= classpath: key.json

La estructura del paquete se verá así.

Ahora podemos ejecutar la aplicación y ejecutar el siguiente curl.

 curl - ubicación - solicitud POST ' http: // localhost: 8080 / upload' \
- formulario 'file=@/Users/Sample.txt'

Obtendrá una URL de "Estilo de ruta".

 https://storage.googleapis.com/some-bucket/media/ad7313fc-0c54-4de4-9371-e3990bd2f7b4?GoogleAccessId=sa-gcs-someaccount@some-project.iam.gserviceaccount.com&Expires=1605773822&Signature=FwQjidH9lryP9UjnKMixOsKVzksowirRIYNnthbcL%2FyVmQ8DkLvBXhMGoXys3qAVAuYQAPHEnl2KvetB% 2FyVwF5kdHR4o3UeB3AyGvL1zJRjNq2Ymf% 2F% 2FTOue3bBmZJ6pal4bpxwryWECIzxhJm8CCnAZ1d6TIZtcoU7SzJBILlLwzGTT7n% 2FOFthWdbvA7mjMKw% 2FG% 2BnlQA8Ltr4mlTIBpfCsmw5Hl2jm% 2FbI8zaOJc7% 2BtpWhGTdiZww3hgjpEqIZe% 2F2r9ZRDQRDPgEntZSymoV3xuI1WBAheYkY0ov7QbRrWi9eH8vGjnBRmwT7znUmS9rj3nUwVKsKfCRziCsOf3jdgw% 3D% 3D

Pegue esto en el navegador y podrá descargar el archivo.

Espere 10 minutos para que la URL caduque e intente acceder a la URL nuevamente. Recibirá un error.

Puedes encontrar el proyecto completo en GitHub aquí .


Subir archivo a GCS, crear URL que caduca usando Spring Cloud se publicó originalmente en Google Cloud - Community on Medium, donde las personas continúan la conversación resaltando y respondiendo a esta historia.