Saltar al contenido

¿Cómo subir archivos con graphql-java?

Comprende el código correctamente previamente a utilizarlo a tu proyecto y si tquieres aportar algo puedes dejarlo en la sección de comentarios.

Solución:

  1. definir un tipo escalar en nuestro esquema

    scalar Upload

    y debemos configurar GraphQLScalarType para cargar, use esto a continuación:

    @Configuration
    public class GraphqlConfig 
    
       @Bean
       public GraphQLScalarType uploadScalarDefine() 
          return ApolloScalars.Upload;
        
    
    
  2. luego definiríamos una mutación en el esquema y un GraphQLMutationResolver para testMultiFilesUpload

    type Mutation 
      testMultiFilesUpload(files: [Upload!]!): Boolean
    
    

aquí está Resolver:

public Boolean testMultiFilesUpload(List parts, DataFetchingEnvironment env) 
    // get file parts from DataFetchingEnvironment, the parts parameter is not use
    List attachmentParts = env.getArgument("files");
    int i = 1;
    for (Part part : attachmentParts) 
      String uploadName = "copy" + i;
      try 
        part.write("your path:" + uploadName);
       catch (IOException e) 
        e.printStackTrace();
      
      i++;
    
    return true;   
  
}
  1. configurar un deserializador jackson para javax.servlet.http.Part y registrarlo en ObjectMapper

    public class PartDeserializer extends JsonDeserializer 
    
      @Override
      public Part deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException          
         return null;
      
    
    

    por qué regresamos null? porque el List parts siempre null , En el método del resolutor, obtenga el argumento de las partes del DataFetchingEnvironment;

    environment.getArgument (“archivos”)

regístrelo en ObjectMapper:

@Bean
public ObjectMapper objectMapper() 
  ObjectMapper objectMapper = new ObjectMapper();
  objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
  SimpleModule module = new SimpleModule();
  module.addDeserializer(Part.class, new PartDeserializer());
  objectMapper.registerModule(module);
  return objectMapper;

  1. Para probar esto, publique los siguientes datos del formulario (usamos Postman) en el punto final de GraphQL
operations

 "query": "mutation($files: [Upload!]!) testMultiFilesUpload(files:$files)", "variables": "files": [null,null]  

map

 "file0": ["variables.files.0"] , "file1":["variables.files.1"]

file0

your file

file1

your file

como esto:

recuerde seleccionar la opción de datos de formulario
ingrese la descripción de la imagen aquí

a través de esto podemos subir varios archivos

El principal problema es que graphql-java-tools puede tener problemas para hacer el mapeo de campos para los resolutores que contienen campos de tipos no básicos como List, String, Integer, Boolean, etc …

Resolvimos este problema simplemente creando nuestro propio escalar personalizado que es básicamente como ApolloScalar.Upload. Pero en lugar de devolver un objeto del tipo Part, devolvemos nuestro propio tipo de resolución FileUpload que contiene el contentType como String y el inputStream como byte[], entonces el mapeo de campo funciona y podemos leer el byte[] dentro del resolutor.

Primero, configure el nuevo tipo que se usará en el resolutor:

public class FileUpload 
    private String contentType;
    private byte[] content;

    public FileUpload(String contentType, byte[] content) 
        this.contentType = contentType;
        this.content = content;
    

    public String getContentType() 
        return contentType;
    

    public byte[] getContent() 
        return content;
    

Luego creamos un escalar personalizado que se parece mucho a ApolloScalars.Upload, pero devuelve nuestro propio tipo de resolución FileUpload:

public class MyScalars 
    public static final GraphQLScalarType FileUpload = new GraphQLScalarType(
        "FileUpload",
        "A file part in a multipart request",
        new Coercing() 

            @Override
            public Void serialize(Object dataFetcherResult) 
                throw new CoercingSerializeException("Upload is an input-only type");
            

            @Override
            public FileUpload parseValue(Object input) 
                if (input instanceof Part) 
                    Part part = (Part) input;
                    try 
                        String contentType = part.getContentType();
                        byte[] content = new byte[part.getInputStream().available()];
                        part.delete();
                        return new FileUpload(contentType, content);

                     catch (IOException e) 
                        throw new CoercingParseValueException("Couldn't read content of the uploaded file");
                    
                 else if (null == input) 
                    return null;
                 else 
                    throw new CoercingParseValueException(
                            "Expected type " + Part.class.getName() + " but was " + input.getClass().getName());
                
            

            @Override
            public FileUpload parseLiteral(Object input) 
                throw new CoercingParseLiteralException(
                        "Must use variables to specify Upload values");
            
    );

En el resolutor, ahora podrá obtener el archivo de los argumentos del resolutor:

public class FileUploadResolver implements GraphQLMutationResolver 

    public Boolean uploadFile(FileUpload fileUpload) 

        String fileContentType = fileUpload.getContentType();
        byte[] fileContent = fileUpload.getContent();

        // Do something in order to persist the file :)


        return true;
    

En el esquema, lo declaras como:

scalar FileUpload

type Mutation 
    uploadFile(fileUpload: FileUpload): Boolean

Avísame si no te funciona 🙂

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *