hello,大叫好,我是小黑,又和大家见面啦~

今天我们来继续学习 Spring Boot GraphQL 实战,我们使用的框架是 https://github.com/graphql-java-kickstart/graphql-spring-boot

项目 github 地址:https://github.com/shenjianeng/graphql-spring-boot-example

Query(查询)

带参数的查询

首先,在 classpath 下创建 graphqls 文件:

type Book{
id:ID!
name:String!
} type Query{
# 根据 id 查询 book,参数名为 id,参数类型的 ID 类型,结果返回 book
getBookById(id:ID!):Book
}

创建一个 Spring Bean,此处需要实现 GraphQLQueryResolver 接口,并在该类中自定义一个方法来映射 graphqls 文件中的查询。

@Data
public class Book {
private int id;
private String name;
} @Component
public class BookGraphQLQueryResolver implements GraphQLQueryResolver { public Book getBookById(int id) {
Book book = new Book();
book.setId(id);
book.setName("这边书没有书名");
return book;
}
}

复合字段查询

需求:每本书都有作者,在查询书本信息时,有时需要返回作者信息。

# 定义 Author 数据类型结构
type Author{
id:ID!
name:String!
} type Book{
id:ID!
name:String!
# 增加 author 字段,数据类型为 Author
author:Author
} type Query{
# 根据 id 查询 book,参数名为 id,参数类型的 ID 类型,结果返回 book
getBookById(id:ID!):Book
}

再看一下此时我们的 Java Bean:

@Data
public class Author {
private UUID id;
private String name;
} @Data
public class Book {
private long id;
private String name;
}

看仔细哦,Book 类中并没有 author 字段,Book 中 author 信息将由 graphql.kickstart.tools.GraphQLResolver 来提供。

@Slf4j
@Component
public class BookGraphQLResolver implements GraphQLResolver<Book> { public Author author(Book book) {
log.info("book id :{} query author info", book.getId());
Author author = new Author();
author.setId(UUID.randomUUID());
author.setName(String.format("我是[%s]的作者", book.getName()));
return author;
}
}

ok,让我们启动服务,访问 http://localhost:8080/graphiql

而当客户端不需要 author 信息时,服务端就不会执行 BookGraphQLResolver#author,真正做到了使得客户端能够准确地获得它需要的数据,而且没有任何冗余

(ps:如果你是服务端开发,你会怎么实现呢?是给客户端提供一个接口返回 book 和 author 信息,还是给客户端提供两个不同的接口呢?)

Mutation(变更)

在 graphqls 文件中,使用 Query 来定义查询接口,使用 Mutation 可以定义变更数据的操作。

type Mutation{
createBook(id:ID!,name:String!):Book
}

上述 graphqls 文件中定义了一个 createBook 的方法,参数列表为 idname ,方法返回创建的 Book 对象。

与之对应的 Java 代码如下:

@Component
public class BookGraphQLMutationResolver implements GraphQLMutationResolver { public Book createBook(int id, String name) {
Book book = new Book();
book.setId(id);
book.setName(name);
return book;
}
}

BookGraphQLMutationResolver 实现了 graphql.kickstart.tools.GraphQLMutationResolver 接口,表明当前类中的方法用来映射 graphqls 文件中的 Mutation。

Input Types

当 Mutation 中请求参数特别多时,我们可以使用 Input Types 来优化代码。

type Mutation{
createBook(id:ID!,name:String!):Book
create(bookInput:BookInput!):Book
} input BookInput{
id:ID!
name:String!
}

同理,我们也需求在 BookGraphQLMutationResolver 中添加对应的方法来映射。

@Component
public class BookGraphQLMutationResolver implements GraphQLMutationResolver {
// ...省略其他代码 public Book create(BookInput input) {
Book book = new Book();
book.setId(input.getId());
book.setName(input.getName());
return book;
}
}

客户端请求代码如下:

自定义标量类型

在 GraphQL 中自带一些默认标量类型:

  • Int:有符号 32 位整数

  • Float:有符号双精度浮点值

  • String:UTF‐8 字符序列

  • Booleantrue 或者 false

  • ID:ID 标量类型表示一个唯一标识符,通常用以重新获取对象或者作为缓存中的键。ID 类型使用和 String 一样的方式序列化

使用 graphql-java-extended-scalars 库

