本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长


+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

2024-11(2)

SpringBoot 中集成 GraphQL:入门篇

发布于2021-05-29 21:38     阅读(556)     评论(0)     点赞(16)     收藏(2)


说实话,网上这玩意资料太少了,用的人也挺少的,不是因为技术需求,估计大家都不会想用,这次来把这个小东西稍微记录一下

一、关于 GrapQL

1、什么是 GraphQL?

官方解释:一种用于 API 的查询语言
看了这句话之后我是懵逼的,没看懂,如果你也没看懂看看下面这句话

请求你所要的数据,不多不少
什么意思呢,很简单,假如我有一个查询用户信息的 restful 接口,里面会返回一些信息,用户名,密码,头像,等等,现在前端和我说,

前端:我只要用户名和头像,其他的都不要,你别查出来给我了
我:what?你不要的数据你不用不就行了,这接口不止你 web 端用,还有 app 接口也在用呢
前端:那我不管,现在需求就是这样
我:……

这个时候 GraphQL 出现了,你想要用户名和头像是吧,行,你自己来取,你要什么自己取什么,后端就会给你返回什么,后端也不用单独来给你写接口,说到这里,你可能似懂非懂,没关系,接着看下去

2、怎么使用?

别着急,继续往下看

二、Idea 中安装 GraphQL 插件

1、安装 JS GraphQL 插件

在这里插入图片描述

2、安装之后

新建文件可以选择新建 graphql 文件
在这里插入图片描述

工具栏也会出现 graphql
这里面会自动去检查我们写的 graphql 文件中语法是否正确
在这里插入图片描述

三、编写一个简单的 GrapQL

1、引入相关依赖

 		<dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
 <!-- 必需:包含了默认配置、graphql-java 和 graphql-java-tools,可以简化配置 -->
        <dependency>
            <groupId>com.graphql-java-kickstart</groupId>
            <artifactId>graphql-spring-boot-starter</artifactId>
            <version>11.0.0</version>
        </dependency>

        <!-- 可选:用于调试 GraphQL,功能类似 Restful 中的 Swagger -->
        <dependency>
            <groupId>com.graphql-java-kickstart</groupId>
            <artifactId>playground-spring-boot-starter</artifactId>
            <version>11.0.0</version>
        </dependency>

2、yml 配置

# 端口
server:
  port: 7002

# 应用名称
spring:
  application:
    name: graphql-demo

# graphql 相关配置
graphql:
  servlet:
    mapping: /graphql
    enabled: true
    corsEnabled: false # 关闭跨域,仅使用浏览器插件调试时设置为false
    playground:
      cdn:
        enabled: true    # playground 使用 cdn 的静态文件
    # if you want to @ExceptionHandler annotation for custom GraphQLErrors
    exception-handlers-enabled: true
    contextSetting: PER_REQUEST_WITH_INSTRUMENTATION
  tools:
    #扫描 resource 下 .graphql 后缀的文件
    schema-location-pattern: "**/*.graphql"


3、新建一个 clazz.graphql 文件

#定义查询类型和更改类型
schema {
    query: Query
    mutation: Mutation
}

#查询方法, 类型来源于上面定义的 Query
  type Query{
    #查询所有班级,返回 list<Clazz>
    listClazz: [Clazz]
    #根据名称查询班级,返回单个 Clazz 对象
    listClazzByName(name:String!): Clazz
}

#变更方法 , 类型来源于上面定义的 Mutation
 type Mutation{
    # 新增班级(返回 Result 对象)
    add(code:String!,name:String!,description:String!): Result
    # 修改班级(返回 Result 对象)
    edit(id:String!,code:String!,name:String!,description:String!): Result
    # 删除班级(返回 Result 对象)
    del(id:String!): Result
    # 创建班级(入参类型为对象 ClazzInputaddByInput(input: ClazzInput!): Result
}

#班级实体
type Clazz{
    #id
    id : String
    #编号
    code : String!
    #名称
    name : String!
    #描述
    description : String!
}


#班级 input 对象
input ClazzInput{
    #id
    id : String
    #编号
    code : String!
    #名称
    name : String!
    #描述
    description : String!

}

type Result{
    #状态码
    code : Int!
    #状态信息
    msg : String!

}

