有个需求,比如我通过 userid 查数据库映射到 userBean 中,然后我还需要通过 userBean 中传回来的内容中的 groupId 查数据库映射到 groupBean 中。这个时候我可以获取到两个 java 对象( user 、group )。 普遍的做法是将两个对象塞到一个 List 中,返回给前端,前端自己过滤和拼装渲染。 其实前端想要是一个聚合后的 json 。 比如按照之前的做法我们返回给前端的 json 是这样的: { "user": { "userid": 111, "name": "张三", "age": "12", "sex": "男" }, "group": { "groupid": 222, "name": "学习组", "des": "学习小组" } }
但是现在前端想要的格式其实是 { "user": { "userid": 111, "name": "学习组", "age": "12", "sex": "男", "groupid": 222 } }
当然服务端可以通过定义一个只包含这些字段的 bean 出来,然后将两次查询到的结果分别 set 进去。但是这样会造成产生了很多返回结构体的 bean 出现。
目前了解了一下 graphQL,但是感觉后端加入这个框架写的很麻烦,网上没有太多 springboot+graphQL 的 demo 。而且感觉写法也不太简单,可能是我太菜的原因。
问下大家,后端实现数据聚合还有哪些思路? 或者是使用 graphQL 有哪些 demo 可以参考。今天看这块内容已经自闭一天了。
1
Mithril 2020-08-12 00:23:45 +08:00 1
这种需求 GraphQL 可以直接解决。你定义 GraphQL 对象的时候直接用 User 里面嵌套一个 Group,前端需要从 User 里面获取所属 Group 的时候直接拿这个对象就可以了,GraphQL 会给它填进去。
当然很多时候你需要自己写 DataLoader 。 你如果不能用纯 Rest API 完成接口设计,那么多数是前端需要依靠后端来聚合数据。大概率是因为性能原因没办法在前端做聚合。GraphQL 本身可以帮你做一些简单的聚合,同时也可以直接减少请求次数。但是最终你很可能还是要自己写一些 DataLoader 或者构造一些用来做 VM 的 Graph Type 。 对于后端来说,用 GraphQL 不会带来太多便利,该写的还是要写。只是前端可以一定程度上自行决定返回的数据结构,你也省了很多沟通成本,提升的是整个项目的效率。 |
2
lihongming 2020-08-12 00:33:15 +08:00 via iPhone
私以为,GraphQL 不是给后端用的,而是应该由前端自己写的。
现在的前端早已不是那个切图仔了,大前端至少要负责到直接对外暴露的 API 那一级 |
3
optional 2020-08-12 09:04:23 +08:00 via Android
graphql 的格式就是前者,而不是后者。
|
4
jiobanma OP @Mithril #1 问下大佬,我想这么做:接口还是传统的 rest 的接口,然后在 controller 中使用 graphql 对数据库中查询出来的数据进行聚合 聚合为一个 json 返回给前端。这样可以实现吗? 因为对 graphql 了解的不是太多,看到网上的 demo 大多都是接口传入的是类似于 json 的 graphql 的语法。
|
6
optional 2020-08-12 09:36:00 +08:00 via Android
就像你上面说的,可以再映射一下数据格式,其实这很好的方案,graphql 直接给前端也有其它的坏处,中间加一层可以解决不少问题。而且这些映射有现成的工具可以配置。
|
8
ianva 2020-08-12 09:49:22 +08:00
java 里似乎没什么好方案,我们这边全转到 node.js ,用 Apollo 了
|
9
Mithril 2020-08-12 09:50:42 +08:00
@jiobanma 你这个做法是不行的。你没法从一个 Rest Controller 里面直接调用 GraphQL 。GraphQL 也不是拿来做数据聚合用的。
它的核心就是你说的那个 JSON 语法,通过 POST 请求过来的 JSON 被解析后,GraphQL 会去调用对应的 Query,然后你这些手写的 Query 会调用和聚合相关的 Type 。 这一个链条里的 Query 和 Graph Type 都是你自己手写的,和 Rest API 用的类型是不一样的。比如按你的例子来说,你在 User 里面挂个 Group 。一般的 Rest API 只会从 User 里面返回一个 Group ID 。但你如果做成 GraphQL 接口的话,你需要自己写把这个 Group ID 转换成 Group 对象的查询。 GraphQL 会帮你在需要的时候去调用这个查询而已。 |
10
jiobanma OP @Mithril #9 但是网上的一个 demo 他的写法是这样的:
``` public static void main(String[] args) { 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}}"; GraphQLSchema schema = new HelloGraphql().getSchema(); Object result1 = GraphQL.newGraphQL(schema).build().execute(query1).getData(); Object result2 = GraphQL.newGraphQL(schema).build().execute(query2).getData(); Object result3 = GraphQL.newGraphQL(schema).build().execute(query3).getData(); // 查询用户列表 System.out.println(result1); // 查询单个用户 System.out.println(result2); // 单个用户、跟用户列表一起查 System.out.println(result3); } ``` 这里得到的 result 不就是我需要的结果吗? 我把这个结果返回 不就是我需要的需求吗? |
11
Mithril 2020-08-12 09:58:43 +08:00
@jiobanma 是的。我说的你不能在 Rest Controller 里面干这个事主要是因为这是违背 Restful 的设计原则的。单独做一个 GraphQL 用的 Controller 就可以了。
你可以去看一下它的 HelloGraphql 的 Schema 和 Type 是怎么写的,那个是核心。 |
13
optional 2020-08-12 10:04:34 +08:00 via Android
@Mithril 实践下来,前面加一层是很有好处的,graphql 还真挺适合做聚合,做接口反倒一堆问题,监控,缓存,日志之类的
|
14
Mithril 2020-08-12 10:10:28 +08:00
@optional 其实做聚合也是一样,简单查询还行,复杂一点的你就得写 DataLoader 。
其实做接口这个事,不管你是 Restful 也好,GraphQL 也好,瞎怼也好,都只是个形式和工具。该做的事一件也不会少。 各有优缺点而已。也不是说上了 GraphQL 就万能了,只是说如果聚合和标准化是你的痛点的话,那 GraphQL 可以帮你尽量避开这些坑,但其他的坑该有也还是会有的。 |
16
Mithril 2020-08-12 10:19:58 +08:00
@jiobanma 嗯。你试的时候注意一下,不要光看例子那些从内存里直接返回数据的,试着把查询打到数据库里。如果你一次返回一个对象数组,然后数组里的对象还嵌套了查询,数据库没准直接就炸了。
Data Loader 就是用来解决这个问题的。 这俩试过了,GraphQL 做查询的坑基本就趟过去了。然后就是 Mutation,权限,Log 等等。。。 |
19
jilu171990 2020-08-12 12:38:50 +08:00
@lihongming 哈哈,让前端写 graphQL 的结果往往就是直接被爆库。。。
|
20
lihongming 2020-08-12 15:48:44 +08:00 via iPhone
@jilu171990 前端直接搞库,后端真啥都不管了啊?
|