相关文章推荐
豪爽的帽子  ·  Font ...·  4 月前    · 
爱逃课的毛豆  ·  Tap/Tun for Debian ...·  10 月前    · 
小眼睛的葫芦  ·  Java技术栈——Java ...·  1 年前    · 

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实现中有两点是实战中不可取的:

  • schema的加载方式,应该以读取本地配置的形式加载
  • 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升级成实战项目需要做的内容:

  • schema与java代码分离,可以通过读取文件的形式将schema加载到系统中;
  • 动态处理GraphQL的请求参数,并随之生成对应的响应
  • 可能大家已经发现,入参和出参都需要服务端编码实现解析。
    其实graphql-java做的事情是很有限的,主要作用如下:

  • 维护schema的结构
  • 根据GraphQL的脚本需要,过滤响应结果
  • 其他很大一部分的工作都需要自己实现的。