首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何用graphql上传文件?

如何用graphql上传文件?
EN

Stack Overflow用户
提问于 2019-08-06 08:49:48
回答 4查看 10.1K关注 0票数 6

如果我使用graphql,我无法找到如何上传文件,有人能给我演示一下吗?我会很感激的!

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

我用graphql-java-kickstart graphql-java-tools在springboot中尝试过,但是它没有工作。

代码语言:javascript
复制
@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;
    }
}

这是我的模式

代码语言:javascript
复制
type Mutation {
    testSingleFileUpload(file: Upload): UploadResult
}

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

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2019-08-08 02:20:51

  1. 在模式中定义标量类型 scalar Upload 我们应该将GraphQLScalarType配置为上传,使用如下所示: @Configuration公共类GraphqlConfig { @Bean公共GraphQLScalarType uploadScalarDefine() {返回ApolloScalars.Upload;}
  2. 然后我们将在模式中定义一个突变,并为GraphQLMutationResolver定义一个testMultiFilesUpload。 类型突变{testMultiFilesUpload(文件:上载!!):布尔}

这是Resolver:

代码语言:javascript
复制
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;   
  }
}
  1. javax.servlet.http.Part配置杰克逊反序列化器并将其注册到ObjectMapper 公共类PartDeserializer扩展JsonDeserializer {@覆盖公共部分反序列化(JsonParser p,DeserializationContext ctxt)抛出IOException,JsonProcessingException {返回null;} 为什么我们返回null?因为List<Part> parts总是null,所以在解析器的方法中,从DataFetchingEnvironment获取parts参数; Environment.getArgument(“文件”)

将其注册到ObjectMapper:

代码语言:javascript
复制
@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. 为了测试这一点,将以下表单数据(我们使用Postman)发布到GraphQL端点

操作{“查询”:“突变($files: Upload!!) {testMultiFilesUpload(文件:$文件)}”,“变量”:{“文件”:null }映射{ " file0 ":"variables.files.0“,”file1“:”variables.file.1“}file0文件file1文件

就像这样:

请记住选择窗体数据选项。

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

票数 13
EN

Stack Overflow用户

发布于 2019-10-24 14:58:42

主要的问题是,graphql-java-tools可能有一些问题,需要为包含非基本类型的字段(如ListStringIntegerBoolean等)的解析器进行字段映射。

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

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

代码语言:javascript
复制
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;
    }
}

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

代码语言:javascript
复制
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");
            }
    });
}

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

代码语言:javascript
复制
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;
    }
}

在模式中,您可以声明如下:

代码语言:javascript
复制
scalar FileUpload

type Mutation {
    uploadFile(fileUpload: FileUpload): Boolean
}

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

票数 9
EN

Stack Overflow用户

发布于 2020-05-14 21:04:50

为了添加到上面的答案中,对于任何像我这样可以用GraphQLSchemaGenerator和模式优先方法找到0个文件上传示例的人,您必须创建一个TypeMapper并将其添加到您的GraphQLSchemaGenerator中:

代码语言:javascript
复制
public class FileUploadMapper implements TypeMapper {

  @Override
  public GraphQLOutputType toGraphQLType(
      final AnnotatedType javaType, final OperationMapper operationMapper,
      final Set<Class<? extends TypeMapper>> mappersToSkip, final BuildContext buildContext) {
    return MyScalars.FileUpload;
  }

  @Override
  public GraphQLInputType toGraphQLInputType(
      final AnnotatedType javaType, final OperationMapper operationMapper,
      final Set<Class<? extends TypeMapper>> mappersToSkip, final BuildContext buildContext) {
    return MyScalars.FileUpload;
  }

  @Override
  public boolean supports(final AnnotatedType type) {
     return type.getType().equals(FileUpload.class); //class of your fileUpload POJO from the previous answer
  }
}

然后在GraphQL @配置文件中构建GraphQLSchema:

代码语言:javascript
复制
public GraphQLSchema schema(GraphQLSchemaGenerator schemaGenerator) {
    return schemaGenerator
        .withTypeMappers(new FileUploadMapper()) //add this line
        .generate();
  }

然后在你的变异解析器中

代码语言:javascript
复制
  @GraphQLMutation(name = "fileUpload")
  public void fileUpload(      
      @GraphQLArgument(name = "file") FileUpload fileUpload //type here must be the POJO.class referenced in your TypeMapper
  ) {
    //do something with the byte[] from fileUpload.getContent();
    return;
  }
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57372259

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档