在 Java 这个生态中,我们可以引入下面这个库来帮助我们很方便的进行扩展:

https://github.com/graphql-java/graphql-java-extended-scalars

  <dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-java-extended-scalars</artifactId>
<version>15.0.0</version>
</dependency>

graphql-java-extended-scalars 中具体扩展了哪些标量类型,我们都可以在 graphql.scalars.ExtendedScalars 类中找到。

(ps:一个小技巧,s 结尾的类一般都是工具类)

如何使用呢?

  1. 向 Spring 容器中注册自定义标量
  2. 在 graphqls 文件中声明要使用的自定义标量
  3. 直接使用即可

相关示例代码如下:

@Configuration
public class CustomScalarTypeConfig { @Bean
public GraphQLScalarType graphQLLong() {
return ExtendedScalars.GraphQLLong;
}
}
scalar Long

type Book{
id:ID!
name:String!
# 增加 author 字段,数据类型为 Author
author:Author
totalPageSize:Long
}

使用 GraphQLScalarType 自定义标量类型

我们可以参考 graphql.scalars.java.JavaPrimitives#GraphQLLong 的实现来自定标量类型。

@Bean
public GraphQLScalarType graphQLDate() {
return GraphQLScalarType
.newScalar()
.name("Date")
.description("Date 类型")
.coercing(new Coercing<Date, String>() {
@Override
public String serialize(Object dataFetcherResult) throws CoercingSerializeException {
return new SimpleDateFormat(DATE_FORMAT_PATTERN_DEFAULT).format((Date) dataFetcherResult);
} @Override
public Date parseValue(Object input) throws CoercingParseValueException {
if (input instanceof String) {
try {
return new SimpleDateFormat(DATE_FORMAT_PATTERN_DEFAULT).parse((String) input);
} catch (ParseException e) {
throw new CoercingParseValueException(e);
}
}
throw new CoercingParseValueException(
"Expected a 'String' but was '" + Kit.typeName(input) + "'."
);
} @Override
public Date parseLiteral(Object input) throws CoercingParseLiteralException {
if (!(input instanceof StringValue)) {
throw new CoercingParseLiteralException(
"Expected AST type 'StringValue' but was '" + typeName(input) + "'."
);
}
try {
return new SimpleDateFormat(DATE_FORMAT_PATTERN_DEFAULT).parse(((StringValue) input).getValue());
} catch (ParseException e) {
throw new CoercingParseValueException(e);
}
}
})
.build();
}

DataFetcherResult

在 Resolver 中,我们可以使用 graphql.execution.DataFetcherResult 来包装返回的结果,示例代码如下:

@Component
public class BookGraphQLQueryResolver implements GraphQLQueryResolver { public DataFetcherResult<Book> getBookById(int id) {
if (id <= 0) {
return DataFetcherResult
.<Book>newResult()
.error(new GenericGraphQLError("id 不能为负数"))
.build();
} Book book = new Book();
book.setId(id);
book.setName("这边书没有书名");
return DataFetcherResult
.<Book>newResult()
.data(book)
.build();
}
}

下期预告

下期我们将使用 graphQL 来实现分页,并介绍一些高级特性,例如:异步加载、全局异常处理等。感谢大家的关注和阅读~~

更多学习参考资料:

https://www.graphql-java-kickstart.com/tools/schema-definition/#resolvers-and-data-classes

https://graphql.org/learn/schema/

