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
在我们的模式中定义一个标量类型
scalar Upload
我们应该为上传配置 GraphQLScalarType,在下面使用它:
@Configuration
public class GraphqlConfig {
@Bean
public GraphQLScalarType uploadScalarDefine() {
return ApolloScalars.Upload;
}
}
Run Code Online (Sandbox Code Playgroud)然后我们将为 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)
为 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)
Run Code Online (Sandbox Code Playgroud)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
像这样:
通过这个我们可以上传多个文件
主要的问题是,graphql-java-tools可能有问题,要做的字段映射的,包含基本不喜欢的类型的字段解析器List,String,Integer,Boolean,等...
我们通过创建我们自己的自定义标量来解决这个问题,它基本上类似于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)
如果它对您不起作用,请告诉我:)