4、相关语法解释

  • .graphql 文件中注释用: #注释内容

  • Query下定义的是查询相关接口,Mutation下定义的是修改相关接口

  • Query 和 Mutation 方法格式
    Query中方法格式为 : 方法名:返回类型 例如:listClazz: [Clazz]

    方法名(参数名:参数类型):返回类型 例如:listClazzByName(name:String!): Clazz 参数类型后面加 !
    代表这个参数不能为空,可为空则不加 ! 即可

  • Mutation 中方法格式基本和 Query 一致

  • type Clazz 你可以理解为定义一个名为 Clazz 的 java 实体类,里面就是它的一些属性,type Result 也一样

  • input ClazzInput 则是定义一个输入类型,可以看到属性基本和 Clazz 一致,只是定义时将 type 改成了 input,作用我们可以理解为,我们可以直接传输这个对象,稍后来进行讲解

5、编写 java 实体类

先把两个对应的 java 实体类写好,属性同 graphql 文件中对象一致

package com.wxw.notes.graphql.demo.entity;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author wuxiongwei
 * @date 2021/5/25 16:38
 * @Description
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Clazz {
    private String id;
    private String code;
    private String name;
    private String description;
}
package com.wxw.notes.graphql.demo.entity;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author wuxiongwei
 * @date 2021/5/25 16:38
 * @Description
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class ClazzInput {
    private String id;
    private String code;
    private String name;
    private String description;
}

package com.wxw.notes.graphql.demo.response;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Result {
    private Integer code;
    private String msg;
}

6、编写 Query 和 Mutation 解析器

package com.wxw.notes.graphql.demo.resolver;

import com.wxw.notes.graphql.demo.entity.Clazz;
import com.wxw.notes.graphql.demo.entity.ClazzInput;
import com.wxw.notes.graphql.demo.response.Result;
import com.wxw.notes.graphql.demo.service.ClazzService;
import graphql.kickstart.tools.GraphQLMutationResolver;
import graphql.kickstart.tools.GraphQLQueryResolver;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * @author wuxiongwei
 * @date 2021/5/25 16:37
 * @Description
 */
@Component
public class ClazzResolver implements GraphQLQueryResolver, GraphQLMutationResolver {

    private final ClazzService clazzService;

    public ClazzResolver(ClazzService clazzService) {
        this.clazzService = clazzService;
    }

    public List<Clazz> listClazz(){
        return clazzService.list();
    }

    public Clazz listClazzByName(String name){
        return clazzService.listByName(name);
    }

    public Result add(String code, String name, String description){
        return clazzService.add(code,name,description);
    }

    public Result del(String id){
        return clazzService.del(id);
    }

    public Result edit(String id,String code, String name, String description){
        return clazzService.edit(id,code,name,description);
    }

    public Result addByInput(ClazzInput cla){
        return clazzService.addByInput(cla);
    }

}

GraphQLQueryResolver 顾名思义就是 Query 查询相关的解析器了
GraphQLMutationResolver 就是 Mutation 更改相关的解析器了

我这里就直接写在一个类里面了(可以选择分开写两个类去分别实现),同时实现
GraphQLQueryResolver 和 GraphQLMutationResolver

7、编写 Service 层方法

在 service 层,我们一般是查询数据库数据,之前怎么查现在还是怎么查,在这里我就简单在内存里面初始化一些数据了

package com.wxw.notes.graphql.demo.service;

import com.wxw.notes.graphql.demo.entity.Clazz;
import com.wxw.notes.graphql.demo.entity.ClazzInput;
import com.wxw.notes.graphql.demo.response.Result;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * @author wuxiongwei
 * @date 2021/5/25 16:38
 * @Description
 */
@Service
public class ClazzService {

    private List<Clazz> clazzList = new ArrayList<Clazz>(){{
        add(Clazz.builder().id(UUID.randomUUID().toString()).code("001").name("三年二班").description("加里顿第一班").build());
    }};


    public Clazz listByName(String name){
        Optional<Clazz> first = clazzList.stream().filter(clazz -> clazz.getName().equals(name)).findFirst();
        return first.orElse(null);
    }

    public List<Clazz> list(){
        return clazzList;
    }

    public Result add(String code, String name, String description){
        Clazz clazz = new Clazz();
        clazz.setId(UUID.randomUUID().toString());
        clazz.setCode(code);
        clazz.setName(name);
        clazz.setDescription(description);

        clazzList.add(clazz);

        return Result.builder().code(200).msg("success").build();
    }

    public Result del(String id){

        clazzList = clazzList.stream().filter(clazz -> !clazz.getId().equals(id)).collect(Collectors.toList());
        return Result.builder().code(200).msg("success").build();
    }

    public Result edit(String id,String code, String name, String description){
        del(id);
        add(code, name, description);
        return Result.builder().code(200).msg("success").build();
    }