Spring Boot GraphQL 实战 02_增删改查和自定义标量的更多相关文章

  1. 使用 Spring Boot 搭建一套增删改查(无多余代码)

    前言 这是我学习 Spring Boot 的第三篇文章,终于可以见到效果了.错过的同学可以看看之前的文章 我们为什么要学习 Spring Boot Spring Boot 入门详细分析 在入门的基础上 ...

  2. Spring Boot实现学生信息增删改查

    上一篇博客写了如何初始化一个简单的Spring Boot项目,这次详细记录一下如何连接数据库并实现增删改查基本操作. 我使用的是MySQL 5.5+Navicat,MySQL量级比较轻,当然微软的SQ ...

  3. 上手spring boot项目(三)之spring boot整合mybatis进行增删改查的三种方式。

    1.引入依赖. <!--springboot的web起步依赖--><dependency> <groupId>org.springframework.boot< ...

  4. 上手spring boot项目(三)之spring boot整合mybatis进行增删改查

    使用mybatis框架进行增删改查大致有两种基础方式,一种扩展方式.两种基础方式分别是使用xml映射文件和使用方法注解.扩展方式是使用mybatis-plus的方式,其用法类似于spring-data ...

  5. spring boot集成mongodb的增删改查

    添加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>sp ...

  6. Spring Boot使用Mybatis实现增删改查

    java.com.wms.model.Admin.java 1 package com.wms.model; 2 3 import java.sql.Timestamp; 4 5 public cla ...

  7. Spring Boot GraphQL 实战 01_快速入门

    hello,大家好,我是小黑,又和大家见面啦~ 新开一个专题是关于 GraphQL 的相关内容,主要是通过 Spring Boot 来快速开发 GraphQL 应用,希望对刚接触 GraphQL 的同 ...

  8. Spring JdbcTemplate框架搭建及其增删改查使用指南

    Spring JdbcTemplate框架搭建及其增删改查使用指南 前言: 本文指在介绍spring框架中的JdbcTemplate类的使用方法,涉及基本的Spring反转控制的使用方法和JDBC的基 ...

  9. Spring Boot GraphQL 实战 03_分页、全局异常处理和异步加载

    hello,大家好,我是小黑,又和大家见面啦~ 今天我们来继续学习 Spring Boot GraphQL 实战,我们使用的框架是 https://github.com/graphql-java-ki ...

随机推荐

  1. idea 安装教程

    臭臭是猪臭臭是猪臭臭是猪臭臭是猪臭臭是猪臭臭是猪臭臭是猪臭臭是猪臭臭是猪臭臭是臭臭是猪臭臭是猪臭臭是猪臭臭是猪臭臭是猪臭臭是猪臭臭是猪臭臭是猪臭臭是猪臭臭是猪臭臭是猪臭臭是猪臭臭是猪臭臭是猪臭臭是猪臭 ...

  2. Linux下的MediaWiki的部署启动遇到的问题与解决方案

    1. MySQL安装不成功 解决方案:https://bbs.csdn.net/topics/394377536 2. no space left on device ubuntu 解决方案:http ...

  3. eclipse 老坑巨滑之内存溢出OOM

    绪:今天接手一个古老项目,tomcat6+jdk6.被   java.lang.OutOfMemoryError: PermGen space  啪啪打脸, 网上确实有很多解决方法,主要有三种类型:一 ...

  4. Java String 演进全解析

    前言 String 是我们使用最频繁的对象,使用不当会对内存.程序的性能造成影响,本篇文章全面介绍一下 Java 的 String 是如何演进的,以及使用 String 的注意事项. 下面的输出结果是 ...

  5. c++11-17 模板核心知识(十二)—— 模板的模板参数 Template Template Parameters

    概念 举例 模板的模板参数的参数匹配 Template Template Argument Matching 解决办法一 解决办法二 概念 一个模板的参数是模板类型. 举例 在c++11-17 模板核 ...

  6. CentOS 安装ElasticSearch-head插件

    1 下载ElasticSearch-head安装包 1.1 Git下载ElasticSearch-head #安装git,若机器环境已存在,不需要再次安装 yum install git #下载 gi ...

  7. MySQL二进制文件(binlog)

    二进制文件(binlog)记录对MySQL数据库执行更改的所有操作,但不包括SELECT和SHOW这类操作,因为这类操作没有改变数据. 为什么会有binlog? 首先 binlog 是 Server ...

  8. Spring Cloud 学习 (六) Spring Cloud Config

    在实际开发过程中,每个服务都有大量的配置文件,例如数据库的配置.日志输出级别的配置等,而往往这些配置在不同的环境中也是不一样的.随着服务数量的增加,配置文件的管理也是一件非常复杂的事 在微服务架构中, ...

  9. 区块链学习7:超级账本项目Hyperledger与Fabric以及二者的关系

    ☞ ░ 前往老猿Python博文目录 ░ 一.超级账本(hyperledger) 超级账本(hyperledger)是Linux基金会于2015年发起的推进区块链数字技术和交易验证的开源项目,成员包括 ...

  10. PyQt(Python+Qt)学习随笔:QTableWidget的构造方法

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 QTableWidget有2个构造方法: QTableWidget(QWidget parent = ...