Spring Boot集成Graphql快速入门Demo

1.Graphql介绍

GraphQL 是一个用于 API 的查询语言,是一个使用基于类型系统来执行查询的服务端运行时(类型系统由你的数据定义)。GraphQL 并没有和任何特定数据库或者存储引擎绑定,而是依靠你现有的代码和数据支撑。

优势

  1. GraphQL 速度快,并且比较稳定,GraphQL 的操作是在数据层面的,所以比较快。

  2. GraphQL 可以获取更多的资源,当查询一个数据的时候,不止是这个数据,甚至可以很快地查询到数据引用的另一个数据。GraphQL 可以在单个请求中去获取尽量多的数据,并且在弱网状态下,GraphQL 依旧表现出色。

  3. GraphQL 是单端点查询,并在此端点中去完成所有的查询。

  4. GraphQL 的可持续性非常出色,无论是新字段、还是旧字段,它都能很好地去处理,可维护性也极佳。

  5. GraphQL 具有向下兼容的特性,就算是很久很久以前的功能,GraphQL 还是能很好地去兼容它,保证旧版本的正常运行,同时又不影响新功能的加入以及整体的稳定性。这样做的好处就是,不需要去担忧版本号问题了。

  6. GraphQL 具有强类型,在 GraphQL 的查询中,一个级别对应一个强类型,这个类型充当一个字段的描述。这样的好处就是,在查询之前,可以校验出错误并提示,方便定位问题,提高性能。

  7. 自省:可以查询 GraphQL 服务器支持的类型。这为工具和客户端软件创建了一个强大的平台,可以在这些信息的基础上构建静态类型语言的代码生成、我们的应用程序框架、Relay 或 GraphiQL 等 IDE。

  8. GraphQL 支持使用者去决定服务器支持的类型。这样的好处就是,给很多使用 GraphQL 的 工具或者端建立了一个比较成熟且强大的应用平台,通过这个平台,一些框架、工具得到不断地优化提升。

劣势

  1. GraphQL 无法完成深度查询,所以无法对于未知深度的数据进行一次性查询。

  2. GraphQL 具有非常死板的响应结构,你必须遵从这个结构去查询数据,或者自己添加一个转换器来转换。

  3. GraphQL 无法进行网络级别的缓存,你必须使用另外别的办法进行持久查询。

  4. GraphQL 默认没有上传文件的功能,GraphQL 也不接收文件类型的参数,但是你可以使用 REST 的方式进行上传文件,达到上传文件的目的。

  5. GraphQL 的执行是不可预测的,因为 GraphQL 太过于灵活了。

  6. 同样的一个简单的 API,GraphQL 会表现得很复杂,所以建议简单 API 使用 RSET。

2.mysql环境搭建

参考代码仓库里面的mysql模块,这里只贴出docker-compose.yml

version: '3'services:  mysql:    image: registry.cn-hangzhou.aliyuncs.com/zhengqing/mysql:5.7    container_name: mysql_3306    restart: unless-stopped                                       volumes:      - "./mysql/my.cnf:/etc/mysql/my.cnf"      - "./mysql/init-file.sql:/etc/mysql/init-file.sql"      - "./mysql/data:/var/lib/mysql"#      - "./mysql/conf.d:/etc/mysql/conf.d"      - "./mysql/log/mysql/error.log:/var/log/mysql/error.log"      - "./mysql/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d" # init sql script directory -- tips: it can be excute  when `/var/lib/mysql` is empty    environment:                        # set environment,equals docker run -e      TZ: Asia/Shanghai      LANG: en_US.UTF-8      MYSQL_ROOT_PASSWORD: root         # set root password      MYSQL_DATABASE: demo              # init database name    ports:                              # port mappping      - "3306:3306"

运行

docker-compose -f docker-compose.yml -p mysql5.7 up -d

初始化脚本

CREATE DATABASE IF NOT EXISTS `BOOK_API_DATA`;USE `BOOK_API_DATA`;
CREATE TABLE IF NOT EXISTS `Book` ( `id` int(20) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, `pageCount` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `Index_name` (`name`) ) ENGINE=InnoDB AUTO_INCREMENT=235 DEFAULT CHARSET=utf8;
CREATE TABLE `Author` ( `id` INT(20) NOT NULL AUTO_INCREMENT, `firstName` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8_general_ci', `lastName` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8_general_ci', `bookId` INT(20) NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE, UNIQUE INDEX `Index_name` (`firstName`) USING BTREE, INDEX `FK_Author_Book` (`bookId`) USING BTREE, CONSTRAINT `FK_Author_Book` FOREIGN KEY (`bookId`) REFERENCES `BOOK_API_DATA`.`Book` (`id`) ON UPDATE CASCADE ON DELETE CASCADE) COLLATE='utf8_general_ci'ENGINE=InnoDBAUTO_INCREMENT=6;


