# GraphQL语法说明
# 说明
GraphQL是一个用于API的查询语言,数据资源API服务通过接收GraphQL查询,并验证和执行。接收到的查询首先会被检查确保它只引用了已定义的类型和字段,然后运行指定的解析函数来生成结果。
# GraphQL语言结构
{ tm_class(first: 1, offset:10, filter:{name:{eq : "123"}}){ num name id } }
1
以上面示例,GraphQL有三部分组成
- 第一部分type类型,在数据资源API中其实际为接口的名称 //tm_class
- 第二部分查询条件,在数据数据资源API中内设3个关键字(first、offset、filter) //(first: 1, offset:10, filter:{name:{eq : "123"}})
- 第三部分查询字段,表示用户本次API查询需要获取的数据字段,查询字段是受权限保护,对于用户无权限访问的字段,一律返回空值;用户发送查询请求时,可去除未申请的字段;如果希望对返回的字段进行重命名可通过(重命名:字段名 username:name) //{ num name id }
# GraphQL查询条件
GraphQL语句中过滤条件内设三个关键字(first、offset、filter);在filter中配置查询条件,filter的value是一个map集合,可以是一个嵌套的key&value。
filter查询过滤
- filter其本质数据结构是一个嵌套的键值对,基本语法: {字段名: {查询关键字: 查询值}}
- 在一个键值对中不能出现相同的key,例如(name:{eq : "123", eq: "231"}),这是不合法的,可以直接通过in,not in的方式来实现
- filter中不是所有字段都可作为查询参数,根据每个API接口提供的查询参数进行相应配置
- 需要特别注意,在filter中如果查询值是字符串,需对相应的 双引号 转义
//查询语句事例, filter中的双引号需转义
public static String selectStatement = "{ tm_class(first: 1, offset:10, filter:{name:{eq : \"123\"}}){ num name id } }";
public static void main(String[] args) {
Map<String, String> bodyMap = new HashMap<String, String>();
bodyMap.put("query", selectStatement);
String response = null;
try {
response = HttpUtils.get(apiEndPoint, new Gson().toJson(bodyMap), "");
}catch (Exception e) {
e.printStackTrace();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
filter查询关键字
关键字 | 符号 | 解释 | 案例 |
---|---|---|---|
eq | == | 等号 | {userid:{eq : "123"}} |
ne | != | 不等于 | {userid:{ne: "123"}} |
ge | >= | 大于等于 | {userid:{ge: "123"}} |
gt | > | 大于 | {userid:{gt: "123"}} |
le | <= | 小于等于 | {userid:{le: "123"}} |
lt | < | 小于 | {userid:{lt: "123"}} |
like | like | sql中like语法 | {userid:{like: "%123%"}} |
nlike | nlike | sql中not like语法 | {userid:{nlike: "%123%"}} |
in | in |
sql中的in语法
多个值之间用逗号隔开 查询值用[]包围 |
{userid:{in: ["123", "321"]}} |
nin | not in |
sql中的not in语法
多个值之间用逗号隔开 查询值用[]包围 |
{userid:{nin: ["123", "321"]}} |
nil | null |
sql中is null语法
查询值用”“ |
{userid:{nil: ""]}} |
notnull | not null |
sql中is not null语法
查询值用”“ |
{userid:{notnull: ""]}} |
filter查询逻辑符(AND/OR)
- filter中也支持AND和OR的逻辑符号,优先级和数据库sql查询一致。默认缺省值为AND。 通过嵌套逻辑符号,可以实现十分复杂的过滤查询。
下面通过一些常用的配置,基本可以了解filter的相应的写法
- 缺省查询条件
# sql中查询 (name="123" and age > 1)转换成graphql的filter写法
filter:{name:{eq : \"123\"}, age:{gt : 1}}
# 上面的filter和下面filter语句的语义是一致的
filter:{and:{name:{eq : \"123\"}, age:{gt : 1}}}
1
2
3
4
2
3
4
- 实现sql中between...and...的
# sql中查询 (name="123" and age between 1 and 10)转换成graphql的filter写法
filter:{and:{name:{eq : \"123\"}, age:{ge : 1, le : 10}}}
1
2
2
- 简单的or查询
#sql中查询(name is null or name="123")转换成graphql的filter写法
filter:{or:{name:{nil : \"\", eq : \"123\"}}}
#sql中查询(name = "123" or age > 10)
filter:{or:{name : {eq : \"123\"}, age: {lt: 10}}}
1
2
3
4
5
2
3
4
5
- AND语句中嵌套OR ( 复杂的条件语句不能使用缺省条件 )
#sql中查询(age > 10 and (name is null or name like "王%"))转换成graphql的filter写法
filter:{and: {age: {gt : 10}, or:{name : {nil: \"\", like: \"王%\"}}}}
1
2
2
- OR语句中嵌套And ( 复杂的条件语句不能使用缺省条件 )
#sql中查询(age > 10 or (name is not null and name like "王%"))转换成graphql的filter写法
filter:{or: {age : {gt : 10}, and: {name : {notnull : \"\", like : \"王%\"}}}}
1
2
2
# 分页查询关键字
过滤条件3大关键字(offset, first, filter), offset和first就是用来指定分页的参数。对于没有指定分页参数的,默认最多返回500条数据。
- first:第一条数据开始的位置, first最小值为1
- offset: 偏移量,一次查询获取最大多少数据
- 假设一次查询10条数据,第一次为(first:1, offset: 10), 则第二次为(first:11, offset:10)。即第二次查询first= (前一次first + 前一次offset)
- 分页查询实例
#第一次查询10条数据
{ tm_class(first: 1, offset:20){ num name id } }
#则第二次查询10条数据
{ tm_class(first: 21, offset:20){ num name id } }
1
2
3
4
5
2
3
4
5
# GraphQL构造示例
示例
graphql语句嵌入查询条件
public class GraphqlFilterHandler {
public final static String FILTER_KEYWORD = "filter";
public final static String PAGE_FIRST_KEYWORD = "first";
public final static String PAGE_OFFSET_KEYWORD = "offset";
* @Title: GraphqlStatementAddFilterCriteria
* @Description: 嵌入的过滤条件
* @param: @param graphqlStatement : graphql查询语句
* @param: @param criteriaEntities :查询条件
* @param: @return
* @return: String
* @throws
public static String GraphqlStatementAddFilterCriteria(String graphqlStatement, CriteriaEntity...criteriaEntities ) {
String filterStatement = buildCriteria(graphqlStatement, criteriaEntities);
graphqlStatement = addFilterCriteria(graphqlStatement, filterStatement);
return graphqlStatement;
* @Title: GraphqlStatementAddFilterCriteria
* @Description: 附带 分页参数
* @param: @param graphqlStatement
* @param: @param pagePara
* @param: @return
* @return: String
* @throws
public static String GraphqlStatementAddFilterCriteria(String graphqlStatement, int first,
int offset, CriteriaEntity...criteriaEntities) {
String pageFirstStatement = PAGE_FIRST_KEYWORD + " : " +first;
String pageOffsetStatement = PAGE_OFFSET_KEYWORD + " : " + offset;
String filterStatement = buildCriteria(graphqlStatement, criteriaEntities);
if(StringUtils.isEmpty(filterStatement)) {
filterStatement = "(" + pageFirstStatement + ", " + pageOffsetStatement + ")";
}else {
int pos = filterStatement.indexOf(")");
String suffix = filterStatement.substring(0, pos);
filterStatement = suffix + ", " + pageFirstStatement + ", " + pageOffsetStatement + ")";
graphqlStatement = addFilterCriteria(graphqlStatement, filterStatement);
return graphqlStatement;
private static String buildCriteria(String graphqlStatement, CriteriaEntity...criteriaEntities) {
String filterStatement = "";
Map<String, Object> filterMap = new HashMap<String, Object>();
for(CriteriaEntity criteriaEntity : criteriaEntities) {
QueryFilterEnum filterEnum = criteriaEntity.getQueryFilterEnum();
Map<String, Object> map = filterEnum.criteriaStatement(criteriaEntity);
filterMap.put(criteriaEntity.getFieldName(), map);
if(filterMap.size() == 0) {
if(graphqlStatement.indexOf(FILTER_KEYWORD) != -1) {
filterStatement = graphqlStatement.substring(graphqlStatement.indexOf("(") , graphqlStatement.indexOf(")") + 1);
return filterStatement;
}else {
return filterStatement;
Gson gson = new Gson();
filterStatement = gson.toJson(filterMap);
filterStatement = filterStatement.replaceAll("\"(\\w+)\"(\\s*:\\s*)", "$1$2");
if(graphqlStatement.indexOf(FILTER_KEYWORD) != -1) {
int pos = graphqlStatement.indexOf(FILTER_KEYWORD);
int criteriaPos = graphqlStatement.indexOf("{", pos);
filterStatement = filterStatement.substring(1, filterStatement.length()-1);
String suffix = graphqlStatement.substring(graphqlStatement.indexOf("("), criteriaPos+1);
String prefix = graphqlStatement.substring(criteriaPos+1, graphqlStatement.indexOf(")")+1);
filterStatement = suffix + filterStatement + " " + prefix;
}else {
filterStatement = "( " + FILTER_KEYWORD + ":" + filterStatement + ")";
return filterStatement;
* 过滤过滤条件添加到graphql语句中
* 前提条件:graphql语句本身不带过滤条件
* @Title: addFilterCriteria
* @param: @param graphqlStatement
* @param: @param filter
* @param: @return
* @return: String
* @throws
private static String addFilterCriteria(String graphqlStatement, String filter) {
if(graphqlStatement.indexOf("(") != -1) {
graphqlStatement = graphqlStatement.substring(0, graphqlStatement.indexOf("(")) + graphqlStatement.substring(graphqlStatement.indexOf(")") +1);
int postion = graphqlStatement.indexOf("{", graphqlStatement.indexOf("{") + 1);
String prefix = graphqlStatement.substring(0, postion);
graphqlStatement = prefix + filter + graphqlStatement.substring(postion, graphqlStatement.length());
return graphqlStatement;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
CriteriaEntity构造类
public class CriteriaEntity implements Serializable {
private static final long serialVersionUID = -300137530104056710L;
public CriteriaEntity(String fieldName, Object argValue, QueryFilterEnum queryFilterEnum) {
this.fieldName = fieldName;
this.argValue = argValue;
this.queryFilterEnum = queryFilterEnum;
private String fieldName;
private Object argValue;
private QueryFilterEnum queryFilterEnum;
public String getFieldName() {
return fieldName;
public Object getArgValue() {
return argValue;
public QueryFilterEnum getQueryFilterEnum() {
return queryFilterEnum;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
查询关键字枚举类
枚举类示例中,仅配置了部分枚举,供参考。
public enum QueryFilterEnum {
GE("ge"){
@Override
public Map<String, Object> criteriaStatement(CriteriaEntity criteriaEntity) {
Map<String, Object> map = new HashMap<String, Object>();
map.put(getKey(), criteriaEntity.getArgValue());
return map;
IN("in") {
@Override
public Map<String, Object> criteriaStatement(CriteriaEntity criteriaEntity) {
Object argVal = criteriaEntity.getArgValue();
if(argVal instanceof List || argVal instanceof Set) {
Map<String, Object> map = new HashMap<String, Object>();
map.put(getKey(), argVal);
return map;
}else {
throw new ClassCastException(String.format("filed name: %s, can not cast to List or Set", criteriaEntity.getFieldName()));
QueryFilterEnum(String key) {
this.key = key;
private String key;
public String getKey() {
return key;
public abstract Map<String, Object> criteriaStatement(CriteriaEntity criteriaEntity);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
账号类APIs