zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    jquery模拟刮刮乐
    jq默认选中每项第一个
    让一个div水平且垂直居中
    ES6模块的import和export用法总结
    linux 标准目录
    spring 注解配置
    多线程下的两种单例写法
    java版二叉树算法实现
    JAVA版A星算法实现
    对于宫格地图寻最短路径的一个广度搜索算法
  • 原文地址:https://www.cnblogs.com/chenglc/p/13743760.html
Copyright © 2011-2022 走看看