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=InnoDB
AUTO_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;




@Component
public 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;


@Component
public 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;


@Component
public 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=none
spring.jpa.database=mysql
spring.jpa.open-in-view=true
spring.jpa.show-sql=true
server.port=8088
#logging.level.org.hibernate=DEBUG
logging.level.org.hibernate.SQL=DEBUG
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring.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=false
spring.datasource.username=root
spring.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
 }
 }

返回结果4e17233ae985cef2ace7a76ad62597a6.png

5.引用

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

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

  • https://graphql.org/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/539419.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

贫穷的本质

李永乐 李永乐一个老师 李永乐&#xff0c;男&#xff0c;汉族&#xff0c;1983年出生于吉林省吉林市 [1]&#xff0c;高中数学、物理老师&#xff0c;北京大学物理与经济双学士 [5]&#xff0c;清华大学电子工程系 [5]硕士研究生。 他的解读逻辑比较清晰&#xff0c;更像是用数…

Redis从入门到精通(十五)Redis分布式缓存(三)Redis分片集群的搭建和原理分析

文章目录 前言5.4 分片集群5.4.1 搭建分片集群5.4.2 散列插槽5.4.3 集群伸缩5.4.3.1 需求分析5.4.3.2 创建新的Redis实例5.4.3.3 添加新节点到Redis集群5.4.3.4 转移插槽 5.4.4 故障转移5.4.4.1 自动故障转移5.4.4.2 手动故障转移 5.4.5 RedisTemplate 5.5 小结 前言 Redis分布…

webpack-loader的使用

引入css后执行打包命令 "build": "npx webpack --config wk.config.js"发现报错&#xff1a; webpack默认只能处理js其他的像css,图片都需要借助loader来处理 css-loader loader可以用于对模块的源代码进行转换&#xff0c;可以把css看成一个模块&…

项目管理工具——使用甘特图制定项目计划的详细步骤

甘特图是一种直观的项目管理工具&#xff0c;它有助于我们清晰地展示任务安排、时间管理和项目的进度。以下是使用甘特图制定项目计划的详细步骤&#xff1a; 1、创建项目&#xff1a;首先&#xff0c;在进度猫中创建新的项目&#xff0c;并设置项目的时间、工作日等参数。根据…

Day37|贪心算法part06:738.单调递增的数字、968. 监控二叉树、贪心总结

738. 单调递增的数字 总体思想就是从后往前遍历&#xff0c;比较第i位和第i1位的大小&#xff0c;不符合顺序char[i]减1&#xff0c;i1位填9&#xff0c;找到需要填9的最先位置&#xff0c;然后填9。 class Solution {public int monotoneIncreasingDigits(int n) {String s …

请求分发场景下的鉴权问题

说明&#xff1a;记录一次对请求分发&#xff0c;无法登录系统的问题。 场景 如下&#xff0c;在此结构下&#xff0c;如何判断该用户是已登录的用户&#xff1b; 常规操作&#xff0c;用户登录后给用户发Token&#xff0c;同时将发放的Token存入到Redis中。要求用户后续请求…

halcon domain和region总结

1.domain是什么 在halcon中&#xff0c;ROI(Region Of Interest)被称为图像的域(domain)&#xff08;参考《solution_guide_i.pdf》&#xff09;。这个术语来自数学中的定义域&#xff0c;而图像就是函数&#xff0c;本函数负责将坐标映射到像素值&#xff0c;即f(x) gray这样…

计算机网络——TCP和UDP协议

目录 前言 前篇 引言 TCP与UDP之间的区别 TCP 三次握手 为什么要三次握手而不是两次握手&#xff1f; 丢包问题与乱序问题的解决 四次挥手 为什么客户端需要等待超时时间&#xff1f; UDP协议 TCP和UDP的主要区别 前言 本博客是博主用于复习计算机网络的博客&…

性能测试-数据库优化二(SQL的优化、数据库拆表、分表分区,读写分离、redis)

数据库优化 explain select 重点&#xff1a; type类型&#xff0c;rows行数&#xff0c;extra SQL的优化 在写on语句时&#xff0c;将数据量小的表放左边&#xff0c;大表写右边where后面的条件尽可能用索引字段&#xff0c;复合索引时&#xff0c;最好按复合索引顺序写wh…

