![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=1739279203-wjqdgrhW7lAuRFStz9guAw0rIHWi0s9G-0-fedf5fcb748ea2e9a1a3a2bca7ee1508)
第3种方式是直接从GitHub上获取代码,可以从GitHub上克隆预先准备好的示例代码:
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_128_2.jpg?sign=1739279203-kFwrjXuOTuc3SiHS2GfrvgU5M4pxPD1H-0-b1d1a8b3e2cc18a354128788776854bf)
该程序位于“023-quarkus-sample-graphql”目录中,是一个Maven工程项目程序。
在IDE工具中导入Maven工程项目程序,在pom.xml的<dependencies>下有如下内容:
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_129_1.jpg?sign=1739279203-UH4xSV7NnAySPcj3TtyoGt5r1V8WiGab-0-f90b35283115bb86fbe3e4f342b667ab)
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=1739279203-6ydzEAOYJ9mtcxjvmX5WKzXKOpKu3cYQ-0-ebec6422bc36740a9cffe8af98729d68)
图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=1739279203-P5kB0kubvtrpAhuGFvDsE8euahwRy8DG-0-1d7cae8787088708ec1e33fd67347df8)
下面讲解 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=1739279203-gnDgtB9hS6lkY9hcc9Cr9uyT9OwryUeN-0-c30e7f6acf6ad5832a5270e93e10774d)
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_130_1.jpg?sign=1739279203-VPoxWq0B7f3eFmPWCU0CRGXCA75Km9hw-0-4b9c46324465eead923fb531fb402ee6)
程序说明:
①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=1739279203-XdZsxTZZimkz0cRBg6rb7P7G1Z2VcfNa-0-619873706d34040b628069d05e10451e)
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_131_1.jpg?sign=1739279203-t4fINv3apFQTyYtbpHTp2Tnlz09zcuhg-0-0200f09e95c5a6384be6747bb61560e0)
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_132_1.jpg?sign=1739279203-YC4KLryUriQDidLZOXpybb9152w7qb7R-0-41d658e99aaa1bd94ecee6661f9629af)
程序说明:
①服务类内部有一个变量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=1739279203-0ABP20erlEnfCB1AleGRIw6bdQEvmFhz-0-f5d6e8e37fa6786e5b9c35448711ae34)
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_133_1.jpg?sign=1739279203-i2jA7sPkhm5tCCROHxSwFSE699fgXK9E-0-88a904f0fe18b15e3491e417ca72a837)
程序说明: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=1739279203-2SdTZer8f7hJDptdT97LPrPYWxj8mRcT-0-11c4e20469a955c38bd8e8b9dc77103d)
图3-14 quarkus-sample-graphql程序动态运行的序列图
3.3.3 验证程序
通过下列几个步骤(如图3-15所示)来验证案例程序。
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_135_1.jpg?sign=1739279203-olGZMxcJDR0LldBrDysaC9fUzRmiCxgV-0-5d407776e27e7dbd5553899489073937)
图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=1739279203-Z6POs4RRlB9bBmEQYgI7lu6fnJ06jdaW-0-f8d52372b0a30fa7f7604904bd65833d)
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_136_1.jpg?sign=1739279203-0rKuXec2mawySfrEALvMcwMIthlvZVxs-0-f0c44397da87daba88eda256aede7138)
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=1739279203-muu3XaXgLd3YrYUj1s4b0A53jWpo4fiy-0-137789a7c32e1af72d281c2520ac22bd)
图3-16 graphql-ui界面
可以在输入框中键入如下查询内容:
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_137_1.jpg?sign=1739279203-1XwKcKHCohekGledIMmP5ip91I8WSlBg-0-10c98b983231100e3ed2f0dc74904556)
然后单击“执行”按钮,会显示如图3-17所示的结果。
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_137_2.jpg?sign=1739279203-T7rEi3dwLggrqEA53JV3STvgXJ4BDolU-0-a5af5d8c93e9e1c8de423f5ec79039e3)
图3-17 显示查询结果界面
4.通过界面工具获取Project列表及其内部全部数据
为了获取所有数据及其内部的层次数据,可以在界面工具窗口中输入如下GraphQL语句:
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_137_3.jpg?sign=1739279203-i01rQK0BYZ0C1ODULpofecBnb1QFxgZa-0-00ae5041f063e427f40e78506b88256b)
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_138_1.jpg?sign=1739279203-RfvBrKSeiIbsA5yRQaAWNH8ezlZaxJnd-0-3e62eee4b7b33bed6358e38d4fc72876)
结果界面如图3-18所示。
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_138_2.jpg?sign=1739279203-IV5W1CEqH2PiWylURWQFdDc9p4cJggcO-0-32d788dcc04065eda867084e8a92e9c3)
图3-18 查询全部数据的结果界面
具体的结果内容如下:
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_138_3.jpg?sign=1739279203-dAY62BpjKl1IOce9uAF5kBMhKpwJBS5c-0-1f6afa2745d07c28ac0a5dbdcbc144a1)
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_139_1.jpg?sign=1739279203-nt0lyTGStRLQrQGLxWOXJbO3Tl9au5Rn-0-4dad249f05df2a5ce7b250ca897bd764)
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_140_1.jpg?sign=1739279203-XKzls1dJzH8eRM1KapPg9BbXvoihJGxN-0-e46966eb46f3cc57242acd0be449427e)
这与我们的初始化数据完全一致。
5.通过界面工具获取一条Project数据
按照JSON格式获取一条Project数据,在界面工具窗口中输入如下GraphQL语句:
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_140_2.jpg?sign=1739279203-YFsSRLktMbaNOP1CIt3cd2kC2GwLyGgP-0-c83eda48ebe608297bc0bf300fbf41ea)
结果是项目id为1的JSON列表。
6.通过界面工具新增一条Project数据
按照JSON格式增加一条Project数据,在界面工具窗口中输入如下GraphQL语句:
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_140_3.jpg?sign=1739279203-HnEN5bjrPcUn690tyelL49e7KkbczUKz-0-e48c5aa3cb734cbb8d6e3997fa092bf0)
7.通过界面工具修改一条Project数据
按照JSON格式修改一条Project数据,在界面工具窗口中输入如下GraphQL语句:
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_141_1.jpg?sign=1739279203-Bc29v4wsRBYZhzdgkiDvlUABk6LGtaZc-0-69e314090f20b86545300cdd339b3709)
通过结果,可以观察到已经修改了数据内容。
8.通过界面工具删除一条Project数据
按照JSON格式删除一条Project数据,在界面工具窗口中输入如下GraphQL语句:
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_141_2.jpg?sign=1739279203-COPNy4PMPcXBxi3ulj4FVxugU8EN5Yjt-0-2ac38144d78707901d6bad7152678fb5)
通过结果,可以观察到已经删除了数据内容。