Java 使用 Graphql 搭建查询服务详解
背景
随着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最小粒度,又满足前端需要,减少请求,提高性能。
感觉以后会朝这方面去发展,大趋所驱。
推荐阅读