GraphQL学习,Java简单实现

简介

是一种查询语言,类似前端与后端之间通过sql语言进行交互。用类似json的语言来查询需要的数据。
如在以下查询语句

{
  bookById(id: "1") {
    id
    name
    pageCount
    author {
      name
    }
  }
}

可以得到一下结果

{
  "data": {
    "bookById": {
      "id": "1",
      "name": "风雪追击",
      "pageCount": 233,
      "author": {
        "name": "东野圭吾"
      }
    }
  }
}

maven依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>com.graphql-java</groupId>
    <artifactId>graphql-java</artifactId>
    <version>11.0</version>
</dependency>
<dependency>
    <groupId>com.graphql-java</groupId>
    <artifactId>graphql-java-spring-boot-starter-webmvc</artifactId>
    <version>1.0</version>
</dependency>
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>26.0-jre</version>
</dependency>

定义schema

上面的查询语句我们事先定义了一下schema,放置在src/main/resources/schema.graphqls

type Query {
  bookById(id: ID): Book
  authors:[Author]
  books:[Book]
  authorAndBooks:[Author]
}

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

type Author {
  id: ID
  name: String
  books:[Book]
}

其中类型为Query的表示为查询,类似CURD中的R;除了Query还有Mutation来表示对数据进行修改,相当于CURD中的CUD操作。在schema中定义了4跳query语句如上所示。我们还定义了Book和Author的类型,其中Book中包含一个Author,Author中包含Book的列表。

定义GraphQLProvider

GraphQLProvider类将会创建一个GraphQL的实例,这里通过@Bean的方式暴露出去可以通过/graphql的url访问到(由依赖graphql-java-spring-boot-starter-webmvc实现的功能)

@Component
public class GraphQLProvider {

    private GraphQL graphQL;

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

    @Autowired
    GraphQLDataFetchers graphQLDataFetchers;

    @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) {
        TypeDefinitionRegistry typeRegistry = new SchemaParser().parse(sdl);
        RuntimeWiring runtimeWiring = buildWiring();
        SchemaGenerator schemaGenerator = new SchemaGenerator();
        return schemaGenerator.makeExecutableSchema(typeRegistry, runtimeWiring);
    }

    private RuntimeWiring buildWiring() {
        Map<String, DataFetcher> map = new HashMap<String,DataFetcher>();
        map.put("bookById",graphQLDataFetchers.getBookByIdDataFetcher());
        map.put("books",graphQLDataFetchers.getBooksDataFetcher());
        map.put("authors",graphQLDataFetchers.getAuthorsDataFetcher());
        return RuntimeWiring.newRuntimeWiring()
                .type(newTypeWiring("Query")
                        .dataFetchers(map))
                .type(newTypeWiring("Book")
                        .dataFetcher("author", graphQLDataFetchers.getAuthorDataFetcher())
                        .dataFetcher("pageCount",graphQLDataFetchers.getPageCountDataFetcher()))
                .type(newTypeWiring("Author")
                        .dataFetcher("books",graphQLDataFetchers.getBooksByAUthorDataFetcher()))
                .build();
    }
}

DataFetchers

GraphQL在执行查询时,是通过Datafetcher来获取一个字段的数据。DataFetcher是一个接口

public interface DataFetcher<T> {
    T get(DataFetchingEnvironment var1) throws Exception;
}

新建一个类用于存放所有的datafetcher(小型项目)

@Component
public class GraphQLDataFetchers {

    private static List<Map<String, String>> books = Arrays.asList(
            ImmutableMap.of("id", "1",
                    "name", "风雪追击",
                    "totalPages", "233",
                    "authorId", "a1"),
            ImmutableMap.of("id", "4",
                    "name", "解忧杂货店",
                    "totalPages", "342",
                    "authorId", "a1"),
            ImmutableMap.of("id", "2",
                    "name", "达芬奇密码",
                    "totalPages", "635",
                    "authorId", "a2"),
            ImmutableMap.of("id", "3",
                    "name", "大秦帝国",
                    "totalPages", "371",
                    "authorId", "a3")
    );

    private static List<Map<String, String>> authors = Arrays.asList(
            ImmutableMap.of("id", "a1",
                    "name", "东野圭吾"),
            ImmutableMap.of("id", "a2",
                    "name", "丹布朗"),
            ImmutableMap.of("id", "a3",
                    "name", "孙皓晖")
    );

    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<String,String> book = dataFetchingEnvironment.getSource();
            String authorId = book.get("authorId");
            return authors
                    .stream()
                    .filter(author -> author.get("id").equals(authorId))
                    .findFirst()
                    .orElse(null);
        };
    }

    public  DataFetcher getBooksByAUthorDataFetcher(){
        return dataFetchingEnvironment -> {
            Map<String,String> author = dataFetchingEnvironment.getSource();
            String authorId = author.get("id");
            return books.stream().filter(book->book.get("authorId").equals(authorId)).toArray();
        };
    }

    public  DataFetcher getAuthorTotalCountDataFetcher(){
        return dataFetchingEnvironment -> {
            Map<String,Object> author = dataFetchingEnvironment.getSource();
            String authorId = author.get("id").toString();
            return books.stream().filter(book->book.get("authorId").equals(authorId))
                    .collect(Collectors.summingInt(map->Integer.parseInt(map.get("totalPages"))));
        };
    }

    public DataFetcher getAuthorsDataFetcher(){
        return dataFetchingEnvironment->{
            return authors;
        };
    }
    

    public DataFetcher getBooksDataFetcher(){
        return dataFetchingEnvironment -> {
            return books;
        };
    }
    
    public DataFetcher getPageCountDataFetcher() {
        return dataFetchingEnvironment -> {
            Map<String,String> book = dataFetchingEnvironment.getSource();
            return book.get("totalPages");
        };
    }
}

验证

可以使用graphql-playground工具来进行验证。我电脑的版本是macos10.15.4,使用1.8.9可以运行,1.8.10则会报错,使用前需要在顶栏输入http://localhost:8080/graphql,然后在左边输入查询语句,右边就能得到查询结果。

image.png

参考链接

java搭建graphQL demo

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,165评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,503评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,295评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,589评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,439评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,342评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,749评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,397评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,700评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,740评论 2 313
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,523评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,364评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,755评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,024评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,297评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,721评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,918评论 2 336