![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=1738794953-V9N7udFPbqis6j6esSSknT1nmzye4tsI-0-189f692bb631e778e982b76a107a10f3)
第3种方式是直接从GitHub上获取代码,可以从GitHub上克隆预先准备好的示例代码:
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_128_2.jpg?sign=1738794953-38Jph78rsf1fkjGsBjP1Q9qFHWV3ZSoe-0-3f2e8f06c4d5bcdc2eee1a8ff444e12c)
该程序位于“023-quarkus-sample-graphql”目录中,是一个Maven工程项目程序。
在IDE工具中导入Maven工程项目程序,在pom.xml的<dependencies>下有如下内容:
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_129_1.jpg?sign=1738794953-mJLgUg4PcaW8Sr0cn75lY0MTj6Vsyt3x-0-e537941d4084690791c2bf8dd2985ccd)
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=1738794953-DEA3iaysqq2HrttE1020lqZMhRrdKNDs-0-7771e8aef624827253fc84c365f14fda)
图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=1738794953-6GwPhjWzUSge1BN7gOYueu8iF7k9B9ML-0-606a77e706fcb763c300997d002fcccf)
下面讲解 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=1738794953-meBJqe1gAFi9U5d0PyJuJDWv4nwNhZJx-0-c7fba4a86def98d1541d31326882135f)
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_130_1.jpg?sign=1738794953-nKzIEQgeG62EP0WZDnZ6fOSYtXAkSkkj-0-2a6c5ee3078d1821ab31179c86d8658c)
程序说明:
①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=1738794953-Zn1DoeA6uenFCej6Qel8HWtLXBEgyxEo-0-be2dcb543ad1108343e892ba30ac7f92)
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_131_1.jpg?sign=1738794953-gCJkhqYa8sI04ply1aRkx9eNKn3Ngs5T-0-0a89ac3788b70aa3d77e29e24346d6ec)
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_132_1.jpg?sign=1738794953-NFYWgi152Qe85dMWNXtW0nKbd3BsrJx0-0-7549dddf205ad8253cfae0e8be4cb6e3)
程序说明:
①服务类内部有一个变量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=1738794953-6raCXnXYuFvWBY3I7SoMnidqFerp5HBP-0-053ad5e5ada13fb8ae50285c9dafd370)
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_133_1.jpg?sign=1738794953-k7YitbFu8TPukwv6Sm4HeHcNcn5OPo9z-0-e78d2be6f141250467465d01d9055073)
程序说明: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=1738794953-a9AJGoksuAg6A9CExUAW81uOOYPJOPfk-0-4b1a14dbd6841781ba8d564fe73d22e4)
图3-14 quarkus-sample-graphql程序动态运行的序列图
3.3.3 验证程序
通过下列几个步骤(如图3-15所示)来验证案例程序。
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_135_1.jpg?sign=1738794953-MlnyqvJ58K2Uh7e1Wt0Q1TlyXKJgRzYf-0-d16d18e45525732b34397d101d9919a1)
图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=1738794953-roxshI3Jcq9Non2FWdIy7EATUlNiaYxA-0-ccb2365eb52c1b1b6d53af8a372a0550)
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_136_1.jpg?sign=1738794953-kvG59eaMeYuAENnt8ve93Rq4H0AUy5bQ-0-7f8f67a2bb379386c19d522d25c2212f)
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=1738794953-gUafbGXTbFCMqUOSVcKwO0sr6V0TLQpe-0-ebf89808ce6ce614d6cb416a53af0eea)
图3-16 graphql-ui界面
可以在输入框中键入如下查询内容:
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_137_1.jpg?sign=1738794953-x39wKz3saHhA4hra3Vybvuqd5IlE2Rf3-0-b81a91807d075bbbbfbcd7a142506410)
然后单击“执行”按钮,会显示如图3-17所示的结果。
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_137_2.jpg?sign=1738794953-ubeXeFBWLPLHGGCQ0ezlnvXehejZZS34-0-bc412040dff1db1eb5bd74e8f7038176)
图3-17 显示查询结果界面
4.通过界面工具获取Project列表及其内部全部数据
为了获取所有数据及其内部的层次数据,可以在界面工具窗口中输入如下GraphQL语句:
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_137_3.jpg?sign=1738794953-9D3pnvxsOkrD9FmBoPjQnj300Of3q2CL-0-9d03b0d7919a069b714cef65718f2238)
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_138_1.jpg?sign=1738794953-F0fozED9FW5qxgKEYGy6t9Z9S48WmPdB-0-c5f645c05c6c7909be68388f97e392c8)
结果界面如图3-18所示。
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_138_2.jpg?sign=1738794953-Lb2GervDvocB3D1qElsd0M75fXZJsrme-0-985c8d8744f0021481ce5334ce0457b2)
图3-18 查询全部数据的结果界面
具体的结果内容如下:
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_138_3.jpg?sign=1738794953-WApRoit5dxzGbRgePZH2FBHfRmT1Uopf-0-5836e1a91ed3626ac376b76f534cc1c2)
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_139_1.jpg?sign=1738794953-BJaLbGifDIhOV2FWYpz0duXOiy5Vtj4L-0-7a924f4b6d3bcca15fcac59cc414f0aa)
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_140_1.jpg?sign=1738794953-OCKwaFecx0GzNfKtn8NqO7ok1UcJLsb6-0-772e10420d9e8a4df7ba196d1e122484)
这与我们的初始化数据完全一致。
5.通过界面工具获取一条Project数据
按照JSON格式获取一条Project数据,在界面工具窗口中输入如下GraphQL语句:
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_140_2.jpg?sign=1738794953-DuuSuO0bCMoAFoQXmboNULSVigIzErNI-0-0446fd0af3ab5245e6a3b37d19ed456e)
结果是项目id为1的JSON列表。
6.通过界面工具新增一条Project数据
按照JSON格式增加一条Project数据,在界面工具窗口中输入如下GraphQL语句:
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_140_3.jpg?sign=1738794953-4qtsmXyXc9aeQ9PFF5vDNSUnxL8zBAXD-0-580b1e97180349eaa2f0f0b7cef04532)
7.通过界面工具修改一条Project数据
按照JSON格式修改一条Project数据,在界面工具窗口中输入如下GraphQL语句:
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_141_1.jpg?sign=1738794953-fz332C97kmtHaAbSIZrt2RHDaGzwYPx3-0-bedb95baa0837967d0b8ddf83a3a4ca3)
通过结果,可以观察到已经修改了数据内容。
8.通过界面工具删除一条Project数据
按照JSON格式删除一条Project数据,在界面工具窗口中输入如下GraphQL语句:
![](https://epubservercos.yuewen.com/ADE0E0/21190709301168906/epubprivate/OEBPS/Images/41803_141_2.jpg?sign=1738794953-ajdi1mGX9K5G3Xv8XAUa88xfKk1sAk2r-0-5aa00b552258563a5f07443e77daa10e)
通过结果,可以观察到已经删除了数据内容。