文档章节

Java 使用 Graphql , 搭建查询服务

-外星人-
 -外星人-
发布于 2016/12/09 00:46
字数 1146
阅读 588
收藏 9

背景

随着react的开源,facebook相继开源了很多相关的项目,这些项目在他们内部已经使用了多年,其中引起我注意的就是本次讨论的是graphql,目前官方只有nodejs版,由于很多公司的后台技术栈都是java,所以便有了graphql的java版实现,在github上可以找到,废话不多说,直接看代码吧,具体介绍还是去看官网吧,不然就跑题了。

GraphQLSchema

Schema相当于一个数据库,它有很多GraphQLFieldDefinition组成,Field相当于数据库表/视图,每个表/视图又由名称、查询参数、数据结构、数据组成.

1) 先定义一个数据结构(GraphQLOutputType)字段,然后定义一个初始化方法

private GraphQLOutputType userType;

private void initOutputType() {
      /**
       * 会员对象结构
       */
      userType = newObject()
              .name("User")
              .field(newFieldDefinition().name("id").type(GraphQLInt).build())
              .field(newFieldDefinition().name("age").type(GraphQLInt).build())
              .field(newFieldDefinition().name("sex").type(GraphQLInt).build())
              .field(newFieldDefinition().name("name").type(GraphQLString).build())
              .field(newFieldDefinition().name("pic").type(GraphQLString).build())
              .build();
}

2)再定义两个表/视图,它包括名称,查询参数,数据结构,以及数据检索器

	/**
     * 查询单个用户信息
     * @return
     */
    private GraphQLFieldDefinition createUserField() {
        return GraphQLFieldDefinition.newFieldDefinition()
                .name("user")
                .argument(newArgument().name("id").type(GraphQLInt).build())
                .type(userType)
                .dataFetcher(environment -> {
                    // 获取查询参数
                    int id = environment.getArgument("id");

                    // 执行查询, 这里随便用一些测试数据来说明问题
                    User user = new User();
                    user.setId(id);
                    user.setAge(id + 15);
                    user.setSex(id % 2);
                    user.setName("Name_" + id);
                    user.setPic("pic_" + id + ".jpg");
                    return user;
                })
                .build();
    }

    /**
     * 查询多个会员信息
     * @return
     */
    private GraphQLFieldDefinition createUsersField() {
        return GraphQLFieldDefinition.newFieldDefinition()
                .name("users")
                .argument(newArgument().name("page").type(GraphQLInt).build())
                .argument(newArgument().name("size").type(GraphQLInt).build())
                .argument(newArgument().name("name").type(GraphQLString).build())
                .type(new GraphQLList(userType))
                .dataFetcher(environment -> {
                    // 获取查询参数
                    int page = environment.getArgument("page");
                    int size = environment.getArgument("size");
                    String name = environment.getArgument("name");

                    // 执行查询, 这里随便用一些测试数据来说明问题
                    List<User> list = new ArrayList<>(size);
                    for (int i = 0; i < size; i++) {
                        User user = new User();
                        user.setId(i);
                        user.setAge(i + 15);
                        user.setSex(i % 2);
                        user.setName(name + "_" + page + "_" + i);
                        user.setPic("pic_" + i + ".jpg");
                        list.add(user);
                    }
                    return list;
                })
                .build();
    }
 

3)接着定义一个Schema,并将其初始化,它包含一个名称,以及一个或多个表/视图(Field)

    private GraphQLSchema schema;
	
	public GraphSchema() {
        initOutputType();
        schema = GraphQLSchema.newSchema().query(newObject()
                .name("GraphQuery")
                .field(createUsersField())
                .field(createUserField())
                .build()).build();
    }

4)完成以上步骤之后,还需要定义一个model,类名不限,但是结构需要满足前面定义的数据结构,而且必须是public的

public class User {
    private int id;
    private int age;
    private int sex;
    private String name;
    private String pic;
    // getter, setter...
}	

5)之后写一个main方法,来测试一下

public static void main(String[] args) {
        GraphQLSchema schema = new GraphSchema().getSchema();

        String query1 = "{users(page:2,size:5,name:\"john\") {id,sex,name,pic}}";
        String query2 = "{user(id:6) {id,sex,name,pic}}";
        String query3 = "{user(id:6) {id,sex,name,pic},users(page:2,size:5,name:\"john\") {id,sex,name,pic}}";

        Map<String, Object> result1 = (Map<String, Object>) new GraphQL(schema).execute(query1).getData();
        Map<String, Object> result2 = (Map<String, Object>) new GraphQL(schema).execute(query2).getData();
        Map<String, Object> result3 = (Map<String, Object>) new GraphQL(schema).execute(query3).getData();

		// 查询用户列表
        System.out.println(result1);
        // 查询单个用户
        System.out.println(result2);
        // 单个用户、跟用户列表一起查
        System.out.println(result3);

}

输出:

{users=[{id=0, sex=0, name=john_2_0, pic=pic_0.jpg}, {id=1, sex=1, name=john_2_1, pic=pic_1.jpg}, {id=2, sex=0, name=john_2_2, pic=pic_2.jpg}, {id=3, sex=1, name=john_2_3, pic=pic_3.jpg}, {id=4, sex=0, name=john_2_4, pic=pic_4.jpg}]}
{user={id=6, sex=0, name=Name_6, pic=pic_6.jpg}}
{user={id=6, sex=0, name=Name_6, pic=pic_6.jpg}, users=[{id=0, sex=0, name=john_2_0, pic=pic_0.jpg}, {id=1, sex=1, name=john_2_1, pic=pic_1.jpg}, {id=2, sex=0, name=john_2_2, pic=pic_2.jpg}, {id=3, sex=1, name=john_2_3, pic=pic_3.jpg}, {id=4, sex=0, name=john_2_4, pic=pic_4.jpg}]}

6)最后把main方法里面的代码放到web层,只需要定义一个query参数,很容易就把查询服务搭建好了,dataFetcher 里面还是调用原来的查询接口

7)引入maven依赖

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

关于graphql查询什么定义,看看这个或许对你有帮助

json

{
	id=6, 
	sex=0, 
	name="Name_6", 
	pic="pic_6.jpg"
}

query

{
	id,
	sex,
	name,
	pic
}

后面那部分,其实就是json字符串,去掉=和value的结果,还是可读的

结语

graphql 带了一种全新的思维方式,可以简化web api的开发,由客户端指定需要什么数据,服务端返回什么数据,减少不必要的流量传输,对移动端友好,还提供多种数据聚合查询,多个查询只是用一个请求,既满足api最小粒度,又满足前端需要,减少请求,提高性能。

感觉以后会朝这方面去发展,大趋所驱。

© 著作权归作者所有

共有 人打赏支持
-外星人-
粉丝 47
博文 46
码字总数 22286
作品 0
深圳
程序员
加载中

评论(6)

-外星人-
-外星人-

引用来自“-外星人-”的评论

引用来自“yuanshichao1988”的评论

楼主,请问这个还有继续研究么?

回复@yuanshichao1988 : 原来有一个项目用过, 现在没怎么用,感觉还不够火,很多人都不知道,推不动

引用来自“TommyLemon”的评论

GraphQL太复杂太难用了,一堆概念,前端/客户端要查的结构还要后端都定义好,手动对字段resolve,要做大量多余的工作。尤其是java版是个巨坑,定义太混乱太啰嗦。
我们公司之前也简单尝试过,后来改用APIJSON了
服务端确实有点繁琐,不过客户端还是挺行,JAVA 强类型,本身语法也这样,可以fork一个然后改进改进嘛,其实我一直想做一个lua版本的,放在nginx内部,提供兼容graphql,后端也不用改,在中间层提供一个这样的服务,无侵入,graphql 理念还是挺好的。。。
孤独的探索号
孤独的探索号

引用来自“-外星人-”的评论

引用来自“yuanshichao1988”的评论

楼主,请问这个还有继续研究么?

回复@yuanshichao1988 : 原来有一个项目用过, 现在没怎么用,感觉还不够火,很多人都不知道,推不动
GraphQL太复杂太难用了,一堆概念,前端/客户端要查的结构还要后端都定义好,手动对字段resolve,要做大量多余的工作。尤其是java版是个巨坑,定义太混乱太啰嗦。
我们公司之前也简单尝试过,后来改用APIJSON了
-外星人-
-外星人-

引用来自“yuanshichao1988”的评论

楼主,请问这个还有继续研究么?

回复@yuanshichao1988 : 原来有一个项目用过, 现在没怎么用,感觉还不够火,很多人都不知道,推不动
迪拜驻开源中国大使
迪拜驻开源中国大使
楼主,请问这个还有继续研究么?
-外星人-
-外星人-

引用来自“WeiXiaodong”的评论

fb版的junit?
GraphQL是一个由Facebook提出的应用层查询语言,用来做后端数据接口的
WeiXiaodong
WeiXiaodong
fb版的junit?
以LeetCode为例——如何发送GraphQL Query获取数据

前言 GraphQL 是一种用于 API 的查询语言,是由 Facebook 开源的一种用于提供数据查询服务的抽象框架。在服务端 API 开发中,很多时候定义一个接口返回的数据相对固定,因此要获得更多信息或...

zxzhang
07/19
0
0
阿里巴巴微服务下使用GraphQL构建BFF

作者“ThoughtWorks” 微服务架构,这个在几年前还算比较前卫的技术在如今遍地开花。得益于开源社区的支持,我们可以轻松地利用 Spring Cloud 以及 Docker 容器化快速搭建一个微服务架构的原...

美的让人心动
04/28
0
0
Vue + GraphQL初试

基本用法 GraphQL概述 GraphQL基本语法特性 GraphQL类型系统 GraphQL类型系统内置基础类型 GraphQL类型系统内置修饰符 GraphQL工作原理 GraphQL执行过程 Vue工程接入GraphQL 基本用法(如何去...

清风0o0
06/17
0
0
Apollo GraphQL 服务端实践

如果喜欢我们的文章别忘了点击关注阿里南京技术专刊呦~ 本文转载自 阿里南京技术专刊-知乎,欢迎大牛小牛投递阿里南京前端/后端开发等职位,详见 阿里南京诚邀前端小伙伴加入~。 在最近的项目...

阿里南京技术专刊
05/22
0
0
前端每周清单第 46 期: 2017 Node.js / GraphQL / Vue.js 盘点,前端性能优化与可用性保障

前端每周清单专注前端领域内容,以对外文资料的搜集为主,帮助开发者了解一周前端热点;分为新闻热点、开发教程、工程实践、深度阅读、开源项目、巅峰人生等栏目。欢迎关注【前端之巅】微信公...

王下邀月熊
01/08
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

180.mariadb 主从复制

参考:https://blog.csdn.net/chengxuzaza/article/details/62042920 睡觉睡觉,明天写 1.效果 当主库中数据有变化的时候,从库就自动同步 2. 环境要求 至少两台 linux服务器 (教程:https...

Lucky_Me
10分钟前
0
0
erlng file id3v1 id3v1.1

%% ---%% Excerpted from "Programming Erlang",%% published by The Pragmatic Bookshelf.%% Copyrights apply to this code. It may not be used to create training material, %% ......

xueyuse0012
11分钟前
0
0
RabbitMq的安装

环境Centos6.5 32位 JDK 1.7.8 Jdk的卸载 rpm -qa|grep jdk yum –y remove 上边的安装包 JDK的安装 Rpm –ivh jdk安装包 配置环境变量 export JAVA_BIN=/usr/java/jdk1.7.0_80/bin export J......

DemonsI
15分钟前
0
0
http和https协议

HTTPS全称为Hypertext Transfer Protocol over Secure Socket Layer,中文含义为“超文本传输协议在安全加密字层”,简单来说就是加密数据传输,通俗的说就是安全连接。 HTTPS安全超文本传输...

寰宇01
21分钟前
0
0
vue内引入语音播报功能

在vue项目中引入语音播报,使用的科大讯飞语音接入, 具体思路为每次接收到语音信息后存入一个数组,然后监听这个数组,开始冲第一个索引播放,并且同时根据vuex getter 来动态删减数量 给a...

originDu
30分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部