Spring Boot + GraphQL 才是 API 的未來!
前言
在淺嘗GraphQL一文描述了GraphQL及基本使用,本文提供一個基本示例,描述如何基于spring boot的web項目快速應用。
graphql-java的官方文檔:Getting started with GraphQL Java and Spring Boot,提供了相關依賴用以快速配置,但是個人真心不建議使用這個庫及相關配置方式來搭建腳手架,在實際開發(fā)中,業(yè)務比較復雜的時候,會導致需要配置的業(yè)務代碼比較多也比較繁瑣,相對下面這種方式,代碼復雜性比較高。
本文提供一種更靈活快捷的方式,在spring boot項目中快速應用開發(fā)。使用的依賴也和上面官方提供的都不一樣,請注意區(qū)分。
快速開始
創(chuàng)建spring boot工程
通過Spring Initializr快速搭建,我選的jdk版本及spring boot版本,如下所示,其它版本未做兼容性測試。

點擊下方的Generate按鈕:

打開工程結構如下,我將application.properties刪除了替換成applicaiton.yml,因為我個人比較喜歡yaml的配置方式:

引入相關依賴
pom.xml配置如下:
"1.0"?encoding="UTF-8"?>
"http://maven.apache.org/POM/4.0.0"?xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
?xsi:schemaLocation="http://maven.apache.org/POM/4.0.0?https://maven.apache.org/xsd/maven-4.0.0.xsd">
?4.0.0
?
??org.springframework.boot
??spring-boot-starter-parent
??2.4.6
?? ?
?
?com.xuxd
?graphql.demo
?0.0.1-SNAPSHOT
?graphql.demo
?GraphQL?Demo?project?for?Spring?Boot
?
??1.8
??1.8
??1.8
??UTF-8
??UTF-8
??1.18.20
??11.0.1
??2.8.7
?
?
??
???org.springframework.boot
???spring-boot-starter
??
??
???org.springframework.boot
???spring-boot-starter-web
??
??
???org.springframework.boot
???spring-boot-starter-test
???test
??
??
???org.projectlombok
???lombok
???${lombok.version}
???provided
??
??
???com.graphql-java-kickstart
???graphql-java-tools
???${graphql-java-tools.version}
??
??
???com.google.code.gson
???gson
???${gson.version}
??
?
?
??
???
????org.springframework.boot
????spring-boot-maven-plugin
???
??
?
初始化GraphQL實例
我們將創(chuàng)建一個GraphQL實例并將其注冊到spring容器中,代碼如下。
Spring Boot 基礎就不介紹了,推薦下這個實戰(zhàn)教程:https://www.javastack.cn/categories/Spring-Boot/
@Component
public?class?GraphQLProvider?{
????private?GraphQL?graphQL;
????@Autowired
????private?IItemService?itemService;
????@Bean
????public?GraphQL?graphQL()?{
????????return?graphQL;
????}
????@PostConstruct
????public?void?init()?throws?IOException?{
????????GraphQLSchema?graphQLSchema?=?SchemaParser.newParser()
????????????.file("graphql/base.graphqls")
????????????.resolvers(new?Query(),?new?Mutation())
????????????.file("graphql/item.graphqls")
????????????.resolvers(new?ItemResolver(itemService))
//????????????.file("book.graphqls")
//????????????.resolvers(new?BookResolver())??//其它定義照上面的示例,繼續(xù)增加
????????????.build().makeExecutableSchema();
????????this.graphQL?=?graphQL.newGraphQL(graphQLSchema).build();
????}
}
關于*.graphqls或者對應的Resolver如ItemResolver,可以參看淺嘗GraphQL相關描述,這里只是作了微調整,相關代碼如下:
base.grqphqls
schema?{
????#?查詢
????query:?Query
????#?更新
????mutation:?Mutation
}
type?Query?{
????version:?String
}
type?Mutation?{
????version:?String
}
item.graphqls
#?定義一個查詢類型
extend?type?Query?{
????queryItemList:?ItemList??#?定義查詢項目列表
????queryById(id:?ID):?Item
}
extend?type?Mutation?{
????updateName(param:?Param):?Item
}
#?定義項目字段
type?Item?{
????id:?ID!
????code:?String!
????name:?String!
}
type?ItemList?{
????itemList:?[Item!]!??#獲取項目列表
????total:?Int!??????#?獲取項目總數
}
input?Param?{
????id:?ID!
????name:?String!
}
ItemResolver
public?class?ItemResolver?implements?GraphQLQueryResolver,?GraphQLMutationResolver?{
????private?IItemService?itemService;
????public?ItemResolver(IItemService?itemService)?{
????????this.itemService?=?itemService;
????}
????//?對應item.graphqls里的queryItemList
????public?ItemList?queryItemList()?{
????????return?itemService.queryItemList();
????}
????public?Item?queryById(Long?id)?{
????????return?itemService.queryById(id);
????}
????public?Item?updateName(Param?param)?{
????????return?itemService.updateName(param);
????}
}
相關業(yè)務代碼比較多,就不一一貼了。
關注公眾號,學習更多 Java 干貨!
提供API
?result?=?new?HashMap<>();????????ExecutionResult?executionResult?=?graphQL.execute(executionInput);????????List?errors?=?executionResult.getErrors();????????if?(errors?!=?null?&&?!errors.isEmpty())?{????????????result.put("errors",?errors);????????????return?result;????????}????????return?executionResult.getData();????}}到這一步,其實基本功能都已配置完成,可以啟動項目進行相關測試了。整個項目的代碼結構如下,我盡量用了一個比較常規(guī)的web項目結構(controller,service,dao等):" data-itemshowtype="0" tab="innerlink" data-linktype="2" data-darkmode-color-16344674345694="rgb(141, 141, 141)" data-darkmode-original-color-16344674345694="#fff|rgb(89, 89, 89)" wah-hotarea="click" hasload="1" style="outline: 0px; color: rgb(125, 144, 169); cursor: pointer; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important;"> @RestController
@RequestMapping("/graphql")
@Log
public?class?GraphqlController?{
????@Autowired
????private?GraphQL?graphQL;
????@PostMapping
????public?Object?execute(@RequestBody?GraphqlRequest?request)?{
????????ExecutionInput?executionInput?=?ExecutionInput.newExecutionInput()
????????????.query(request.getQuery())
????????????.variables(request.getVariables())
????????????.build();
????????Map?result?=?new?HashMap<>();
????????ExecutionResult?executionResult?=?graphQL.execute(executionInput);
????????List?errors?=?executionResult.getErrors();
????????if?(errors?!=?null?&&?!errors.isEmpty())?{
????????????result.put("errors",?errors);
????????????return?result;
????????}
????????return?executionResult.getData();
????}
}

測試
示例中總共提供了3個接口,兩個查詢一個更新,分別進行測試:
ItemList?queryItemList();
Item?queryById(Long?id);
Item?updateName(Param?param);
查詢所有項目列表(只獲取每個項目的編碼和名稱,以及列表總數):

根據ID查詢,獲取項目的id和名稱

更新指定ID的項目名稱
我們項目Id為1編碼為test的項目修改為“java項目”

再查詢一下,可以看到結果更新了:

結束語
這樣整個項目的GraphQL相關的基本配置已經完成,可以進行業(yè)務開發(fā)了。
歡迎關注“Java引導者”,我們分享最有價值的Java的干貨文章,助力您成為有思想的Java開發(fā)工程師!
