GraphQL實戰-第二篇-java實現及分析


GraphQL實戰-第二篇-java實現及分析

https://blog.csdn.net/xplan5/article/details/108748841

到這里必須具備的知識儲備:對GraphQL有簡單的了解,了解Schema的常用類型。

這里用一些demo示例來體驗GraphQL的執行過程,這只是借助graphql-java實現的java版本。

首先需要引入graphql-java的依賴

        <dependency>
            <groupId>com.graphql-java</groupId>
            <artifactId>graphql-java</artifactId>
            <version>15.0</version>
        </dependency>

Demo1

第一個demo是官網提供的

import graphql.ExecutionResult;
import graphql.GraphQL;
import graphql.schema.GraphQLSchema;
import graphql.schema.StaticDataFetcher;
import graphql.schema.idl.RuntimeWiring;
import graphql.schema.idl.SchemaGenerator;
import graphql.schema.idl.SchemaParser;
import graphql.schema.idl.TypeDefinitionRegistry;

import static graphql.schema.idl.RuntimeWiring.newRuntimeWiring;

public class HelloWorld {

    public static void main(String[] args) {
        //定義schema文件,直接寫在了代碼中,包含一個hello的查詢方法
        String schema = "type Query{hello: String} schema{query: Query}";
        SchemaParser schemaParser = new SchemaParser();
        //直接加載schema,初始化GraphQL
        TypeDefinitionRegistry typeDefinitionRegistry = schemaParser.parse(schema);
        //加載一份服務端數據
        RuntimeWiring runtimeWiring = new RuntimeWiring()
                .type("Query", builder -> builder.dataFetcher("hello", new StaticDataFetcher("world")))
                .build();

        SchemaGenerator schemaGenerator = new SchemaGenerator();
        GraphQLSchema graphQLSchema = schemaGenerator.makeExecutableSchema(typeDefinitionRegistry, runtimeWiring);
        // 構建一個GraphQL實例,執行graphql腳本
        GraphQL build = GraphQL.newGraphQL(graphQLSchema).build();
        ExecutionResult executionResult = build.execute("{hello}");

        System.out.println(executionResult.getData().toString());
        // Prints: {hello=world}
    }
}

這個demo直接加載了schema的內容,構建Graphql執行腳本。這種方式最接近於實際開發的操作。

Deom2

通過這個demo來看一下一個GraphQL的服務端都做了什么。並對比一下java代碼加載GraphQL對象與schema中的GraphQL的聯系。

所依賴的對象User

/**
 * ClassName: User<br/>
 * Description: <br/>
 * date: 2019/6/28 10:38 AM<br/>
 *
 * @author chengluchao
 * @since JDK 1.8
 */
@Data
public class User {
    private int age;
    private long id;
    private String name;
    private Card card;

    public User(int age, long id, String name, Card card) {
        this.age = age;
        this.id = id;
        this.name = name;
        this.card = card;
    }

    public User(int age, long id, String name) {
        this.age = age;
        this.id = id;
        this.name = name;
    }
}

/**
 * ClassName: Card<br/>
 * Description: <br/>
 * date: 2019/6/28 3:25 PM<br/>
 *
 * @author chengluchao
 * @since JDK 1.8
 */
@Data
public class Card {
    private String cardNumber;
    private Long userId;

    public Card(String cardNumber, Long userId) {
        this.cardNumber = cardNumber;
        this.userId = userId;
    }
}

接下來是demo

/**
 * ClassName: GraphQLDemo<br/>
 * Description: <br/>
 * date: 2019/6/28 10:40 AM<br/>
 *
 * @author chengluchao
 * @since JDK 1.8
 */

