SpringBoot 中集成 GraphQL:深入篇

本文介绍了如何在GraphQL中初始化数据,包括.graphql文件的定义、对象之间的关联以及复杂对象的处理。通过示例展示了查询和变更操作,包括对象中嵌套对象和对象集合的查询与变更。同时,提供了Java后端实体类和resolver的实现。文章强调了GraphQL在实际开发中的应用,并指出了后续学习的方向和注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

接着上一篇的问题来写,直接在原有的基础上进行改造了

一、初始化数据

为了后面的复杂逻辑,我这边先初始化一些 .graphql 文件 和 java 实体类
后面根据逻辑会一一给大家讲解

1、root.graphql

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

# 定义一个空的查询类型
type Query{

}

# 定义一个空的更改类型
type Mutation{

}

2、result.graphql

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

}

3、student.graphql

type Student{
    #id
    id : String
    #编号
    code : String!
    #名称
    name : String!
    #描述
    description : String!

}

input StudentInput{
    #id
    id : String
    #编号
    code : String!
    #名称
    name : String!
    #描述
    description : String!

}

4、teacher.graphql

extend type Query{
    listTeacher:[Teacher]
}

type Teacher{
    code : String
    name : String
    description : String
}

input TeacherInput{
    code : String
    name : String
    description : String
}

5、上一篇文章 clazz.grapql 调整

#查询方法, 继承 root 定义的 Query
extend  type Query{
    #查询所有班级,返回 list<Clazz>
    listClazz: [Clazz]
    #根据名称查询班级,返回单个 Clazz 对象
    listClazzByName(name:String!): Clazz
}

#变更方法 , 继承 root 定义的 Mutation
extend 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!
    #假设一个班一个班主任
    teacher : Teacher
    #学生集合
    studentList : [Student]
}

#班级 input 对象
input ClazzInput{
    #id
    id : String
    #编号
    code : String!
    #名称
    name : String!
    #描述
    description : String!
    #假设一个班一个班主任
    teacher : TeacherInput
    #学生集合
    studentList : [StudentInput]
}

一、多个 .graphql 文件相互间的关联

在我们日常开发中,通常是一个对象就是一个 java 实体类,那么我们肯定也希望在 graphql 中也如此,也就是一个对象对应一个 .graphql 文件
其实这个有影响的只是包含 Query 和 Mutation 的,如果 graphql 文件只是定义对象则无影响

1、定义一个 root.grophql

这个在初始化数据的时候已经定义好了

2、其他 graphql 文件只需要继承

#继承 root Query
extend type Query

#继承 root Mutation
extend type Mutation

比如上一篇的 clazz.graphql

#查询方法, 继承 root 定义的 Query
extend  type Query{
    #查询所有班级,返回 list<Clazz>
    listClazz: [Clazz]
    #根据名称查询班级,返回单个 Clazz 对象
    listClazzByName(name:String!): Clazz
}

#变更方法 , 继承 root 定义的 Mutation
extend 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
}

如果某个 graphql 文件里面只有定义对象的,而没有 Query 和 Mutation 也就不用继承了
比如原来的 clazz.graphql 里面有一个 result 对象,现在我单独提取出来了(引用的话还是照常引用就可以)

像这个里面没有 Query 和 Mutation ,只有一个定义对象的,那就直接定义我们的对象就好了,不用去继承

请看初始化数据中的 result.graphql

比如新定义一个 teacher.graphql ,里面有一个查询方法,这个 Query 就需要在前面加 extend 关键字了

请看初始化数据中的 teacher.graphql

3、引用其他 graphql 文件中定义的对象

比如我在 clazz.graphql 文件中引用了三个外部文件中的对象

Result ,用来获取返回值

#变更方法 , 继承 root 定义的 Mutation
extend 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
}

Student ,用来内置一个学生集合属性
Teacher ,用来内置一个班主任属性对象

#班级实体
type Clazz{
    #id
    id : String
    #编号
    code : String!
    #名称
    name : String!
    #描述
    description : String!
    #假设一个班一个班主任
    teacher : Teacher
    #学生集合
    studentList : [Student]
}

teacher : Teacher ,表示定义一个属性 teacher,类型为 Teacher 对象
studentList : [Student] ,表示定义一个属性 studentList ,类型为 Student 集合
[] 就表示一个数组

二、 复杂对象

1、初始化 java 代码

由于初始化时增加了部分 graphql 对象并且 clazz 对象也有变更,这里把对应 java 代码贴上

Student 实体类

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 Student {
    private String id;
    private String code;
    private String name;
    private String description;
}

Teacher 实体类

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

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

