說實話,網上這玩意資料太少了,用的人也挺少的,不是因爲技術需求,估計大家都不會想用,這次來把這個小東西稍微記錄一下
一、關於 GrapQL
1、什麼是 GraphQL?
官方解釋:一種用於 API 的查詢語言
看了這句話之後我是懵逼的,沒看懂,如果你也沒看懂看看下面這句話
請求你所要的數據,不多不少
什麼意思呢,很簡單,假如我有一個查詢用戶信息的 restful 接口,裏面會返回一些信息,用戶名,密碼,頭像,等等,現在前端和我說,
前端:我只要用戶名和頭像,其他的都不要,你別查出來給我了
我:what?你不要的數據你不用不就行了,這接口不止你 web 端用,還有 app 接口也在用呢
前端:那我不管,現在需求就是這樣
我:……
這個時候 GraphQL 出現了,你想要用戶名和頭像是吧,行,你自己來取,你要什麼自己取什麼,後端就會給你返回什麼,後端也不用單獨來給你寫接口,說到這裏,你可能似懂非懂,沒關係,接着看下去
2、怎麼使用?
彆着急,繼續往下看
二、Idea 中安裝 GraphQL 插件
1、安裝 JS GraphQL 插件
2、安裝之後
新建文件可以選擇新建 graphql 文件
工具欄也會出現 graphql
這裏面會自動去檢查我們寫的 graphql 文件中語法是否正確
三、編寫一個簡單的 GrapQL
1、引入相關依賴
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 必需:包含了默認配置、graphql-java 和 graphql-java-tools,可以簡化配置 -->
<dependency>
<groupId>com.graphql-java-kickstart</groupId>
<artifactId>graphql-spring-boot-starter</artifactId>
<version>11.0.0</version>
</dependency>
<!-- 可選:用於調試 GraphQL,功能類似 Restful 中的 Swagger -->
<dependency>
<groupId>com.graphql-java-kickstart</groupId>
<artifactId>playground-spring-boot-starter</artifactId>
<version>11.0.0</version>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2、yml 配置
# 端口
server:
port: 7002
# 應用名稱
spring:
application:
name: graphql-demo
# graphql 相關配置
graphql:
servlet:
mapping: /graphql
enabled: true
corsEnabled: false # 關閉跨域,僅使用瀏覽器插件調試時設置爲false
playground:
cdn:
enabled: true # playground 使用 cdn 的靜態文件
# if you want to @ExceptionHandler annotation for custom GraphQLErrors
exception-handlers-enabled: true
contextSetting: PER_REQUEST_WITH_INSTRUMENTATION
tools:
#掃描 resource 下 .graphql 後綴的文件
schema-location-pattern: "**/*.graphql"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
3、新建一個 clazz.graphql 文件
#定義查詢類型和更改類型
schema {
query: Query
mutation: Mutation
}
#查詢方法, 類型來源於上面定義的 Query
type Query{
#查詢所有班級,返回 list<Clazz>
listClazz: [Clazz]
#根據名稱查詢班級,返回單個 Clazz 對象
listClazzByName(name:String!): Clazz
}
#變更方法 , 類型來源於上面定義的 Mutation
type Mutation{
# 新增班級(返回 Result 對象)
add(code:String!,name:String!,description:String!): Result
# 修改班級(返回 Result 對象)
edit(id:String!,code:String!,name:String!,description:String!): Result
# 刪除班級(返回 Result 對象)
del(id:String!): Result
# 創建班級(入參類型爲對象 ClazzInput)
addByInput(input: ClazzInput!): Result
}
#班級實體
type Clazz{
#id
id : String
#編號
code : String!
#名稱
name : String!
#描述
description : String!
}
#班級 input 對象
input ClazzInput{
#id
id : String
#編號
code : String!
#名稱
name : String!
#描述
description : String!
}
type Result{
#狀態碼
code : Int!
#狀態信息
msg : String!
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
4、相關語法解釋
.graphql 文件中註釋用: #註釋內容
Query下定義的是查詢相關接口,Mutation下定義的是修改相關接口
Query 和 Mutation 方法格式
Query中方法格式爲 : 方法名:返回類型 例如:listClazz: [Clazz]
方法名(參數名:參數類型):返回類型 例如:listClazzByName(name:String!): Clazz 參數類型後面加 !
代表這個參數不能爲空,可爲空則不加 ! 即可
Mutation 中方法格式基本和 Query 一致
type Clazz 你可以理解爲定義一個名爲 Clazz 的 java 實體類,裏面就是它的一些屬性,type Result 也一樣
input ClazzInput 則是定義一個輸入類型,可以看到屬性基本和 Clazz 一致,只是定義時將 type 改成了 input,作用我們可以理解爲,我們可以直接傳輸這個對象,稍後來進行講解
5、編寫 java 實體類
先把兩個對應的 java 實體類寫好,屬性同 graphql 文件中對象一致
package com.wxw.notes.graphql.demo.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author wuxiongwei
* @date 2021/5/25 16:38
* @Description
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Clazz {
private String id;
private String code;
private String name;
private String description;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.wxw.notes.graphql.demo.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author wuxiongwei
* @date 2021/5/25 16:38
* @Description
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class ClazzInput {
private String id;
private String code;
private String name;
private String description;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.wxw.notes.graphql.demo.response;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Result {
private Integer code;
private String msg;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
6、編寫 Query 和 Mutation 解析器
package com.wxw.notes.graphql.demo.resolver;
import com.wxw.notes.graphql.demo.entity.Clazz;
import com.wxw.notes.graphql.demo.entity.ClazzInput;
import com.wxw.notes.graphql.demo.response.Result;
import com.wxw.notes.graphql.demo.service.ClazzService;
import graphql.kickstart.tools.GraphQLMutationResolver;
import graphql.kickstart.tools.GraphQLQueryResolver;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @author wuxiongwei
* @date 2021/5/25 16:37
* @Description
*/
@Component
public class ClazzResolver implements GraphQLQueryResolver, GraphQLMutationResolver {
private final ClazzService clazzService;
public ClazzResolver(ClazzService clazzService) {
this.clazzService = clazzService;
}
public List<Clazz> listClazz(){
return clazzService.list();
}
public Clazz listClazzByName(String name){
return clazzService.listByName(name);
}
public Result add(String code, String name, String description){
return clazzService.add(code,name,description);
}
public Result del(String id){
return clazzService.del(id);
}
public Result edit(String id,String code, String name, String description){
return clazzService.edit(id,code,name,description);
}
public Result addByInput(ClazzInput cla){
return clazzService.addByInput(cla);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
GraphQLQueryResolver 顧名思義就是 Query 查詢相關的解析器了
GraphQLMutationResolver 就是 Mutation 更改相關的解析器了
我這裏就直接寫在一個類裏面了(可以選擇分開寫兩個類去分別實現),同時實現
GraphQLQueryResolver 和 GraphQLMutationResolver
7、編寫 Service 層方法
在 service 層,我們一般是查詢數據庫數據,之前怎麼查現在還是怎麼查,在這裏我就簡單在內存裏面初始化一些數據了
package com.wxw.notes.graphql.demo.service;
import com.wxw.notes.graphql.demo.entity.Clazz;
import com.wxw.notes.graphql.demo.entity.ClazzInput;
import com.wxw.notes.graphql.demo.response.Result;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* @author wuxiongwei
* @date 2021/5/25 16:38
* @Description
*/
@Service
public class ClazzService {
private List<Clazz> clazzList = new ArrayList<Clazz>(){{
add(Clazz.builder().id(UUID.randomUUID().toString()).code("001").name("三年二班").description("加里頓第一班").build());
}};
public Clazz listByName(String name){
Optional<Clazz> first = clazzList.stream().filter(clazz -> clazz.getName().equals(name)).findFirst();
return first.orElse(null);
}
public List<Clazz> list(){
return clazzList;
}
public Result add(String code, String name, String description){
Clazz clazz = new Clazz();
clazz.setId(UUID.randomUUID().toString());
clazz.setCode(code);
clazz.setName(name);
clazz.setDescription(description);
clazzList.add(clazz);
return Result.builder().code(200).msg("success").build();
}
public Result del(String id){
clazzList = clazzList.stream().filter(clazz -> !clazz.getId().equals(id)).collect(Collectors.toList());
return Result.builder().code(200).msg("success").build();
}
public Result edit(String id,String code, String name, String description){
del(id);
add(code, name, description);
return Result.builder().code(200).msg("success").build();
}
public Result addByInput(ClazzInput cla){
Clazz clazz = new Clazz();
clazz.setId(UUID.randomUUID().toString());
clazz.setCode(cla.getCode());
clazz.setName(cla.getName());
clazz.setDescription(cla.getDescription());
clazzList.add(clazz);
return Result.builder().code(200).msg("success").build();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
8、見證 GraphQL 使用
一切準備工作就緒之後,我們用 playground 圖形化工具來看看 graphql 到底怎麼來進行使用
啓動我們的工程,訪問 localhost:7002/playground
就可以看到下面這個界面了,默認界面風格是黑色,如果你想要修改成我這顏色,點擊右上角設置
“editor.theme” 的值修改成 “light” 然後點擊右上角保存即可
左邊的查詢語句,可能大家一進來就是空的,截圖的查詢語句是我這邊之前測試寫的
接下來,我們依次來調用下我們寫的 graphql 方法,看看怎麼調用
首先調用查詢所有班級的方法,可以點開右側 DOCS 文檔,對照來寫,我們想查詢哪些信息,我左邊就寫哪些字段,我先查詢所有字段
8.1、Query 查詢
# listClazz 調用的方法名
# id,code,name,description 調用後想要得到的返回值
{
listClazz {
id
code
name
description
}
}
1
2
3
4
5
6
7
8
9
10
這個時候我們來解決前端給我的問題,假如小夥子不要 id 了,簡單,你自己查詢的時候直接去掉就行了,這樣我就不給你 id 了,如下
# listClazz 調用的方法名
# code,name,description 調用後想要得到的返回值
{
listClazz {
code
name
description
}
}
1
2
3
4
5
6
7
8
9
再調用根據名稱查詢班級的方法,直接放入參數
# listClazzByName 調用的方法名
# name 參數屬性名,三年二班 參數值
# code,name,description 調用後想要得到的返回值
listClazzByName(name:"三年二班"){
code
name
description
}
1
2
3
4
5
6
7
8
8.2 、使用變量 Variables
再調用根據名稱查詢班級的方法,使用變量 Variables 傳入參數
# query 查詢關鍵字
# listClazzByName 別名
# $name:String! name 爲聲明變量,String 類型,不爲空(變量前加 $)
# listClazzByName 方法名,name 屬性名,$name 引用上面聲明的變量
# code,name,description 查詢後想要的返回值
query listClazzByName($name:String!){
listClazzByName(name:$name){
code
name
description
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
# json 格式
{
"name":"三年二班"
}
1
2
3
4
8.3、 Mutation 變更
我們來單獨寫變更中的 新增
# mutation 變更關鍵字
# add 方法名
# code,name,description 參數
# code,msg 請求後想要返回的返回值
mutation{
add(code: "001"
name: "三年三班"
description: "加里頓第二班級"){
code
msg
}
}
1
2
3
4
5
6
7
8
9
10
11
12
新增之後,再查詢所有看看,可以看到已經成功添加了
8.4、Input 輸入類型
接下來我們看看上文說到的輸入類型怎麼使用
# mutation 變更關鍵字
# addByInput 別名
# $clazzInput:ClazzInput! ,聲明變量 $clazzInput ,類型爲 ClazzInput ,不爲空
# addByInput 接口名,input:$clazzInput input 入參類型, $clazzInput 引用變量
# code,msg 調用接口後想要的返回值
mutation addByInput($clazzInput:ClazzInput!){
addByInput(input:$clazzInput){
code
msg
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
# 參數
{
"clazzInput": {
"code": "003",
"name": "三年四班",
"description": "加里頓第三班"
}
}
1
2
3
4
5
6
7
8
新增之後,再查詢所有看看,可以看到已經成功添加了
好了,基本用法就分享到這裏了,大家有興趣可以自行查閱官網
官網地址
四、總結
1、這只是一個簡單的 demo,我們 java 中複雜的實體對象怎麼實現呢?嵌套對象,嵌套集合等等
2、多個 .graphql 文件怎麼引用呢?我們不可能一個 graphql 文件裏面把所有的實體類都寫了
3、使用 graphql 我們會遇到哪些問題?怎麼去解決定位呢?
是不是覺得不過癮,感覺還沒有看到你想要的,想了解更多的可以進入下一篇深入瞭解,源碼地址也會在下一篇進行分享
————————————————