![Quarkus实践指南:构建新一代的Kubernetes原生Java微服务](https://wfqqreader-1252317822.image.myqcloud.com/cover/237/40795237/b_40795237.jpg)
3.3 编写GraphQL应用
3.3.1 案例简介
本案例介绍基于 Quarkus 框架来实现 GraphQL的基本功能。通过阅读和分析在 Web上实现的基于 GraphQL 语言的查询、新增、删除操作等案例代码,可以理解和掌握基于 Quarkus 框架的GraphQL使用方法。
基础知识:GraphQL应用和MicroProfile GraphQL规范。
GraphQL既是一种用于API的查询语言,也是一个满足数据查询的运行时环境。GraphQL为应用系统API中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余。这一功能也让API更容易地随着时间的推移而演进,还能用于构建强大的开发者工具。关于GraphQL的详细内容可参考其官网上的资料。
MicroProfile GraphQL规范的目的是提供一组“代码优先”的 API,使用户能够在 Java中快速开发基于 GraphQL 的可移植应用程序。本规范的所有实现有两个主要目的:①生成并促使 GraphQL 模式可用,这是通过查看用户代码中的注解来完成的,并且必须包括所有GraphQL 查询和变异,以及通过查询和变异的响应类型或参数隐式定义的所有实体;②执行GraphQL请求,这将以查询或变异的形式出现。
3.3.2 编写程序代码
编写程序代码有 3种方式。第 1种方式是通过代码 UI来实现的,在 Quarkus 官网的生成代码页面中按照指定步骤生成脚手架代码,然后下载文件,将项目引入 IDE 工具中,最后修改程序源码。
第2种方式是通过mvn来构建程序,通过下面的命令创建Maven项目来实现:
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_128_1.jpg?sign=1738862268-tuGATq29v5e8qgzG4mXAbes4gXXnN3kF-0-f0f02fc93468437d5fd5f4b0a1f10a19)
第3种方式是直接从GitHub上获取代码,可以从GitHub上克隆预先准备好的示例代码:
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_128_2.jpg?sign=1738862268-TZ81XnOK031c1rqKtczbvf0gBcwg3rLU-0-24193c7dd7a7e18aea0a1799d86a7236)
该程序位于“023-quarkus-sample-graphql”目录中,是一个Maven工程项目程序。
在IDE工具中导入Maven工程项目程序,在pom.xml的<dependencies>下有如下内容:
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_129_1.jpg?sign=1738862268-ckmAgQixqGKgmDZyj9Kl9EdFAzk7pysm-0-fe286c8c9b93e5e0fb0ac2641c5a2fb5)
quarkus-smallrye-graphql是Quarkus 整合了SmallRye的GraphQL实现。
quarkus-sample-graphql程序的应用架构(如图3-13所示)表明,外部访问ProjectResource资源接口,ProjectResource 调用 ProjectService 服务,ProjectResource 资源依赖于 SmallRye Mutiny框架,GraphQL运行遵循MicroProfile GraphQL规范。
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_129_2.jpg?sign=1738862268-85KJIhYdOf8ofgpycwjLDVd5vs7tJBgZ-0-9987e14aa244f0b4a2379268adc2a9c7)
图3-13 quarkus-sample-graphql程序应用架构图
quarkus-sample-graphql程序的核心类如表3-3所示。
表3-3 quarkus-sample-graphql程序的核心类
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_129_3.jpg?sign=1738862268-K9C9uZAfIShVZjrClVM6yZASYuiBpGcc-0-6e1b3a17be961c8693af296bc4f9d987)
下面讲解 quarkus-sample-graphql 程序中的 ProjectResource 资源类、ProjectService 服务类和Project实体类的功能和作用。
1.ProjectResource资源类
用IDE工具打开com.iiit.quarkus.sample.graphql.ProjectResource类文件,其代码如下:
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_129_4.jpg?sign=1738862268-gUq3oE0g9LrAqxYlmFdw3wuRHW2ttJms-0-18ab48dc0c990ce0679d5917303fd4ea)
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_130_1.jpg?sign=1738862268-Ip7jvGR9sckoUXzmXE5acCQbRNOn3mwX-0-433eec505bb9d45c003b93204e50354c)
程序说明:
①ProjectResource类的作用还是与外部进行交互,该程序实现了GraphQL的CRUD操作。
②@GraphQLApi注解:表明引入GraphQL的API方法。
③@Query("projects")注解:查询路径,类似于REST的GET方法。
④@Mutation注解:在数据被创建、更新或删除时使用,类似于REST的POST、PUT和DELETE方法。
2.ProjectService服务类
用 IDE工具打开 com.iiit.quarkus.sample.graphql.ProjectService类文件,ProjectService类主要给ProjectResource提供业务逻辑服务,其代码如下:
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_130_2.jpg?sign=1738862268-H91UGVsHJEHrbmtYuuHA34ZJWKanGy2S-0-945b46bb98f78d880fbd8a463d16c597)
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_131_1.jpg?sign=1738862268-PpSBTXwPF7IfNTthliQxQIWtM2G7MDDn-0-90674a69e1404d2229a5bdffec44adbb)
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_132_1.jpg?sign=1738862268-1CLfBHqDPgi2V3QUHUPHKPRqUkM0uDu8-0-dbf179e5b294166972ce98bfbdb1a395)
程序说明:
①服务类内部有一个变量Set<Project>,用来存储所有的Project对象实例。该服务实现了对Set<Project>的全部列出、查询、新增、修改和删除等操作功能。
② ProjectService构造阶段,实例化了8个Project对象,然后建立了这8个Project对象之间的父子层次。
3.Project实体类
用 IDE 工具打开 com.iiit.quarkus.sample.graphql.Project 类文件,实体类主要就是基本的POJO对象,其代码如下:
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_132_2.jpg?sign=1738862268-3Vzgh4ph8OWQodMZfBn577sBMyBj5oM1-0-97ea547d0b49fde6cbca92d1ad48404e)
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_133_1.jpg?sign=1738862268-Wb16lfgbJdSVfVnOr2J4xVkFJsYBanSg-0-cae074d354796a60314ddec5b506e908)
程序说明:Project类一定是一个标准的 JavaBean,即内部字段都是私有变量,通过 get和set方法来赋值和取值。
该程序动态运行的序列图(如图 3-14所示,遵循 UML 2.0规范绘制)描述了外部调用者Actor、ProjectResource和ProjectService等3个对象之间的时间顺序交互关系。
该序列图中总共有5个序列,分别介绍如下。
序列1活动:① 外部调用ProjectResource资源类的Query(list)方法;② Query(list)方法调用ProjectService服务类的list方法;③返回整个Project列表。
序列 2活动:① 外部传入参数 ID并调用 ProjectResource资源类的 Query(getById)方法;② Query(getById)方法调用 ProjectService服务类的 getById方法;③ 返回 Project列表中对应ID的Project对象。
序列3活动:① 外部传入参数Project对象并调用ProjectResource资源类的Mutation(add)方法;② Mutation(add)方法调用 ProjectService服务类的 add方法,ProjectService服务类实现增加一个Project对象的操作并返回整个Project列表。
序列 4 活动:① 外部传入参数 Project 对象并调用 ProjectResource 资源类的Mutation(update)方法;② Mutation(update)方法调用 ProjectService 服务类的 update 方法,ProjectService 服务类根据项目名称是否相等来实现修改一个 Project 对象的操作并返回整个Project列表。
序列 5 活动:① 外部传入参数 Project 对象并调用 ProjectResource 资源类的 Mutation (delete)方法;② Mutation(delete)方法调用 ProjectService 服务类的 delete 方法,ProjectService服务类根据项目名称是否相等来实现删除一个Project对象的操作并返回整个Project列表。
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_134_1.jpg?sign=1738862268-SDFHn6jlp2fnHCe8Ej2XJPiiXIO46BKL-0-d0131120f5741d2c043c0616116f060b)
图3-14 quarkus-sample-graphql程序动态运行的序列图
3.3.3 验证程序
通过下列几个步骤(如图3-15所示)来验证案例程序。
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_135_1.jpg?sign=1738862268-2vp7MmkWnTzw53j1g9jJtjEeiOdQGLiK-0-4972f2dce959181bc0bd4642f6c5aa12)
图3-15 quarkus-sample-graphql程序验证流程图
下面对其中涉及的关键点进行说明。
1.启动quarkus-sample-graphql程序服务
启动程序有两种方式,第 1种是在开发工具(如 Eclipse)中调用 ProjectMain类的 run方法,第2种是在程序目录下直接运行命令mvnw compile quarkus:dev。
2.通过API显示全部schema内容
在命令行窗口中键入命令 curl http://localhost:8080/graphql/schema.graphql,或在浏览器中输入URL(http://localhost:8080/graphql/schema.graphql),获得的结果是schema列表,是JSON格式的:
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_135_2.jpg?sign=1738862268-0pdPnjdKnZ7S2ymLencGLJNsYdEgyyjC-0-5328045da88b33d69bb1f14a513c139b)
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_136_1.jpg?sign=1738862268-2dmslcvk7XLot73hwR4EqKWKQHPsfR26-0-837354ef1bc9fe1f163536e321e0fc12)
schema内容说明如下:
①Query有2个方法,分别是project和projects方法。
②Mutation有3个方法,分别是add、delete、update方法。
③Project对象结构。
④输入的Project对象结构。
3.GraphQL的查询和处理
接着,通过专业工具来进行查询和处理,打开浏览器 URL(http://localhost:8080/graphql-ui/),会显示如图3-16所示的graphql-ui界面。
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_136_2.jpg?sign=1738862268-cPG9L1rTcNpuB5HGaK1biwkHPJLh4Zym-0-f11773ef042074a4e41c2b54a1cac109)
图3-16 graphql-ui界面
可以在输入框中键入如下查询内容:
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_137_1.jpg?sign=1738862268-XfdAinHnGA1nMwBGojidMBvr9O2bSxbv-0-b4b96382fa4e09d98f6e861a6159ec9f)
然后单击“执行”按钮,会显示如图3-17所示的结果。
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_137_2.jpg?sign=1738862268-WuV1WIe46Y9XcuMU44oOzWk1WomsHCX5-0-b5e43e2e29efe17739ac8da65e9b0677)
图3-17 显示查询结果界面
4.通过界面工具获取Project列表及其内部全部数据
为了获取所有数据及其内部的层次数据,可以在界面工具窗口中输入如下GraphQL语句:
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_137_3.jpg?sign=1738862268-5WsY2pS2Lnt7WXWs7ybZD3dMXiZxIvl9-0-4c2019100d7367e32c9b2f08b67ea1a5)
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_138_1.jpg?sign=1738862268-PGkOqEGrzC5X5D3p9oToA8yaFlnDbq3a-0-986542d866835fed10bdabf97ebee992)
结果界面如图3-18所示。
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_138_2.jpg?sign=1738862268-zRLpeVmZv7sb8mQdTeESUl5Z7VADWsrI-0-d359efd1b1038215ba75cdac9e57bae3)
图3-18 查询全部数据的结果界面
具体的结果内容如下:
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_138_3.jpg?sign=1738862268-fb2GDBZJkDCkQODtczKxV5mrmmt7JWlP-0-2c96ac9bce820f645625908afec4f378)
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_139_1.jpg?sign=1738862268-iDFpYCxn8X9jjx8ZSSDdmWC3eC9lrL1M-0-e6fd8b1fb16c96a3331bb2b7b7d6a494)
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_140_1.jpg?sign=1738862268-AnlJiqEqx5P09Nkk5V2OfjZBTt0MRrHC-0-79e490231a871f0ac62b631eec69ff4f)
这与我们的初始化数据完全一致。
5.通过界面工具获取一条Project数据
按照JSON格式获取一条Project数据,在界面工具窗口中输入如下GraphQL语句:
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_140_2.jpg?sign=1738862268-IKxWTXxm266I2PsFPb4sKE89Sp4Vn4tG-0-62847be8d8f4722efca6792045964f19)
结果是项目id为1的JSON列表。
6.通过界面工具新增一条Project数据
按照JSON格式增加一条Project数据,在界面工具窗口中输入如下GraphQL语句:
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_140_3.jpg?sign=1738862268-3KUWV77V5igPBb8WNIJYtHrqOCf34bq9-0-d1341b1464d137d99d563b34ed1070f8)
7.通过界面工具修改一条Project数据
按照JSON格式修改一条Project数据,在界面工具窗口中输入如下GraphQL语句:
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_141_1.jpg?sign=1738862268-i4dqR7pNoocjSwROPeM2xzsT6gdiD7Um-0-093905bf7d7b8ec5935fe3c91e3b3dc4)
通过结果,可以观察到已经修改了数据内容。
8.通过界面工具删除一条Project数据
按照JSON格式删除一条Project数据,在界面工具窗口中输入如下GraphQL语句:
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_141_2.jpg?sign=1738862268-ZeW0NB5C4ziXJfWTyT5BnJgO3B6IFpvR-0-2411897ac61785aed762d1ffe25fcbb9)
通过结果,可以观察到已经删除了数据内容。