/**
 * @author wuxiongwei
 * @date 2021/5/26 9:01
 * @Description
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Teacher {
    private String code;
    private String name;
    private String description;
}

Clazz 实体类

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

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

import java.util.List;

/**
 * @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;
    private Teacher teacher;
    private List<Student> studentList;
}

TeacherResolver

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

import com.wxw.notes.graphql.demo.entity.Teacher;
import graphql.kickstart.tools.GraphQLQueryResolver;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

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

    private List<Teacher> teacherList = new ArrayList<Teacher>(){{
        add(Teacher.builder().code("A01").name("张大炮").build());
    }};
    
    public List<Teacher> listTeacher(){
        return teacherList;
    }
    
}

ClazzResolver

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

import com.wxw.notes.graphql.demo.entity.Clazz;
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(Clazz cla){
        return clazzService.addByInput(cla);
    }

}

ClazzService

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

import com.wxw.notes.graphql.demo.entity.Clazz;
import com.wxw.notes.graphql.demo.entity.Student;
import com.wxw.notes.graphql.demo.entity.Teacher;
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>(){{
        List<Student> studentList = new ArrayList<Student>(){{
            add(Student.builder().id(UUID.randomUUID().toString()).code("001").name("张三").description("法外狂徒").build());
            add(Student.builder().id(UUID.randomUUID().toString()).code("002").name("李四").description("路人之王").build());
        }};
        add(Clazz.builder()
                .id(UUID.randomUUID().toString())
                .code("001")
                .name("三年二班")
                .description("加里顿第一班")
                .studentList(studentList)
                .teacher(Teacher.builder().code("A001").name("班主任").build())
                .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(Clazz cla){
        Clazz clazz = new Clazz();
        clazz.setId(UUID.randomUUID().toString());
        clazz.setCode(cla.getCode());
        clazz.setName(cla.getName());
        clazz.setDescription(cla.getDescription());
        clazz.setTeacher(cla.getTeacher());
        clazz.setStudentList(cla.getStudentList());
        clazzList.add(clazz);
        return Result.builder().code(200).msg("success").build();
    }
}

2、对象中嵌套对象和对象集合查询

为了测试效果,我在 clazz 中放了一个 teacher 对象属性 和一个 student 集合
启动我们的项目,继续访问 http://localhost:7002/playground

首先我们来个简单查询,不查 teacher 和 student,我们只要 clazz 的基础信息,那么我们只需要这样写

{
  listClazz {
    id
    code
    name
    description
  }
}

在这里插入图片描述

此时我们加上查询 teacher 和 student 的语句,也就是把我们想要的属性写出来,也不需要修改我们的后台代码

{
  listClazz {
    id
    code
    name
    description
    teacher{
      code
      name
    }
    studentList{
      code
      name
      description
    }
  }
}

效果如下
在这里插入图片描述

3、对象中嵌套对象和对象集合变更

这里来写一个插入的方法
因为参数值比较多,我们这里就采用输入类型进行添加

# mutation 变更关键字
# addByInput 别名
# $clazzInput:ClazzInput! , clazzInput 声明参数,ClazzInput 参数类型,
# 不为空
# addByInput 对应 clazz.graphql 中的方法名
# input 输入类型,$clazzInput 引入声明的参数
# code,msg 想要的返回参数
mutation addByInput($clazzInput:ClazzInput!){
  addByInput(input:$clazzInput){
    code
    msg
  }
}

variables 参数

# json 格式
{
  "clazzInput": {
    "code": "003",
    "name": "三年四班",
    "description": "加里顿第三班",
    "teacher":{
      "code":"A002",
      "name":"班主任02"
    },
    "studentList":[
      {
         "code": "003",
         "name": "王五",
         "description": "王老五"
      },
       {
         "code": "004",
         "name": "赵六",
         "description": "小六"
      }
    ]
  }
}

在这里插入图片描述

三、最终目录及源码下载

目录
在这里插入图片描述

源码下载地址:点击查看

四、总结:学习 GraphQL 之后

1、初步学习之后的问题

  • 我们要了解,现在这一切都是基于 Java 后端,肯定前端开发也需要学习使用这一套的查询语言调用我们写的接口才有用,就像我们自己现在都是用 playground 图形化工具来调用,后续项目开发肯定不会这样(因为本身也略懂一点前端,后续有时间可能会计划学习一下前端如何使用,当然这些官网都有)

  • 目前这些内容也是边学边写,后续肯定还有更为复杂的,比如分页怎么查询、GrapQL 里面其他的(目前我们学习过程中只用到了 int,String,对象,数组)数据类型怎么和我们 Java 里面的数据类型对应起来,这个都是我们还要继续去学习的地方

2、关于 GraphQL 需要注意的点

  • type Query 方法名和我们 resolver 中的方法名必须一致
  • graphql 文件中定义的对象的属性列,必须在 java 实体类中一一进行对应,java 实体类中可以有不存在

下一篇传送门:SpringBoot 集成 GraphQL 遇到的问题

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值