GraphQL入門(mén)總體創(chuàng)建教程
簡(jiǎn)介
因?yàn)槟壳白龅捻?xiàng)目查詢提供的接口都使用GraphQL替代典型的REST API,所以有必要去對(duì)它進(jìn)行了解和源碼的閱讀。本篇主要大致了解下GraphQL。
一種用于API的查詢語(yǔ)言,讓你的請(qǐng)求數(shù)據(jù)不多不少。前端按需獲取,后端動(dòng)態(tài)返回(不需要的數(shù)據(jù)不會(huì)返回甚至不會(huì)查庫(kù)),對(duì)比起典型的REST API將更加靈活,后端代碼提供可選能力。如果增加新的字段應(yīng)用不想處理這部分?jǐn)?shù)據(jù)可以不用區(qū)分版本。
后端確定哪些接口行為是被允許的,前端按需獲取數(shù)據(jù),讓你的請(qǐng)求數(shù)據(jù)不多不少。
詳細(xì)的介紹可以參考官方首頁(yè)配合動(dòng)圖更加清晰。
簡(jiǎn)單示例
最好使用Spring Initializr去創(chuàng)建一個(gè)新的項(xiàng)目,不會(huì)產(chǎn)生一些沖突。
maven依賴
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="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"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.6.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.graphql-java.tutorial</groupId> <artifactId>book-details</artifactId> <version>0.0.1-SNAPSHOT</version> <name>book-details</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/com.graphql-java/graphql-java --> <dependency> <groupId>com.graphql-java</groupId> <artifactId>graphql-java</artifactId> <version>11.0</version> </dependency> <!-- https://mvnrepository.com/artifact/com.graphql-java/graphql-java-spring-boot-starter-webmvc --> <dependency> <groupId>com.graphql-java</groupId> <artifactId>graphql-java-spring-boot-starter-webmvc</artifactId> <version>1.0</version> </dependency> <!-- https://mvnrepository.com/artifact/com.google.guava/guava --> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>26.0-jre</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>central</id> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> <layout>default</layout> <!-- 是否開(kāi)啟發(fā)布版構(gòu)件下載 --> <releases> <enabled>true</enabled> </releases> <!-- 是否開(kāi)啟快照版構(gòu)件下載 --> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> </project>
Schema
在src/main/resources
中創(chuàng)建schema.graphqls
文件:
type Query { bookById(id: ID): Book } type Book { id: ID name: String pageCount: Int author: Author } type Author { id: ID firstName: String lastName: String }
可以看到定義了一個(gè)bookById查詢,用于根據(jù)id查詢書(shū)籍,書(shū)籍中包含id、name、pageCount、author屬性,其中author是一個(gè)復(fù)合類(lèi)型所以定義了type Author
。
上面顯示的用于描述schema的特定于域的語(yǔ)言稱為schema定義語(yǔ)言或SDL。更多細(xì)節(jié)可以在這里找到。
解析schema并關(guān)聯(lián)對(duì)應(yīng)的fetchers
一旦我們有了這個(gè)文件,我們需要通過(guò)讀取文件并解析它并且添加代碼來(lái)為它獲取數(shù)據(jù)使它“栩栩如生”。
package com.graphqljava.tutorial.bookdetails; import com.google.common.base.Charsets; import com.google.common.io.Resources; import graphql.GraphQL; import graphql.schema.GraphQLSchema; import graphql.schema.idl.RuntimeWiring; import graphql.schema.idl.SchemaGenerator; import graphql.schema.idl.SchemaParser; import graphql.schema.idl.TypeDefinitionRegistry; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import java.io.IOException; import java.net.URL; import static graphql.schema.idl.TypeRuntimeWiring.newTypeWiring; @Component public class GraphQLProvider { private GraphQL graphQL; /** * 注入GraphQL實(shí)例,GraphQL Java Spring適配器將使用GraphQL實(shí)例使我們的schema可用,通過(guò)Http-使用默認(rèn)的"/graphql"url路徑 * * @return */ @Bean public GraphQL graphQL() { return graphQL; } @PostConstruct public void init() throws IOException { //使用Resources讀取graphqls文件 URL url = Resources.getResource("schema.graphqls"); //拿到graphqls文件內(nèi)容 String sdl = Resources.toString(url, Charsets.UTF_8); GraphQLSchema graphQLSchema = buildSchema(sdl); this.graphQL = GraphQL.newGraphQL(graphQLSchema).build(); } @Autowired GraphQLDataFetchers graphQLDataFetchers; /** * 創(chuàng)建GraphQLSchema實(shí)例:解析schema并關(guān)聯(lián)fetcher * * @param sdl * @return */ private GraphQLSchema buildSchema(String sdl) { TypeDefinitionRegistry typeRegistry = new SchemaParser().parse(sdl); RuntimeWiring runtimeWiring = buildWiring(); SchemaGenerator schemaGenerator = new SchemaGenerator(); return schemaGenerator.makeExecutableSchema(typeRegistry, runtimeWiring); } /** * 根據(jù)層級(jí)去關(guān)聯(lián)fetcher構(gòu)建RuntimeWiring。最外層為Query可以提供bookById所需參數(shù)。第二層為Book-經(jīng)過(guò)第一層獲得的,可以為author提供所需參數(shù)。 * * @return */ private RuntimeWiring buildWiring() { return RuntimeWiring.newRuntimeWiring() .type(newTypeWiring("Query") .dataFetcher("bookById", graphQLDataFetchers.getBookByIdDataFetcher())) .type(newTypeWiring("Book") .dataFetcher("author", graphQLDataFetchers.getAuthorDataFetcher())) .build(); } }
package com.graphqljava.tutorial.bookdetails; import com.google.common.collect.ImmutableMap; import graphql.schema.DataFetcher; import org.springframework.stereotype.Component; import java.util.Arrays; import java.util.List; import java.util.Map; @Component public class GraphQLDataFetchers { /** * books靜態(tài)數(shù)據(jù) */ private static List<Map<String, String>> books = Arrays.asList( ImmutableMap.of("id", "book-1", "name", "Harry Potter and the Philosopher's Stone", "pageCount", "223", "authorId", "author-1"), ImmutableMap.of("id", "book-2", "name", "Moby Dick", "pageCount", "635", "authorId", "author-2"), ImmutableMap.of("id", "book-3", "name", "Interview with the vampire", "pageCount", "371", "authorId", "author-3") ); /** * autors靜態(tài)數(shù)據(jù) */ private static List<Map<String, String>> authors = Arrays.asList( ImmutableMap.of("id", "author-1", "firstName", "Joanne", "lastName", "Rowling"), ImmutableMap.of("id", "author-2", "firstName", "Herman", "lastName", "Melville"), ImmutableMap.of("id", "author-3", "firstName", "Anne", "lastName", "Rice") ); /** * bookById的fetcher,這里只是簡(jiǎn)單的通過(guò)靜態(tài)數(shù)據(jù)進(jìn)行篩選,具體生產(chǎn)使用sql進(jìn)行查詢 * * @return */ public DataFetcher getBookByIdDataFetcher() { return dataFetchingEnvironment -> { // 獲得查詢篩選參數(shù) String bookId = dataFetchingEnvironment.getArgument("id"); return books .stream() .filter(book -> book.get("id").equals(bookId)) .findFirst() .orElse(null); }; } /** * 第二層author fetcher * * @return */ public DataFetcher getAuthorDataFetcher() { return dataFetchingEnvironment -> { //獲得上級(jí)對(duì)象 Map<String, String> book = dataFetchingEnvironment.getSource(); //根據(jù)上級(jí)對(duì)象找到關(guān)聯(lián)id(相當(dāng)于外鍵) String authorId = book.get("authorId"); return authors .stream() .filter(author -> author.get("id").equals(authorId)) .findFirst() .orElse(null); }; } }
DataFetchers
對(duì)于GraphQL Java服務(wù)器來(lái)說(shuō),最重要的概念可能是DataFetcher:DataFetcher在執(zhí)行查詢時(shí)獲取一個(gè)字段的數(shù)據(jù)。
GraphQL Java在執(zhí)行查詢時(shí),會(huì)為查詢中遇到的每個(gè)字段調(diào)用相應(yīng)的DataFetcher。DataFetcher是函數(shù)接口,函數(shù)具有一個(gè)參數(shù)為DataFetchingEnvironment類(lèi)型。
public interface DataFetcher<T> { T get(DataFetchingEnvironment dataFetchingEnvironment) throws Exception; }
Default DataFetchers
如上我們實(shí)現(xiàn)了兩個(gè)DataFetchers。如上所述,如果你不指定一個(gè),PropertyDataFetcher則是被默認(rèn)使用。比如上面的例子中Book.id,Book.name,Book.pageCount,Author.id,Author.firstName和Author.lastName都有一個(gè)PropertyDataFetcher與之關(guān)聯(lián)。
PropertyDataFetcher嘗試以多種方式查找Java對(duì)象的屬性。如果是java.util.Map
,簡(jiǎn)單的通過(guò)key查找。這對(duì)我們來(lái)說(shuō)非常好,因?yàn)閎ook和author Maps的keys與schema中指定的字段相同。
總體創(chuàng)建過(guò)程
資料
Getting started with Spring Boot
以上就是GraphQL入門(mén)總體創(chuàng)建教程的詳細(xì)內(nèi)容,更多關(guān)于GraphQL創(chuàng)建教程的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
編碼實(shí)現(xiàn)從無(wú)序鏈表中移除重復(fù)項(xiàng)(C和JAVA實(shí)例)
如果不能使用臨時(shí)緩存,你怎么實(shí)現(xiàn)無(wú)序鏈表中移除重復(fù)項(xiàng)(?C和JAVA實(shí)例無(wú)序鏈表中移除重復(fù)項(xiàng)。2013-10-10如何讓Jackson JSON生成的數(shù)據(jù)包含的中文以u(píng)nicode方式編碼
這篇文章主要介紹了如何讓Jackson JSON生成的數(shù)據(jù)包含的中文以u(píng)nicode方式編碼。需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助2013-12-12Spring探秘之如何妙用BeanPostProcessor
BeanPostProcessor也稱為Bean后置處理器,它是Spring中定義的接口,在Spring容器的創(chuàng)建過(guò)程中會(huì)回調(diào)BeanPostProcessor中定義的兩個(gè)方法,這篇文章主要給大家介紹了關(guān)于Spring探秘之如何妙用BeanPostProcessor的相關(guān)資料,需要的朋友可以參考下2022-01-01Java下載文件時(shí)文件名亂碼問(wèn)題解決辦法
我最近在開(kāi)發(fā)時(shí)遇到了文件另存為時(shí)文件名出現(xiàn)亂碼,在火狐上正常的文件名,在IE中又出現(xiàn)亂碼問(wèn)題,然后好不容易在IE下調(diào)試好了文件名亂碼問(wèn)題,在火狐下又出現(xiàn)亂碼,最后終于感覺(jué)這樣是能解決了。具體如下:2013-04-04springboot整合持久層的方法實(shí)現(xiàn)
本文主要介紹了springboot整合持久層的方法實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09詳解Java中l(wèi)og4j.properties配置與加載應(yīng)用
這篇文章主要介紹了 log4j.properties配置與加載應(yīng)用的相關(guān)資料,需要的朋友可以參考下2018-02-02Java自定義類(lèi)數(shù)組報(bào)null的相關(guān)問(wèn)題及解決
這篇文章主要介紹了Java自定義類(lèi)數(shù)組報(bào)null的相關(guān)問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09淺談 java中ArrayList、Vector、LinkedList的區(qū)別聯(lián)系
ArrayList,Vector底層是由數(shù)組實(shí)現(xiàn),LinkedList底層是由雙線鏈表實(shí)現(xiàn),從底層的實(shí)現(xiàn)可以得出性能問(wèn)題ArrayList,Vector插入速度較慢,查詢速度較快,而LinkedList插入速度較快,而查詢速度較慢。再者由于Vevtor使用了線程安全鎖,所以ArrayList的運(yùn)行效率高于Vector2015-11-11springBoot項(xiàng)目中使用@Value取值出現(xiàn)的問(wèn)題及解決
這篇文章主要介紹了springBoot項(xiàng)目中使用@Value取值出現(xiàn)的問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07