Graphql 工具:将实体类型映射到 graphql 类型

Graphql Tools: Map entity type to graphql type

我在 spring 应用程序中使用 graphql java 工具。我有一个这样的实体:

@Entity
data class Image(
        @Id
        @GeneratedValue(strategy = GenerationType.SEQUENCE)
        @Column(nullable = false)
        val id: Long = 0
) {
    @Lob
    @Column(nullable = false)
    var image: Blob? = null
}

并且在 GraphQL 模式中我想要一个不同的类型:

type Image {
    id: ID!
    image: String!
}   

当然,由于架构解析异常,因此无法启动。 所以我认为一定有可能在模式解析之间放置一些东西来实现从 BlobString.

的映射

这在某种程度上可能吗?

@Bean
fun schemaParserDictionary(): SchemaParserDictionary {
    return SchemaParserDictionary()
}

编辑

抱歉,它不会给出架构解析异常。它只会将字节放入一个字符串中。但是我不能使用那个字符串来创建图像。

澄清

抱歉,我想我的问题不够清楚。我不需要知道如何将 blob 转换为字符串。有非常简单的解决方案。例如,我可以使用一个简单的 API 函数将字节码转换为 base64:

val base64 = Base64.getEncoder().encodeToString(byteCode)

我想问的是如何 "tell" graphql 模式解析器对特定字段使用 "custom" 转换。因此,当我的实体对象具有数据类型为 blob 的字段 image 时,graphql 会自动将其转换为 string。但是字符串不包含我需要的内容。所以我想为那个特定的领域使用自定义解析/映射/转换/任何东西。当然,我也可以通过引入另一个我没有存储在数据库中的字段来轻松解决这个问题:

@Entity
data class Image(
        @Id
        @GeneratedValue(strategy = GenerationType.SEQUENCE)
        @Column(nullable = false)
        val id: Long = 0
) {
    @Lob
    @Column(nullable = false)
    var image: Blob? = null

    @Transient
    var base64: String = ""
}

但我通过 graphql 使其可查询 api:

type Image {
    id: ID!
    image: String!
    base64: String!
}

type Images {
    images: [Image!]!
    totalCount: Int!
}

type Query {
    getImages: Images!
}

并在我的控制器中设置它:

private fun getImages(): Images {
    var images: List<Image> = repository.findTop1000()

    images.forEach {
        it.base64 = Base64.getEncoder().encodeToString(it.image)

        queue.offer(it)
    }
}

但如果我可以告诉 graphql 模式解析器这样做会更清晰。

让我们从头检查一下。我们知道 BLOB 是 Binary Large Object 的首字母缩写,用于存储超过特定数据类型允许的常规大小的字节和字节数据。如果 BLOB 数据太大,在内存中将 BLOB 转换为字符串有时会导致 OutOfMemoryException

但是如果您想将 BLOB 转换为字符串,这里是您可以尝试的代码片段:

String s = "";
InputStream inStream = b.getBinaryStream();
//b is your BLOB
InputStreamReader inStreamReader = new InputStreamReader(inStream);
BufferedReader reader = new BufferedReader(inStreamReader );
StringBuffer buf = new StringBuffer();
while(s = reader.readLine())
{
   buf.append(s);
}

您还可以采用其他几种方法,其中之一是

ByteArrayOutputStream baos = new ByteAttayOutputStream();
byte[] buf = new byte[1024];
InputStream in = blob.getBinaryStream();
int n = 0;
while ((n=in.read(buf))>=0)
{
   baos.write(buf, 0, n);
}
in.close();
byte[] bytes = baos.toByteArray();
String blobString = new String(bytes); 

如有任何问题,我将不胜感激。

Kushal 的回答提供了将 Blob 转换为字符串的片段。要使用此转换,最好使用 DTO。

为此,将您的 graphql 模式转换为:

type ImageDTO {
    id: ID!
    image: String!
} 

并创建一个 DTO class ImageDTO:

public class ImageDTO {
    private Image entity;

    //Constructor
    public ImageDTO(Image image) {
         this.entity=image;
    }

    //Getters
    public Long getId() {
        return entity.getId();
    }

    public String getImage() {
        //convert the entity image and return it as String
        return Base64.getEncoder().encodeToString(entity.getImage());
    }
}

将 DTO 与实体分开可以让您更好地控制传输的数据。

为什么不使用自定义标量?它直接回答了您的起始问题:

So I thought it must be possible to put something in between the schema parsing to implement a mapping from Blob to String.

Is this somehow possible here?

您的 GraphQL 架构将是:

scalar ImageBlob
type Image {
    id: ID!
    image: ImageBlob!
} 

然后,在自定义标量实现中,您提供 Blob 与 String 之间的转换。