如何使用graphql-java上传文件?

EA *_*oft 5 java file-upload graphql-java

如果我使用graphql-java,我不知道如何上传文件,有人可以给我演示吗?我将不胜感激!

参考:https : //github.com/graphql-java-kickstart/graphql-java-tools/issues/240

我在springboot中通过使用graphql-java-kickstart graphql-java-tools尝试了一下,但是没有用

@Component
public class FilesUpload implements GraphQLMutationResolver {

    public Boolean testMultiFilesUpload(List<Part> parts, DataFetchingEnvironment env) {
        // get file parts from DataFetchingEnvironment, the parts parameter is not used
        List<Part> attchmentParts = env.getArgument("files");
        System.out.println(attchmentParts);
        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的架构

type Mutation {
    testSingleFileUpload(file: Upload): UploadResult
}
Run Code Online (Sandbox Code Playgroud)

我希望这个解析器可以打印attchmentParts,所以我可以得到文件的一部分。

EA *_*oft 11

  1. 在我们的模式中定义一个标量类型

    scalar Upload

    我们应该为上传配置 GraphQLScalarType,在下面使用它:

    @Configuration
    public class GraphqlConfig {
    
       @Bean
       public GraphQLScalarType uploadScalarDefine() {
          return ApolloScalars.Upload;
       } 
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 然后我们将为 testMultiFilesUpload 定义架构中的突变和 GraphQLMutationResolver

    type Mutation {
      testMultiFilesUpload(files: [Upload!]!): Boolean
    }
    
    Run Code Online (Sandbox Code Playgroud)

这是解析器:

public Boolean testMultiFilesUpload(List<Part> parts, DataFetchingEnvironment env) {
    // get file parts from DataFetchingEnvironment, the parts parameter is not use
    List<Part> 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;   
  }
}
Run Code Online (Sandbox Code Playgroud)
  1. 为 jackson 解串器配置javax.servlet.http.Part并将其注册到 ObjectMapper

    public class PartDeserializer extends JsonDeserializer<Part> {
    
      @Override
      public Part deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {         
         return null;
      }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    为什么我们返回null?因为List<Part> parts总是 null ,在解析器的方法中,从 DataFetchingEnvironment 中获取parts 参数;

    environment.getArgument("文件")

将其注册到 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;
}
Run Code Online (Sandbox Code Playgroud)
  1. 为了测试这一点,将以下表单数据(我们使用 Postman)发布到 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
Run Code Online (Sandbox Code Playgroud)

像这样:

记得选择表单数据选项 在此处输入图片说明

通过这个我们可以上传多个文件

  • @stereo 这个anwser已经有2年了,我不记得一些细节了,但我可以告诉你的是我们现在可以使用Netflix DGS Graphql框架:https://netflix.github.io/dgs/ 已经实现了文件使用 graphql 上传。您可以在这里找到文件上传文档:https://netflix.github.io/dgs/advanced/file-uploads/ (2认同)

And*_*son 7

主要的问题是,graphql-java-tools可能有问题,要做的字段映射的,包含基本不喜欢的类型的字段解析器ListStringIntegerBoolean,等...

我们通过创建我们自己的自定义标量来解决这个问题,它基本上类似于ApolloScalar.Upload. 但是Part我们没有返回type 的对象,而是返回我们自己的解析器类型FileUpload,其中包含 contentType asString和 inputStream as byte[],然后字段映射起作用,我们可以byte[]在解析器中读取。

首先,设置要在解析器中使用的新类型:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我们创建一个看起来很像的自定义标量ApolloScalars.Upload,但返回我们自己的解析器类型FileUpload

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

            @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");
            }
    });
}
Run Code Online (Sandbox Code Playgroud)

在解析器中,您现在可以从解析器参数中获取文件:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

在架构中,您将其声明为:

scalar FileUpload

type Mutation {
    uploadFile(fileUpload: FileUpload): Boolean
}
Run Code Online (Sandbox Code Playgroud)

如果它对您不起作用,请告诉我:)