INSERT INTO `Book` (`id`, `name`, `pageCount`) VALUES (1, 'the golden ticket', '255');INSERT INTO `Book` (`id`, `name`, `pageCount`) VALUES (2, 'coding game', '300');
INSERT INTO `Author` (`id`, `firstName`, `LastName`, `bookId`) VALUES (4, 'Brendon', 'Bouchard', 1);INSERT INTO `Author` (`id`, `firstName`, `LastName`, `bookId`) VALUES (5, 'John', 'Doe', 2);

3.代码工程


 实验目标

实现一个基于graphql查询的例子

实现过程

1. 定义Schema,Schema使用GraphQL Schema Definition Language (SDL)来定义

2. 实现Resolver,Resolver函数负责从数据源中获取请求的数据

3. 配置和启动GraphQL服务器 ,要启动GraphQL服务器,你需要安装相应的依赖和配置服务器

pomxml

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">    <parent>        <artifactId>springboot-demo</artifactId>        <groupId>com.et</groupId>        <version>1.0-SNAPSHOT</version>    </parent>    <modelVersion>4.0.0</modelVersion>
<artifactId>GraphQL</artifactId>
<properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> <kotlin.version>1.5.0</kotlin.version> </properties> <dependencies>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.graphql-java-kickstart</groupId> <artifactId>graphql-spring-boot-starter</artifactId> <version>12.0.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency>
<dependency> <groupId>com.graphql-java-kickstart</groupId> <artifactId>graphql-java-tools</artifactId> <version>12.0.0</version> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency>
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>26.0-jre</version> </dependency>
<dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <scope>provided</scope> </dependency> </dependencies></project>


GraphQLQueryResolver

package com.et.graphql.queryresolvers;
import com.et.graphql.model.Author;import com.et.graphql.model.Book;import com.et.graphql.repository.AuthorRepository;import com.et.graphql.repository.BookRepository;import graphql.kickstart.tools.GraphQLQueryResolver;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;

@Componentpublic class BookQuery implements GraphQLQueryResolver{
@Autowired BookRepository bookRepository; @Autowired AuthorRepository authorRepository;
public Iterable<Book> allBook(){ return bookRepository.findAll(); }
public Book getBookByName(String name){ return bookRepository.findBookByName(name); }
public Iterable<Author> allAuthor(){ return authorRepository.findAll(); }
}
package com.et.graphql.queryresolvers;
import com.et.graphql.model.Book;import com.et.graphql.repository.BookRepository;import graphql.kickstart.tools.GraphQLMutationResolver;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;
import java.util.Optional;
@Componentpublic class BookMutation implements GraphQLMutationResolver {
@Autowired BookRepository bookRepository;
public Book newBook(String name, String pageCount){ Book book = new Book(); book.setName(name); book.setPageCount(pageCount); return bookRepository.save(book); }
public Book deleteBook(Integer id){ Book deleteBook = new Book(); Optional<Book> findBook = bookRepository.findById(id); if(findBook.isPresent()){ bookRepository.delete(findBook.get()); deleteBook = findBook.get(); } return deleteBook; }}
package com.et.graphql.queryresolvers;

import com.et.graphql.model.Author;import com.et.graphql.model.Book;import com.et.graphql.repository.AuthorRepository;import graphql.kickstart.tools.GraphQLResolver;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;
@Componentpublic class BookAuthorResolver implements GraphQLResolver<Book> {
@Autowired AuthorRepository authorRepository;
public Author getAuthor(Book book){
return authorRepository.findAuthorByBookId(book.getId()); }}

graphqls(/resources/graphql)

type Book {    id: Int    name: String    pageCount: String    author: Author}
type Query { allBook: [Book] allAuthor:[Author] getBookByName(name: String): Book}
type Mutation { newBook(name: String!, pageCount: String): Book deleteBook(id:Int!):Book}


type Author { id: Int firstName: String lastName: String bookId: Int}

model

package com.et.graphql.model;

