Java 使用 Graphql 搭建查詢服務(wù)詳解
背景
隨著React的開源,facebook相繼開源了很多相關(guān)的項(xiàng)目,這些項(xiàng)目在他們內(nèi)部已經(jīng)使用了多年,其中引起我注意的就是本次討論的是graphql,目前官方只有nodejs版,由于很多公司的后臺(tái)技術(shù)棧都是Java,所以便有了graphql的java版實(shí)現(xiàn),在github上可以找到,廢話不多說,直接看代碼吧,具體介紹還是去看官網(wǎng)吧,不然就跑題了。
GraphQLSchema
Schema相當(dāng)于一個(gè)數(shù)據(jù)庫(kù),它有很多GraphQLFieldDefinition組成,F(xiàn)ield相當(dāng)于數(shù)據(jù)庫(kù)表/視圖,每個(gè)表/視圖又由名稱、查詢參數(shù)、數(shù)據(jù)結(jié)構(gòu)、數(shù)據(jù)組成.
1) 先定義一個(gè)數(shù)據(jù)結(jié)構(gòu)(GraphQLOutputType)字段,然后定義一個(gè)初始化方法
private GraphQLOutputType userType;
private void initOutputType() {
/**
* 會(huì)員對(duì)象結(jié)構(gòu)
*/
userType = newObject()
.name("User")
.field(newFieldDefinition().name("id").type(GraphQLInt).build())
.field(newFieldDefinition().name("age").type(GraphQLInt).build())
.field(newFieldDefinition().name("sex").type(GraphQLInt).build())
.field(newFieldDefinition().name("name").type(GraphQLString).build())
.field(newFieldDefinition().name("pic").type(GraphQLString).build())
.build();
}
2)再定義兩個(gè)表/視圖,它包括名稱,查詢參數(shù),數(shù)據(jù)結(jié)構(gòu),以及數(shù)據(jù)檢索器
/**
* 查詢單個(gè)用戶信息
* @return
*/
private GraphQLFieldDefinition createUserField() {
return GraphQLFieldDefinition.newFieldDefinition()
.name("user")
.argument(newArgument().name("id").type(GraphQLInt).build())
.type(userType)
.dataFetcher(environment -> {
// 獲取查詢參數(shù)
int id = environment.getArgument("id");
// 執(zhí)行查詢, 這里隨便用一些測(cè)試數(shù)據(jù)來說明問題
User user = new User();
user.setId(id);
user.setAge(id + 15);
user.setSex(id % 2);
user.setName("Name_" + id);
user.setPic("pic_" + id + ".jpg");
return user;
})
.build();
}
/**
* 查詢多個(gè)會(huì)員信息
* @return
*/
private GraphQLFieldDefinition createUsersField() {
return GraphQLFieldDefinition.newFieldDefinition()
.name("users")
.argument(newArgument().name("page").type(GraphQLInt).build())
.argument(newArgument().name("size").type(GraphQLInt).build())
.argument(newArgument().name("name").type(GraphQLString).build())
.type(new GraphQLList(userType))
.dataFetcher(environment -> {
// 獲取查詢參數(shù)
int page = environment.getArgument("page");
int size = environment.getArgument("size");
String name = environment.getArgument("name");
// 執(zhí)行查詢, 這里隨便用一些測(cè)試數(shù)據(jù)來說明問題
List<User> list = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
User user = new User();
user.setId(i);
user.setAge(i + 15);
user.setSex(i % 2);
user.setName(name + "_" + page + "_" + i);
user.setPic("pic_" + i + ".jpg");
list.add(user);
}
return list;
})
.build();
}
3)接著定義一個(gè)Schema,并將其初始化,它包含一個(gè)名稱,以及一個(gè)或多個(gè)表/視圖(Field)
private GraphQLSchema schema;
public GraphSchema() {
initOutputType();
schema = GraphQLSchema.newSchema().query(newObject()
.name("GraphQuery")
.field(createUsersField())
.field(createUserField())
.build()).build();
}
4)完成以上步驟之后,還需要定義一個(gè)model,類名不限,但是結(jié)構(gòu)需要滿足前面定義的數(shù)據(jù)結(jié)構(gòu),而且必須是public的
public class User {
private int id;
private int age;
private int sex;
private String name;
private String pic;
// getter, setter...
}
5)之后寫一個(gè)main方法,來測(cè)試一下
public static void main(String[] args) {
GraphQLSchema schema = new GraphSchema().getSchema();
String query1 = "{users(page:2,size:5,name:\"john\") {id,sex,name,pic}}";
String query2 = "{user(id:6) {id,sex,name,pic}}";
String query3 = "{user(id:6) {id,sex,name,pic},users(page:2,size:5,name:\"john\") {id,sex,name,pic}}";
Map<String, Object> result1 = (Map<String, Object>) new GraphQL(schema).execute(query1).getData();
Map<String, Object> result2 = (Map<String, Object>) new GraphQL(schema).execute(query2).getData();
Map<String, Object> result3 = (Map<String, Object>) new GraphQL(schema).execute(query3).getData();
// 查詢用戶列表
System.out.println(result1);
// 查詢單個(gè)用戶
System.out.println(result2);
// 單個(gè)用戶、跟用戶列表一起查
System.out.println(result3);
}
輸出:
{users=[{id=0, sex=0, name=john_2_0, pic=pic_0.jpg}, {id=1, sex=1, name=john_2_1, pic=pic_1.jpg}, {id=2, sex=0, name=john_2_2, pic=pic_2.jpg}, {id=3, sex=1, name=john_2_3, pic=pic_3.jpg}, {id=4, sex=0, name=john_2_4, pic=pic_4.jpg}]}
{user={id=6, sex=0, name=Name_6, pic=pic_6.jpg}}
{user={id=6, sex=0, name=Name_6, pic=pic_6.jpg}, users=[{id=0, sex=0, name=john_2_0, pic=pic_0.jpg}, {id=1, sex=1, name=john_2_1, pic=pic_1.jpg}, {id=2, sex=0, name=john_2_2, pic=pic_2.jpg}, {id=3, sex=1, name=john_2_3, pic=pic_3.jpg}, {id=4, sex=0, name=john_2_4, pic=pic_4.jpg}]}
6)最后把main方法里面的代碼放到web層,只需要定義一個(gè)query參數(shù),很容易就把查詢服務(wù)搭建好了,dataFetcher 里面還是調(diào)用原來的查詢接口
7)引入maven依賴
<dependency> <groupId>com.graphql-java</groupId> <artifactId>graphql-java</artifactId> <version>2.0.0</version> </dependency>
關(guān)于graphql查詢什么定義,看看這個(gè)或許對(duì)你有幫助
json
{
id=6,
sex=0,
name="Name_6",
pic="pic_6.jpg"
}
query
{
id,
sex,
name,
pic
}
后面那部分,其實(shí)就是json字符串,去掉=和value的結(jié)果,還是可讀的
結(jié)語
graphql 帶了一種全新的思維方式,可以簡(jiǎn)化web api的開發(fā),由客戶端指定需要什么數(shù)據(jù),服務(wù)端返回什么數(shù)據(jù),減少不必要的流量傳輸,對(duì)移動(dòng)端友好,還提供多種數(shù)據(jù)聚合查詢,多個(gè)查詢只是用一個(gè)請(qǐng)求,既滿足api最小粒度,又滿足前端需要,減少請(qǐng)求,提高性能。
感覺以后會(huì)朝這方面去發(fā)展,大趨所驅(qū)。
相關(guān)文章
Springboot使用pdfbox提取PDF圖片的代碼示例
PDFBox是一個(gè)用于創(chuàng)建和處理PDF文檔的Java庫(kù),它可以使用Java代碼創(chuàng)建、讀取、修改和提取PDF文檔中的內(nèi)容,本文就給大家介紹Springboot如何使用pdfbox提取PDF圖片,感興趣的同學(xué)可以借鑒參考2023-06-06
springboot?集成easy-captcha實(shí)現(xiàn)圖像驗(yàn)證碼顯示和登錄
本文主要介紹了springboot?集成easy-captcha實(shí)現(xiàn)圖像驗(yàn)證碼顯示和登錄,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04
Spring中如何使用@Value注解實(shí)現(xiàn)給Bean屬性賦值
這篇文章主要介紹了Spring中如何使用@Value注解實(shí)現(xiàn)給Bean屬性賦值的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08
SpringBoot中的五種對(duì)靜態(tài)資源的映射規(guī)則的實(shí)現(xiàn)
這篇文章主要介紹了SpringBoot中的五種對(duì)靜態(tài)資源的映射規(guī)則的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12
Java數(shù)據(jù)存儲(chǔ)的“雙子星”對(duì)決(Map和Set的區(qū)別)
文章主要介紹了Java中Map和Set兩種數(shù)據(jù)結(jié)構(gòu)的定義、實(shí)現(xiàn)、方法及應(yīng)用場(chǎng)景,Map用于存儲(chǔ)鍵值對(duì),鍵唯一,值可重復(fù);Set用于存儲(chǔ)唯一元素,無序,兩者都提供了豐富的操作方法,如添加、刪除、查找等,感興趣的朋友一起看看吧2025-02-02
java線程之用Thread類創(chuàng)建線程的方法
本篇文章介紹了,Thread類創(chuàng)建線程的方法。需要的朋友參考下2013-05-05
springboot使用定時(shí)器@Scheduled不管用的解決
這篇文章主要介紹了springboot使用定時(shí)器@Scheduled不管用的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
Java?hutool?List集合對(duì)象拷貝示例代碼
這篇文章主要介紹了Java?hutool?List集合對(duì)象拷貝的相關(guān)資料,文章還分享了在實(shí)現(xiàn)過程中遇到的一些問題,并強(qiáng)調(diào)了閱讀源碼和正確配置CopyOptions的重要性,需要的朋友可以參考下2024-12-12

