<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Java 后端的未來(lái)? GraphQL?

          共 7730字,需瀏覽 16分鐘

           ·

          2021-11-03 17:05

          ?GraphQL 既是一種用于 API 的查詢(xún)語(yǔ)言也是一個(gè)滿(mǎn)足你數(shù)據(jù)查詢(xún)的運(yùn)行時(shí)。


          003e2bcb221eb7a276adaca61af28e20.webp

          GraphQL 既是一種用于 API 的查詢(xún)語(yǔ)言也是一個(gè)滿(mǎn)足你數(shù)據(jù)查詢(xún)的運(yùn)行時(shí)。GraphQL 對(duì)你的 API 中的數(shù)據(jù)提供了一套易于理解的完整描述,使得客戶(hù)端能夠準(zhǔn)確地獲得它需要的數(shù)據(jù),而且沒(méi)有任何冗余,也讓 API 更容易地隨著時(shí)間推移而演進(jìn),還能用于構(gòu)建強(qiáng)大的開(kāi)發(fā)者工具。

          GraphQL 是一個(gè)用于 API 的查詢(xún)語(yǔ)言,是一個(gè)使用基于類(lèi)型系統(tǒng)來(lái)執(zhí)行查詢(xún)的服務(wù)端運(yùn)行時(shí)(類(lèi)型系統(tǒng)由你的數(shù)據(jù)定義)。GraphQL 并沒(méi)有和任何特定數(shù)據(jù)庫(kù)或者存儲(chǔ)引擎綁定,而是依靠你現(xiàn)有的代碼和數(shù)據(jù)支撐.

          以上是 GraphQL 的一些介紹和描述. 看了你可能會(huì)一臉懵逼, 沒(méi)事, 我也是(哈哈)....... 因此, 我們先看使用后理解, 開(kāi)始我們永久不衰的 Hello World.

          1. 項(xiàng)目構(gòu)建

          1.1 創(chuàng)建項(xiàng)目

          這里以** SpringBoot 2.1.2.RELEASE** 為例, 構(gòu)建工具選用 Gradle, 快速創(chuàng)建一個(gè) Web 項(xiàng)目. 需要的依賴(lài)有

          dependencies {
          implementation 'com.graphql-java:graphql-java:11.0'
          implementation 'com.graphql-java:graphql-java-spring-boot-starter-webmvc:1.0'
          implementation 'com.google.guava:guava:26.0-jre'
          implementation 'org.springframework.boot:spring-boot-starter-web'
          testImplementation 'org.springframework.boot:spring-boot-starter-test'
          }

          功能實(shí)現(xiàn)一個(gè)書(shū)本及作者信息查詢(xún). 所有數(shù)據(jù)用集合模擬如下:

              private static List> 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")
          );

          private static List> 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")
          );

          1.2 創(chuàng)建 Schema

          resources 下新建 schema.graphqls 文件用于描述需要的 API.

          type Query {
          bookById(id: ID): Book
          }

          type Book {
          id: ID
          name: String
          pageCount: Int
          author: Author
          }

          type Author {
          id: ID
          firstName: String
          lastName: String
          }

          該語(yǔ)句定義了兩個(gè)實(shí)體: Book 和 Author, 并且定義了一個(gè)查詢(xún): bookById, 通過(guò)書(shū)本 id 查詢(xún) Book 信息, Book 中又包含 Author 信息, 因此需要級(jí)聯(lián)查詢(xún) Author.

          1.3 創(chuàng)建 GraphQL 實(shí)例

          創(chuàng)建一個(gè) GraphQLProvider.java 用于初始化和暴露 GraphQL 實(shí)例.

          @Component
          public class GraphQLProvider {

          private GraphQL graphQL;

          @Bean
          public GraphQL graphQL() {
          return graphQL;
          }

          @PostConstruct
          public void init() throws IOException {
          URL url = Resources.getResource("schema.graphqls");
          String sdl = Resources.toString(url, Charsets.UTF_8);
          GraphQLSchema graphQLSchema = buildSchema(sdl);
          this.graphQL = GraphQL.newGraphQL(graphQLSchema).build();
          }

          private GraphQLSchema buildSchema(String sdl) {
          // TODO: 在這里構(gòu)造 Schema
          }
          }

          基于 schema.graphqls 構(gòu)造 GraphQL 對(duì)象, 并暴露在 IOC 容器, GraphQL 適配器將會(huì)在此 GraphQL 對(duì)象之上構(gòu)建 Schema 中的 API, 且默認(rèn)的請(qǐng)求路徑為 /graphql.

          1.4 構(gòu)建 GraphQLSchema

          上面我們構(gòu)建 GraphQL 實(shí)例還需要實(shí)現(xiàn) buildSchema 方法, 此方法將會(huì)創(chuàng)建 GraphQLSchema 對(duì)象并獲取數(shù)據(jù).

              @Autowired
          GraphQLDataFetchers graphQLDataFetchers;

          private GraphQLSchema buildSchema(String sdl) {
          TypeDefinitionRegistry typeRegistry = new SchemaParser().parse(sdl);
          RuntimeWiring runtimeWiring = buildWiring();
          SchemaGenerator schemaGenerator = new SchemaGenerator();
          return schemaGenerator.makeExecutableSchema(typeRegistry, runtimeWiring);
          }

          private RuntimeWiring buildWiring() {
          return RuntimeWiring.newRuntimeWiring()
          .type(newTypeWiring("Query")
          .dataFetcher("bookById", graphQLDataFetchers.getBookByIdDataFetcher()))
          .type(newTypeWiring("Book")
          .dataFetcher("author", graphQLDataFetchers.getAuthorDataFetcher()))
          .build();
          }

          TypeDefinitionRegistry 是 Schema 文件的解析器。SchemaGenerator 結(jié)合 TypeDefinitionRegistryRuntimeWiring 來(lái)實(shí)際構(gòu)造 GraphQLSchema. buildWiring 使用 graphQLDataFetchers 這個(gè) Bean 來(lái)實(shí)際注冊(cè)了兩個(gè) DataFetcher.

          • 一個(gè)通過(guò)書(shū)本 ID 查詢(xún)書(shū)本的 DataFetcher

          • 一個(gè)獲取書(shū)本中作者信息的 DataFetcher

          DataFetcher 和如何創(chuàng)建 graphQLDataFetchers 稍后說(shuō)明. 總的來(lái)說(shuō), 創(chuàng)建 GraphQLGraphQLSchema 的流程如下:

          2a46760c66b7bf75d738b113d9572047.webp

          1.5 DataFetcher

          DataFetcher 是 GraphQL 最重要的概念之一, 用于查詢(xún)時(shí)獲取一個(gè)字段的數(shù)據(jù). 當(dāng) GraphQL 執(zhí)行查詢(xún)時(shí), 他會(huì)為每一個(gè)字段執(zhí)行合適的 DataFetcher. DataFetcher 是一個(gè)只有一個(gè)方法的接口:

          public interface DataFetcher {
          T get(DataFetchingEnvironment dataFetchingEnvironment) throws Exception;
          }

          Schema 中的每個(gè)字段都需要一個(gè) DataFetcher, 如果字段沒(méi)有指定 DataFetcher, 那么就會(huì)使用的 PropertyDataFetcher 作為默認(rèn)的 DataFetcher.

          創(chuàng)建 1.4 節(jié)中的 graphQLDataFetchers 實(shí)現(xiàn) GraphQLDataFetchers.java:

          @Component
          public class GraphQLDataFetchers {

          private static List> 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")
          );

          private static List> 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")
          );

          public DataFetcher getBookByIdDataFetcher() {
          return dataFetchingEnvironment -> {
          String bookId = dataFetchingEnvironment.getArgument("id");
          return books
          .stream()
          .filter(book -> book.get("id").equals(bookId))
          .findFirst()
          .orElse(null);
          };
          }

          public DataFetcher getAuthorDataFetcher() {
          return dataFetchingEnvironment -> {
          Map book = dataFetchingEnvironment.getSource();
          String authorId = book.get("authorId");
          return authors
          .stream()
          .filter(author -> author.get("id").equals(authorId))
          .findFirst()
          .orElse(null);
          };
          }
          }

          這里我們創(chuàng)建了兩個(gè) DataFetcher: 通過(guò) ID 獲取書(shū)本信息的 getBookByIdDataFetcher 以及獲取書(shū)本中作者信息的 getAuthorDataFetcher.

          至此 GraphQL 工程就搭建起來(lái)了, 基本結(jié)構(gòu)如下:

          0e25adb06f7e3268791f9405d95e746a.webp

          2. API 查詢(xún)

          啟動(dòng) SpringBoot 應(yīng)用 BookDetailsApplication 后, 我們就可以通過(guò) http://localhost:8080/graphql 進(jìn)行 API 訪問(wèn). 你可以下載 GraphQL 查詢(xún)工具查詢(xún)(工具下載: https://github.com/prisma/graphql-playground), 如下:

          7f95a54b75b7ace5b15baee342357486.webp

          也可以通過(guò) PostMan 查詢(xún), GraphQL 可以支持 GET 和 POST 兩種請(qǐng)求查詢(xún).

          2.1 Postman 通過(guò) POST GraphQL 請(qǐng)求體查詢(xún)

          Postman 中請(qǐng)求體已經(jīng)支持了 GraphQL, 查詢(xún)語(yǔ)句如下:

          {
          bookById(id: "book-1"){
          id
          name
          pageCount
          author {
          firstName
          lastName
          }
          }
          }

          a411eb35ef792cbfb0af3e85cdc36af4.webp

          2.2 Postman 通過(guò)普通 POST 請(qǐng)求查詢(xún)

          正常的 POST 請(qǐng)求也可以查詢(xún) GraphQL, 需要請(qǐng)求體攜帶一個(gè) query 參數(shù), 該參數(shù)即是上面的查詢(xún)語(yǔ)句, 但是由于請(qǐng)求必須是 application/json, 而 JSON 對(duì)多行字符串不支持, 因此需要做好 JSON 處理

          76139ecface9f531967b9fb0ac1c25ad.webp

          由此也可以看出, GraphQL 請(qǐng)求體實(shí)際為我們做的就是請(qǐng)求參數(shù)的格式化.

          2.3 Postman 通過(guò) GET 請(qǐng)求查詢(xún)

          GraphQL 也支持 GET 方式查詢(xún), 主要是因?yàn)?GraphQLServlet 實(shí)現(xiàn)了 doGet 和 doPost 兩個(gè)方法. Get 請(qǐng)求查詢(xún)時(shí)需要一個(gè) query 請(qǐng)求參數(shù), 且參數(shù)值需要 encode.

          a3017c4369b5a2d82512b46f981ecc43.webp

          3. 應(yīng)用場(chǎng)景

          至此, 我們應(yīng)該對(duì) GraphQL 有一個(gè)簡(jiǎn)單的認(rèn)識(shí)了, 那此時(shí)就有人會(huì)問(wèn)了: 這玩意到底有啥用?

          • 靜態(tài)變動(dòng)態(tài), 前端可以自己從 API 獲取想要的數(shù)據(jù),不必依賴(lài) REST 端返回的固定數(shù)據(jù)結(jié)構(gòu)

          • 請(qǐng)求次數(shù)及交互數(shù)據(jù)量的減少

          • API 網(wǎng)關(guān)層面

          3b2c9d88a70b5bb5932e139e19fbbf20.webp

          ? ? ? ?

          ? ? ? ? 如果有任何相關(guān)的問(wèn)題都可以加入 QQ/微信群一起討論, 學(xué)習(xí), 進(jìn)步. 此外如果有任何對(duì)于本公眾號(hào)的意見(jiàn)和建議也歡迎大家留言積極批評(píng)指正, 最后, 愿你我都能成為更好的自己.?


          ? ? ? ? 我是帥帥, 一個(gè)集帥氣, 幽默與內(nèi)涵, 并且熱愛(ài)編程, 擁抱開(kāi)源, 喜歡烹飪與旅游的暖男, 我們下期再見(jiàn).?拜了個(gè)拜!

          ? ? ? ??老規(guī)矩別忘了哦,?點(diǎn)擊原文鏈接跳轉(zhuǎn)到我們官方的博客平臺(tái)哦.



          悄悄話(huà)




          每文一句



          Before you talk, LISTEN

          Before you react, WAIT

          Before you quit, TRY?


          日常求贊

          ? ? ? 你們白漂的力量就是我拖更的史詩(shī)級(jí)動(dòng)力, 點(diǎn)贊, 評(píng)論, 再看, 贊賞, 看都看到這了, 隨便點(diǎn)一個(gè)咯.



          關(guān)注加好友


          拉你進(jìn)大佬交流群





          瀏覽 68
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  最新在线成人网站 | 国产欧美在线免费观看 | 爱爱视频在线看 | 操我骚逼~好爽麻豆 | 超碰成人欧美 |