import javax.persistence.*;
@Entity@Table(name = "Author", schema = "BOOK_API_DATA")public class Author { @Id @GeneratedValue(strategy = GenerationType.AUTO) Integer id; @Column(name = "firstname") String firstName; @Column(name = "lastname") String lastName; @Column(name = "bookid") Integer bookId;
public Author(Integer id, String firstName, String lastName, Integer bookId) { this.id = id; this.firstName = firstName; this.lastName = lastName; this.bookId = bookId; }
public Author() {
}
public Integer getId() { return id; }
public String getFirstName() { return firstName; }
public String getLastName() { return lastName; }
public void setId(Integer id) { this.id = id; }
public void setFirstName(String firstName) { this.firstName = firstName; }
public void setLastName(String lastName) { this.lastName = lastName; }
public Integer getBookId() { return bookId; }
public void setBookId(Integer bookId) { this.bookId = bookId; }}
package com.et.graphql.model;
import javax.persistence.*;
@Entity@Table(name = "Book", schema = "BOOK_API_DATA")public class Book { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; private String name; @Column(name = "pagecount") private String pageCount;
public Book(Integer id, String name, String pageCount) { this.id = id; this.name = name; this.pageCount = pageCount; }
public Book() {
}
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getPageCount() { return pageCount; }
public void setPageCount(String pageCount) { this.pageCount = pageCount; }}

repository

package com.et.graphql.repository;
import com.et.graphql.model.Author;import org.springframework.data.repository.CrudRepository;
public interface AuthorRepository extends CrudRepository<Author, Integer> {
Author findAuthorByBookId(Integer bookId);}
package com.et.graphql.repository;

import com.et.graphql.model.Book;import org.springframework.data.repository.CrudRepository;
public interface BookRepository extends CrudRepository<Book, Integer> {
Book findBookByName(String name);}

DemoApplication.java

package com.et.graphql;
import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication@ComponentScan(basePackages = "com.et.graphql.queryresolvers")public class BookAPIApplication {
public static void main(String[] args) { SpringApplication.run(BookAPIApplication.class, args); }
}

application.yaml

spring.jpa.hibernate.ddl-auto=nonespring.jpa.database=mysqlspring.jpa.open-in-view=truespring.jpa.show-sql=trueserver.port=8088#logging.level.org.hibernate=DEBUGlogging.level.org.hibernate.SQL=DEBUGspring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImplspring.jpa.hibernate.use-new-id-generator-mappings= false
# book api db"spring.datasource.url=jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=falsespring.datasource.username=rootspring.datasource.password=root

以上只是一些关键代码,所有代码请参见下面代码仓库


代码仓库

  • https://github.com/Harries/springboot-demo

4.测试

启动spring boot应用 打开postman,调用

http://127.0.0.1:8088/graphql 输入

query { allBook{ id name pageCount } }

返回结果

5.引用

  • https://www.cnblogs.com/zcqiand/p/18011513

  • http://www.liuhaihua.cn/archives/710416.html

  • https://graphql.org/


相关推荐

  • 搭建完美写作环境 P7:Markdown 主题美化
  • 【Python】用 Python 处理 Excel 的 14 个常用操作
  • 为Python应用选择最好的Docker镜像
  • 多项式朴素贝叶斯分类器
  • 工作中如何体现一个人的技术深度?
  • 北邮15名研究生23页PDF举报遭导师压榨!校方回应来了:取消研究生导师资格!
  • 音乐界Sora隆重发布!效果炸裂,超越Suno!根据指令生成定制音乐,原创续歌样样行!前谷歌Deepmind人员创建
  • 2023图灵奖得主揭晓!史上首位计算机和数学最高奖“双料王”诞生
  • BAMBOO: 全面评估大型语言模型的长文本处理能力
  • 综述:一文详解 50 多种多模态图像融合方法
  • 2024,Transformer 王者归来!
  • 稀疏算力暴涨591%!Meta推出5nm AI训练芯片,自研AI芯片盛世来了
  • 法国版OpenAI杀疯了!1760亿参数MoE登开源榜首,3张A100显卡可跑,杨立昆转发“逆天”评论
  • 倒计时26天!天玑开发者大会启动报名,AI和游戏开发者的年度盛宴来了
  • 前端开发的利器,使用Whistle提升开发幸福感
  • 2024 年让我想疯狂学习的几个框架。。
  • “洗牌”开始了,很严重,大家提前做好准备吧!
  • JMH + Arthas,性能监控的神器
  • 揭秘数据指标设计的奥妙!
  • 用微前端 qiankun 接入十几个子应用后,我遇到了这些问题