public class GraphQLDemo {
    public static void main(String[] args) {
        /*
            定義GraphQL對象,等同於schema中定義的
            type User {
                id:ID
                age:Int
                name:String
            }
        */
        GraphQLObjectType userObjectType = GraphQLObjectType.newObject()
                .name("User")
                .field(GraphQLFieldDefinition.newFieldDefinition().name("id").type(Scalars.GraphQLLong))
                .field(GraphQLFieldDefinition.newFieldDefinition().name("age").type(Scalars.GraphQLInt))
                .field(GraphQLFieldDefinition.newFieldDefinition().name("name").type(Scalars.GraphQLString))
                .build();
        /*
            queryUser : User 指定對象及參數類型
            等同於在GraphQL中定義一個無參方法 queryUser,返回值為User
            queryUser:User
            dataFetcher指定了響應的數據集,這個demo里使用了靜態寫入的方式
         */
        GraphQLFieldDefinition userFileldDefinition = GraphQLFieldDefinition.newFieldDefinition()
                .name("queryUser")
                .type(userObjectType)
                //靜態數據
                .dataFetcher(new StaticDataFetcher(new User(19, 2, "CLC")))
                .build();
        /*
            type UserQuery 定義查詢類型

            對應的graphQL為:
                type UserQuery {
                    queryUser:User
                }
         */
        GraphQLObjectType userQueryObjectType = GraphQLObjectType.newObject()
                .name("UserQuery")
                .field(userFileldDefinition)
                .build();
        /*
            Schema 定義查詢
            定義了query的root類型
            對應的GraphQL語法為:
               schema {
                    query:UserQuery
               }
         */
        GraphQLSchema qlSchema = GraphQLSchema.newSchema().query(userQueryObjectType).build();

        //構建一個GraphQl對象,執行邏輯都在此處進行
        GraphQL graphQL = GraphQL.newGraphQL(qlSchema).build();

        //模擬客戶端傳入查詢腳本,方法名queryUser,獲取響應值為 id name age
        String query = "{queryUser{id name age}}";
        // 執行業務操作邏輯,獲取返回值
        ExecutionResult result = graphQL.execute(query);

        System.out.println(result.toSpecification());
    }
}

這里對應的sehema應該是這樣的:

#對應的User定義如下
schema {
    #定義查詢
    query: UserQuery
}

#定義查詢類型
type UserQuery {
    #指定對象以及參數類型
    queryUser : User
}

#定義對象
type User {
    #!表示非空
    id: ID!
    name:String
    age:Int
    card:Card
}

type Card {
    cardNumber:String
    userId:ID
}

可以看出:

schema的結構層級是:schema > UserQuery > User

schema中定義的是操作類型,UserQuery下定義的是操作方法,而User對應的是GraphQL的對象,此對象應該對應於java中一個相同的對象

以上demo實現中有兩點是實戰中不可取的:

  1. schema的加載方式,應該以讀取本地配置的形式加載
  2. dataFetcher的數據加載,demo中是靜態寫死的方式,實戰中應該是動態加載的數據

接下來從這兩點改進

demo3

首先在resources目錄下創建一個user.graphqls的文件

#對應的User定義如下
schema {
    #定義查詢
    query: UserQuery
}

#定義查詢類型
type UserQuery {
    #指定對象以及參數類型
    queryUser : User
    queryUserById(id:ID) : User
}

#定義對象
type User {
    #!表示非空
    id: ID!
    name:String
    age:Int
    card:Card
}

type Card {
    cardNumber:String
    userId:ID
}

import clc.bean.Card;
import clc.bean.User;
import graphql.ExecutionResult;
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.apache.commons.io.IOUtils;


/**
 * ClassName: GraphQLSDLDemo<br/>
 * Description: <br/>
 * date: 2019/6/28 11:19 AM<br/>
 *
 * @author chengluchao
 * @since JDK 1.8
 */

public class GraphQLSDLDemo {
    public static void main(String[] args) throws Exception {
        //讀取graphqls文件
        String fileName = "user.graphqls";
        String fileContent = IOUtils.toString(GraphQLSDLDemo.class.getClassLoader().getResource(fileName), "UTF-8");
        //解析文件
        TypeDefinitionRegistry typeDefinitionRegistry = new SchemaParser().parse(fileContent);

        RuntimeWiring wiring = RuntimeWiring.newRuntimeWiring()
                .type("UserQuery", builder ->
                        builder.dataFetcher("queryUserById", environment -> {
                            //解析請求參數,根據業務返回結果
                            Long id = Long.parseLong(environment.getArgument("id"));
                            Card card = new Card("123456", id);
                            return new User(18, id, "user0" + id, card);
                        })
                )
                .build();

        GraphQLSchema graphQLSchema = new SchemaGenerator().makeExecutableSchema(typeDefinitionRegistry, wiring);

        GraphQL graphQL = GraphQL.newGraphQL(graphQLSchema).build();

        String query = "{queryUserById(id:15){id,name,age,card{cardNumber,userId}}}";
        ExecutionResult result = graphQL.execute(query);

        System.out.println("query: " + query);
        System.out.println(result.toSpecification());
    }
}

項目源碼:https://gitee.com/chengluchao/graphql-clc/tree/master/graphql-java/src/main/java/com/clc/demo

從demo升級成實戰項目需要做的內容:

  1. schema與java代碼分離,可以通過讀取文件的形式將schema加載到系統中;
  2. 動態處理GraphQL的請求參數,並隨之生成對應的響應

可能大家已經發現,入參和出參都需要服務端編碼實現解析。
其實graphql-java做的事情是很有限的,主要作用如下:

  1. 維護schema的結構
  2. 根據GraphQL的腳本需要,過濾響應結果

其他很大一部分的工作都需要自己實現的。

CLC


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM