文档章节

Java 使用 Graphql , 搭建查询服务

-外星人-
 -外星人-
发布于 2016/12/09 00:46
字数 1146
阅读 580
收藏 9
点赞 0
评论 6

背景

随着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最小粒度,又满足前端需要,减少请求,提高性能。

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

© 著作权归作者所有

共有 人打赏支持
-外星人-
粉丝 45
博文 45
码字总数 22101
作品 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?
阿里巴巴微服务下使用GraphQL构建BFF

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

美的让人心动 ⋅ 04/28 ⋅ 0

Vue + GraphQL初试

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

清风0o0 ⋅ 06/17 ⋅ 0

Apollo GraphQL 服务端实践

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

阿里南京技术专刊 ⋅ 05/22 ⋅ 0

Facebook开发的一种数据查询语言——GraphQL:安全概述和测试技巧

随着GraphQL技术越来越受欢迎,我们总结了一些关于常见安全错误的概述和技巧。 GraphQL是什么? GraphQL是Facebook开发的一种数据查询语言,并于2015年公开发布。它是REST API的替代品。 即使...

技术小能手 ⋅ 05/28 ⋅ 0

如何利用GitHub GraphQL API开发个人博客?

作为一个程序员,搭建一个个人博客几乎是所有人的需求,一来比较酷,二来也可以记录自己的学习和生活总结。但如果你不是全栈工程师,实现这个需求还是有点麻烦。后端搭建一套现有的前端框架及...

simbawu ⋅ 05/11 ⋅ 0

还在用 Redux,要不要试试 GraphQL 和 Apollo?

https://twitter.com/seldo/status/950794461235130368 题注:如果喜欢我们的文章别忘了点击关注阿里南京技术专刊呦~ 本文转载自 阿里南京技术专刊-知乎,欢迎大牛小牛投递阿里南京前端/后端...

阿里南京技术专刊 ⋅ 05/18 ⋅ 0

Dgraph 1.0.6 发布,事务性的分布式图形数据库

Dgraph 1.0.6 发布了,Dgraph 是一个可扩展的,分布式的,低延迟的图数据库,目标是提供 Google 生产水平的规模和吞吐量,在超过 TB 的结构数据里,为用户提供足够低延迟的实时查询。Dgraph ...

h4cd ⋅ 今天 ⋅ 0

完爆Facebook/GraphQL,APIJSON全方位对比解析(二)-权限控制

相关阅读: 完爆Facebook/GraphQL,APIJSON全方位对比解析(一)-基础功能 自APIJSON发布以来,不断有网友拿来和Facebook开发的GraphQL对比,甚至不少人声称“完爆”APIJSON。 然而事实正好相反...

TommyLemon-GitHub ⋅ 06/05 ⋅ 0

Dgraph v1.0.5 发布,低延迟的开源图数据库

Dgraph v1.0.5 已发布,DGraph 是一个可扩展的,分布式的,低延迟的图数据库,目标是提供 Google 生产水平的规模和吞吐量,在超过TB的结构数据里,为用户提供足够低延迟的实时查询。DGraph ...

王练 ⋅ 04/21 ⋅ 0

代码格式化开源工具Prettier

Prettier是一款自动规范和标准化代码格式的开源工具,不会影响其执行,开发人员可以用自己的风格进行编码,同时生成可读性高的代码,以提高互操作性和协作性。软件遵守MIT开源协议。 举例: ...

marsdream ⋅ 05/04 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

JDK1.6和JDK1.7中,Collections.sort的区别,

背景 最近,项目正在集成测试阶段,项目在服务器上运行了一段时间,点击表格的列进行排序的时候,有的列排序正常,有的列在排序的时候,在后台会抛出如下异常,查询到不到数据,而且在另外一...

tsmyk0715 ⋅ 23分钟前 ⋅ 0

spring RESTful

spring RESTful官方文档:http://spring.io/guides/gs/rest-service/ 1. 可以这么去理解RESTful:其实就是web对外提供的一种基于URL、URI的资源供给服务。不是一个原理性知识点。是一个方法论...

BobwithB ⋅ 25分钟前 ⋅ 0

C++ 中命名空间的 5 个常见用法

相信小伙伴们对C++已经非常熟悉,但是对命名空间经常使用到的地方还不是很明白,这篇文章就针对命名空间这一块做了一个叙述。 命名空间在1995年被引入到 c++ 标准中,通常是这样定义的: 命名...

柳猫 ⋅ 27分钟前 ⋅ 0

@Conditional派生注解

@Conditional派生注解(Spring注解版原生的@Conditional作用) 作用:必须是@Conditional指定的条件成立,才给容器中添加组件,配置配里面的所有内容才生效; @Conditional扩展注解 作用(判...

小致dad ⋅ 28分钟前 ⋅ 0

适配器模式

适配器模式 对象适配器 通过私有属性来实现的类适配器 通过继承来实现的接口适配器 通过继承一个默认实现的类实现的

Cobbage ⋅ 31分钟前 ⋅ 0

Java 限流策略

概要 在大数据量高并发访问时,经常会出现服务或接口面对暴涨的请求而不可用的情况,甚至引发连锁反映导致整个系统崩溃。此时你需要使用的技术手段之一就是限流,当请求达到一定的并发数或速...

轨迹_ ⋅ 35分钟前 ⋅ 0

GridView和子View之间的间隙

默认的情况下GridView和子View之间会有一个间隙,原因是GridView为了在子View被选中时在子View周围显示一个框。去掉的办法如下: android:listSelector="#0000" 或 setSelector(new ColorDra...

国仔饼 ⋅ 39分钟前 ⋅ 0

idea插件开发

1 刷新页面要使用多线程 2 调试要使用restart bug 不要去关闭调试的idea 否则再次启动会卡住

林伟琨 ⋅ 39分钟前 ⋅ 0

Java 内存模型

物理机并发处理方案 绝大多数计算任务,并不是单纯依赖 cpu 的计算完成,不可避免需要与内存交互,获取数据。内存要拿到数据,需要和硬盘发生 I/O 操作。计算机存储设备与 cpu 之间的处理速度...

长安一梦 ⋅ 46分钟前 ⋅ 0

思路分析 如何通过反射 给 bean entity 对象 的List 集合属性赋值?

其实 这块 大家 去 看 springmvc 源码 肯定可以找到实现办法。 因为 spirngmvc 的方法 是可以 为 对象 参数里面的 list 属性赋值的。 我也没有看 具体的 mvc 源码实现,我这里只是 写一个 简...

之渊 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部