NGO-VMD+皮尔逊系数+小波阈值降噪+重构

NGO-VMD皮尔逊系数小波阈值降噪重构 NGO-VMD皮尔逊系数小波阈值降噪重构代码获取戳此处代码获取戳此处 以西储大学轴承数据为例&#xff0c;进行VMD&#xff0c;且采用NGO进行K a参数寻优 并对分解分量计算皮尔逊相关系数筛选含噪声分量&#xff0c;对其进行小波软硬阈值降噪&a…

网络协议——OSPF(开放式最短路径优先)详解

1.什么是OSPF 开放式最短路径优先OSPF 是一种动态的高度可靠和高度可扩展的路由协议&#xff0c;用于构建大型网络中的动态路由系统 2. OSPF的协议号为&#xff1a;89 3. OSPF的特点: OSPF是链路状态协议使用了区域概念&#xff1a;减少路由选择协议对路由器CPU&#xff0c;…

电磁兼容导论翻译疑问

在读电磁兼容导论P71页时&#xff0c;发现在“注意“这句话翻译的和原文有疑问&#xff1a;我的理解是单边幅度谱是双边幅度谱的两倍。请大家帮忙看看应如何翻译。 英文原版&#xff1a;Note that all positive frequency components except the dc component in the two-side…

【计算机毕业设计】基于微信小程序的开发项目150套(附源码+演示视频+LW)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f9e1;今天给大家分享200的微信小程序毕业设计&#xff0c;后台用Java开发&#xff0c;这些项目都经过精心挑选&#xff0c;涵盖了不同的实战主题和用例&#xff0c;可做毕业设…

解决mac本git安装后找不到命令的问题

不熟悉mac配置&#xff0c;折腾了半天&#xff0c;记录一下。 1.问题描述2.解决方法 1.问题描述 从https://sourceforge.net/projects/git-osx-installer/files/下载的git安装包&#xff1a; 安装时提示&#xff1a; 这里的解决办法是按住control键再打开文件安装。 安装完…

Linux内核之互斥锁mutex_init和自旋锁spin_lock区别及用法实例(四十六)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

股权融资成本GLS模型计算

一、模型公式 式中&#xff1a; r 为股权融资成本 P为股价 B为每股净资产 FROE为预测每股净资产收益率 目标&#xff1a;求解股权融资成本r 二、模型口径参考来源 PS&#xff1a;实际以代码为准 ①FROE&#xff08;预测每股净资产收益率&#xff09;: 资本市场开放与…

物联网实战--驱动篇之(五)TEA和AES加密算法

目录 一、前言 二、TEA算法 三、AES算法 四、加解密测试 五、安全性保障 一、前言 物联网的安全性是经常被提及的一个点&#xff0c;如果你的设备之间通讯没有加密的话&#xff0c;那么攻击者很容易就能获取并解析出报文的协议&#xff0c;从而根据攻击者的需要进行设备操…

c# refc# substring c# 反射c# split c# websocket c# datatable使用

在C#编程中&#xff0c;ref关键字、Substring方法、反射&#xff08;Reflection&#xff09;、Split方法、WebSocket通信以及DataTable的使用都是常见的技术和方法。下面我将逐一为您详解这些内容。 1. C# ref关键字 ref关键字在C#中用于按引用传递参数。这意味着当您将变量作…

当你的项目体积比较大?你如何做性能优化

在前端开发中&#xff0c;项目体积优化是一个重要的环节&#xff0c;它直接影响到网页的加载速度和用户体验。随着前端项目越来越复杂&#xff0c;引入的依赖也越来越多&#xff0c;如何有效地减少最终打包文件的大小&#xff0c;成为了前端工程师需要面对的挑战。以下是一些常…

vim卡死了,没有反应怎么办?

解决办法&#xff1a; 很有可能是你有个在window下的好习惯&#xff0c;没事儿就ctrl s保存文件。但是在vim里&#xff0c;ctrl s默认是发送一种流控制信号&#xff0c;通常用于停止终端的输出&#xff0c;所以你的屏幕就卡死了。 解决办法也很简单&#xff0c;按下ctrl q即…