随着现代应用程序的复杂性不断提高,构建可扩展的api和查询系统变得越来越重要。在过去,rest api和soap都是主流的api构建方案,但现在graphql也成为了受欢迎的选项。本文将介绍如何使用spring boot和graphql构建api和查询系统。
什么是GraphQL?
GraphQL是一种用于API和查询系统的查询语言。与传统的REST API相比,GraphQL有以下优势:
- 灵活性:GraphQL允许客户端指定需要的数据,因此可以避免不必要的数据传输。
- 可扩展性:GraphQL为客户端和服务器提供了高度的灵活性,因此可以轻松地添加新的字段或操作。
- 性能:由于GraphQL允许客户端指定所需的数据,因此可以避免过度拉取数据。
Spring Boot和GraphQL
Spring Boot是一个Java框架,用于构建基于Java的Web应用程序。它提供了许多有用的功能,例如自动配置和快速开发。与传统的Java Web开发相比,Spring Boot可以使开发过程变得更加愉快和高效。
在本文中,我们将使用Spring Boot和GraphQL来构建一个基本的API和查询系统。在开始之前,您需要了解以下几个组件:
- Spring Boot:用于构建基于Java的Web应用程序。
- GraphQL Java:Java的GraphQL实现。
- Spring Boot Starter Data JPA:用于将Spring Boot和Java Persistence API(JPA)集成在一起。
- H2数据库:用于本地开发和测试的内存数据库。
构建API和查询系统
首先,我们需要创建一个Spring Boot应用程序。您可以使用Spring Initializr来快速创建一个Spring Boot应用程序。以下是创建一个Spring Boot应用程序的步骤:
- 打开Spring Initializr网站。
- 选择您的Spring Boot版本。
- 可以选择您喜欢的构建工具,例如Maven或Gradle。
- 添加所需的依赖项。在本文中,我们需要“Spring Web”,“GraphQL Java Tools”,“GraphQL Java Spring Boot Starter”,“Spring Boot Starter Data JPA”和“H2 Database”。
- 单击“生成”按钮,将下载基本的Spring Boot应用程序结构。
创建GraphQL Schema
在创建GraphQL Schema之前,让我们考虑一下我们的API需要执行哪些操作。我们将创建一个具有三个类型的API:作者,书籍和作者-书籍关系。以下是我们的API操作:
- 获取作者列表:返回作者列表。
- 按ID获取作者:按作者ID返回作者详细信息。
- 获取书籍列表:返回书籍列表。
- 按ID获取书籍:按书籍ID返回书籍详细信息。
- 获取作者-书籍关系列表:返回作者-书籍关系列表。
- 按作者ID获取关联书籍:按作者ID返回该作者的所有书籍详细信息。
下一步是创建GraphQL Schema。Schema定义了可以在API上执行的操作。在本文中,我们将使用GraphQL Java Tools来创建Schema。创建GraphQL Schema的步骤如下:
- 在src/main/resources文件夹中创建一个名为“schema.graphqls”文件,并添加以下代码:
type Author {
id: ID!
name: String!
}
type Book {
id: ID!
title: String!
author: Author!
}
type Relationship {
id: ID!
author: Author!
book: Book!
}
type Query {
authors: [Author]
author(id: ID!): Author
books: [Book]
book(id: ID!): Book
relationships: [Relationship]
booksByAuthor(authorId: ID!): [Book]
}这个Schema定义了三个类型:作者,书籍和关系。它还定义了六个操作:获取作者列表,按ID获取作者,获取书籍列表,按ID获取书籍,获取关系列表和按作者ID获取关联书籍。
- 在项目中创建GraphQL服务并将schema.graphqls文件加载到该服务中。在src/main/java/com.example.demo文件夹中创建一个名为“GraphQLProvider”的新类,其中包含以下代码:
package com.example.demo;
import com.example.demo.entity.*;
import com.example.demo.repository.*;
import com.example.demo.resolver.*;
import java.util.List;
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import graphql.schema.DataFetcher;
import graphql.schema.DataFetchingEnvironment;
import graphql.schema.GraphQLSchema;
import graphql.schema.idl.RuntimeWiring;
import graphql.schema.idl.SchemaGenerator;
import graphql.schema.idl.SchemaParser;
import graphql.schema.idl.TypeRuntimeWiring;
import graphql.servlet.GraphQLServlet;
import graphql.servlet.SimpleGraphQLHttpServlet;
@Configuration
public class GraphQLProvider {
private static final Logger LOGGER = LoggerFactory.getLogger(GraphQLProvider.class);
private final AuthorRepository authorRepository;
private final BookRepository bookRepository;
private final RelationshipRepository relationshipRepository;
private List fetchDataers;
@Autowired
public GraphQLProvider(
AuthorRepository authorRepository,
BookRepository bookRepository,
RelationshipRepository relationshipRepository,
List fetchDataers
) {
this.authorRepository = authorRepository;
this.bookRepository = bookRepository;
this.relationshipRepository = relationshipRepository;
this.fetchDataers = fetchDataers;
}
@PostConstruct
public void setup() {
fetchDataers.add(new DataFetcher() {
@Override
public Object get(DataFetchingEnvironment environment) {
return authorRepository.findAll();
}
});
fetchDataers.add(new DataFetcher() {
@Override
public Object get(DataFetchingEnvironment environment) {
return authorRepository.findById(environment.getArgument("id")).get();
}
});
fetchDataers.add(new DataFetcher() {
@Override
public Object get(DataFetchingEnvironment environment) {
return bookRepository.findAll();
}
});
fetchDataers.add(new DataFetcher() {
@Override
public Object get(DataFetchingEnvironment environment) {
return bookRepository.findById(environment.getArgument("id")).get();
}
});
fetchDataers.add(new DataFetcher() {
@Override
public Object get(DataFetchingEnvironment environment) {
return relationshipRepository.findAll();
}
});
fetchDataers.add(new DataFetcher() {
@Override
public Object get(DataFetchingEnvironment environment) {
return bookRepository.findByAuthor_Id(environment.getArgument("authorId"));
}
});
}
@Bean
public GraphQLSchema schema() {
SchemaParser schemaParser = new SchemaParser();
SchemaGenerator schemaGenerator = new SchemaGenerator();
TypeRuntimeWiring.Builder authorWiring = newTypeWiring("Author").dataFetchers(fetchDataers);
return schemaGenerator.makeExecutableSchema(schemaParser.parse(getClass().getResource("/schema.graphqls").getPath()), RuntimeWiring.newRuntimeWiring()
.type(authorWiring)
.build());
}
@Bean
public GraphQLServlet graphQLServlet() {
return new SimpleGraphQLHttpServlet(new GraphQL.Builder(schema()).build());
}
} 该类创建一个GraphQL服务,将schema.graphqls文件加载到该服务中,并定义了Data Fetchers。Data Fetchers负责获取数据并填充GraphQL操作的结果。
创建JPA实体和存储库
现在,我们需要创建实体并将它们映射到数据库中。在本文中,我们将创建Author,Book和Relationship实体,并使用JPA将其映射到H2数据库。
- 在src/main/java/com.example.demo.repository 包中创建名为“AuthorRepository”的新接口,其中包含以下代码:
package com.example.demo.repository; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; import com.example.demo.entity.Author; @Repository public interface AuthorRepository extends JpaRepository{ }
- 按照上述方法,创建BookRepository和RelationshipRepository。
- 在src/main/java/com.example.demo.entity包中创建实体和关系。以下是作者实体的示例代码:
package com.example.demo.entity;
import lombok.Data;
import javax.persistence.*;
@Data
@Entity
public class Author {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
protected Author() {}
public Author(String name) {
this.name = name;
}
}在上面的示例中,我们使用Lombok的@Data注释的“id”和“name”字段创建了一个名为Author的Java实体。
- 输入书籍和关系。
填充数据
seo特别版程序介绍:注意:普通用户建议使用淄博分类信息港程序普通版本。主要针对seo需要增加了自定义功能:自定义文件路径;自定义文件名;自定义关键字。这些功能的作用,只有自己体会了。以下是淄博分类信息港程序的介绍:淄博分类信息港程序一套现成的城市分类信息网站发布系统。发布管理房屋、人才、招租、招聘、求购、求租、搬迁、运输、二手交易、招生培训、婚介交友等各类信息的发布和查询。淄博分类信息港发布程序
我们现在可以使用H2控制台或编写Java代码来填充数据。
使用H2控制台填充数据:
- 在src/main/resources文件夹中创建一个名为“data.sql”的文件,并添加以下代码:
INSERT INTO author (id, name) VALUES (1, 'William Shakespeare'); INSERT INTO author (id, name) VALUES (2, 'John Milton'); INSERT INTO author (id, name) VALUES (3, 'Charles Dickens'); INSERT INTO book (id, title, author_id) VALUES (1, 'Hamlet', 1); INSERT INTO book (id, title, author_id) VALUES (2, 'Paradise Lost', 2); INSERT INTO book (id, title, author_id) VALUES (3, 'Oliver Twist', 3); INSERT INTO relationship (id, author_id, book_id) VALUES (1, 1, 1); INSERT INTO relationship (id, author_id, book_id) VALUES (2, 2, 2); INSERT INTO relationship (id, author_id, book_id) VALUES (3, 3, 3);
- 启动应用程序并访问http://localhost:8080/h2-console。
- 在H2控制台中,更改JDBC URL为jdbc:h2:mem:testdb并单击Connect按钮。
- 执行data.sql文件中的查询以填充数据。
使用Java代码填充数据:
- 在src/main/java/com.example.demo.seed包中创建一个新类并命名为“DataSeed”,其中包含以下代码:
package com.example.demo.seed;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import com.example.demo.entity.Author;
import com.example.demo.entity.Book;
import com.example.demo.entity.Relationship;
import com.example.demo.repository.AuthorRepository;
import com.example.demo.repository.BookRepository;
import com.example.demo.repository.RelationshipRepository;
@Component
public class DataSeed implements CommandLineRunner {
private AuthorRepository authorRepository;
private BookRepository bookRepository;
private RelationshipRepository relationshipRepository;
public DataSeed(AuthorRepository authorRepository,
BookRepository bookRepository,
RelationshipRepository relationshipRepository) {
this.authorRepository = authorRepository;
this.bookRepository = bookRepository;
this.relationshipRepository = relationshipRepository;
}
@Override
public void run(String... args) throws Exception {
Author shakespeare = new Author("William Shakespeare");
Author milton = new Author("John Milton");
Author dickens = new Author("Charles Dickens");
authorRepository.save(shakespeare);
authorRepository.save(milton);
authorRepository.save(dickens);
Book hamlet = new Book("Hamlet", shakespeare);
Book paradiseLost = new Book("Paradise Lost", milton);
Book oliverTwist = new Book("Oliver Twist", dickens);
bookRepository.save(hamlet);
bookRepository.save(paradiseLost);
bookRepository.save(oliverTwist);
relationshipRepository.save(new Relationship(shakespeare, hamlet));
relationshipRepository.save(new Relationship(milton, paradiseLost));
relationshipRepository.save(new Relationship(dickens, oliverTwist));
}
}在上面的示例中,我们创建了一个CommandLineRunner工具类,它在应用程序启动时添加示例数据到数据库中。
测试GraphQL API
我们现在可以使用GraphQL Playground工具查询GraphQL API。
以下是一些示例查询:
获取作者列表:
query {
authors {
id
name
}
}按ID获取作者:
query {
author(id: 1) {
id
name
}
}获取书籍列表:
query {
books {
id
title
author {
id
name
}
}
}按ID获取书籍:
query {
book(id: 1) {
id
title
author {
id
name
}
}
}获取作者-书籍关系列表:
query {
relationships {
id
author {
id
name
}
book {
id
title
}
}
}按作者ID获取关联书籍:
query {
booksByAuthor(authorId: 1) {
id
title
author {
id
name
}
}
}结论
本文介绍了如何使用Spring Boot和GraphQL构建API和查询系统,并执行基本的操作。可以使用GraphQL Java Tools和JPA轻松定义Schema和映射实体。GraphQL的灵活性和可扩展性使得它成为构建现代Web应用程序的理想选择。