    public Result addByInput(ClazzInput cla){
        Clazz clazz = new Clazz();
        clazz.setId(UUID.randomUUID().toString());
        clazz.setCode(cla.getCode());
        clazz.setName(cla.getName());
        clazz.setDescription(cla.getDescription());
        clazzList.add(clazz);
        return Result.builder().code(200).msg("success").build();
    }
}

8、见证 GraphQL 使用

一切准备工作就绪之后,我们用 playground 图形化工具来看看 graphql 到底怎么来进行使用

启动我们的工程,访问 localhost:7002/playground
就可以看到下面这个界面了,默认界面风格是黑色,如果你想要修改成我这颜色,点击右上角设置
“editor.theme” 的值修改成 “light” 然后点击右上角保存即可

左边的查询语句,可能大家一进来就是空的,截图的查询语句是我这边之前测试写的

在这里插入图片描述

接下来,我们依次来调用下我们写的 graphql 方法,看看怎么调用
首先调用查询所有班级的方法,可以点开右侧 DOCS 文档,对照来写,我们想查询哪些信息,我左边就写哪些字段,我先查询所有字段

8.1、Query 查询

# listClazz 调用的方法名
# id,code,name,description 调用后想要得到的返回值
{
  listClazz {
    id
    code
    name
    description
  }
}

在这里插入图片描述
这个时候我们来解决前端给我的问题,假如小伙子不要 id 了,简单,你自己查询的时候直接去掉就行了,这样我就不给你 id 了,如下

# listClazz 调用的方法名
# code,name,description 调用后想要得到的返回值
{
  listClazz {
    code
    name
    description
  }
}

在这里插入图片描述
再调用根据名称查询班级的方法,直接放入参数

# listClazzByName 调用的方法名
# name 参数属性名,三年二班 参数值
# code,name,description 调用后想要得到的返回值
  listClazzByName(name:"三年二班"){
    code
    name
    description
  }

在这里插入图片描述

8.2 、使用变量 Variables

再调用根据名称查询班级的方法,使用变量 Variables 传入参数

# query  查询关键字
# listClazzByName 别名
# $name:String! name 为声明变量,String 类型,不为空(变量前加 $)
# listClazzByName 方法名,name 属性名,$name 引用上面声明的变量
# code,name,description 查询后想要的返回值
query listClazzByName($name:String!){
  listClazzByName(name:$name){
    code
    name
    description
  }
}

# json 格式
{
  "name":"三年二班"
}

在这里插入图片描述

8.3、 Mutation 变更

我们来单独写变更中的 新增

 # mutation 变更关键字
 # add 方法名
 # code,name,description 参数
 # code,msg 请求后想要返回的返回值
  mutation{
    add(code: "001"
      name: "三年三班"
  	  description: "加里顿第二班级"){
      code
      msg
    }
  }

在这里插入图片描述

新增之后,再查询所有看看,可以看到已经成功添加了

在这里插入图片描述

8.4、Input 输入类型

接下来我们看看上文说到的输入类型怎么使用

# mutation 变更关键字
# addByInput 别名
# $clazzInput:ClazzInput! ,声明变量 $clazzInput ,类型为 ClazzInput ,不为空
# addByInput 接口名,input:$clazzInput  input 入参类型, $clazzInput 引用变量
# code,msg 调用接口后想要的返回值

mutation addByInput($clazzInput:ClazzInput!){
  addByInput(input:$clazzInput){
    code
    msg
  }
}

# 参数
{
  "clazzInput": {
    "code": "003",
    "name": "三年四班",
    "description": "加里顿第三班"
  }
}

在这里插入图片描述
新增之后,再查询所有看看,可以看到已经成功添加了
在这里插入图片描述

好了,基本用法就分享到这里了,大家有兴趣可以自行查阅官网

官网地址

四、总结

1、这只是一个简单的 demo,我们 java 中复杂的实体对象怎么实现呢?嵌套对象,嵌套集合等等

2、多个 .graphql 文件怎么引用呢?我们不可能一个 graphql 文件里面把所有的实体类都写了

3、使用 graphql 我们会遇到哪些问题?怎么去解决定位呢?

是不是觉得不过瘾,感觉还没有看到你想要的,想了解更多的可以进入下一篇深入了解,源码地址也会在下一篇进行分享

下一篇传送门:SpringBoot 中集成 GraphQL:深入篇



所属网站分类: 技术文章 > 博客

作者:我是一个射手

链接:http://www.javaheidong.com/blog/article/207378/7b8acd9e11fcfc3ebd1b/

来源:java黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

16 0
收藏该文
已收藏

评论内容:(最多支持255个字符)