本文目录导读:

在Java中实现GraphQL主要有几种主流方案,我来详细介绍最常用的两种方法:
使用 GraphQL Java (官方库)
依赖配置 (Maven)
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-java</artifactId>
<version>21.3</version>
</dependency>
完整案例:图书管理系统
// 1. 数据模型
@Data
@AllArgsConstructor
class Book {
private String id;
private String title;
private String author;
private int pages;
}
@Data
@AllArgsConstructor
class Author {
private String id;
private String name;
private int age;
}
// 2. 数据源 (模拟数据库)
class DataSource {
private static List<Book> books = Arrays.asList(
new Book("1", "Java编程思想", "Bruce Eckel", 880),
new Book("2", "Spring实战", "Craig Walls", 420),
new Book("3", "算法导论", "Thomas Cormen", 1312)
);
private static List<Author> authors = Arrays.asList(
new Author("1", "Bruce Eckel", 65),
new Author("2", "Craig Walls", 50)
);
public static Book getBookById(String id) {
return books.stream()
.filter(b -> b.getId().equals(id))
.findFirst()
.orElse(null);
}
}
// 3. GraphQL Schema 定义和查询执行
public class GraphQLServer {
public static void main(String[] args) throws Exception {
// 定义 Schema (可使用SDL字符串)
String schema = """
type Book {
id: ID!
title: String!
author: String!
pages: Int!
}
type Query {
bookById(id: ID!): Book
books: [Book]
}
""";
// 创建 Schema 对象
SchemaParser schemaParser = new SchemaParser();
TypeDefinitionRegistry typeRegistry = schemaParser.parse(schema);
// 创建 RuntimeWiring
RuntimeWiring wiring = RuntimeWiring.newRuntimeWiring()
.type("Query", builder -> builder
.dataFetcher("bookById", env -> {
String id = env.getArgument("id");
return DataSource.getBookById(id);
})
.dataFetcher("books", env -> DataSource.getBooks())
)
.build();
// 生成可执行的 Schema
SchemaGenerator generator = new SchemaGenerator();
GraphQLSchema graphQLSchema = generator.makeExecutableSchema(typeRegistry, wiring);
// 创建 GraphQL 执行引擎
GraphQL graphQL = GraphQL.newGraphQL(graphQLSchema).build();
// 执行查询
String query = """
query {
bookById(id: "1") {
title
author
pages
}
}
""";
ExecutionInput executionInput = ExecutionInput.newExecutionInput()
.query(query)
.build();
ExecutionResult result = graphQL.execute(executionInput);
System.out.println(result.getData().toString());
}
}
使用 Spring Boot + GraphQL (更常见)
依赖配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-graphql</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Schema 定义 (resources/graphql/schema.graphqls)
type Book {
id: ID! String!
author: String!
pages: Int!
price: Float!
reviews: [Review]
}
type Review {
id: ID!
rating: Int!
comment: String
user: String!
}
type Query {
books(author: String, titleContains: String): [Book]
bookById(id: ID!): Book
reviews(bookId: ID!): [Review]
}
type Mutation {
addBook(title: String!, author: String!, pages: Int!, price: Float!): Book
addReview(bookId: ID!, rating: Int!, comment: String, user: String!): Review
}
模型类
// Book.java
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Book {
private String id;
private String title;
private String author;
private int pages;
private double price;
private List<Review> reviews;
}
// Review.java
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Review {
private String id;
private int rating;
private String comment;
private String user;
}
数据层
// BookRepository.java
@Repository
public class BookRepository {
private final Map<String, Book> books = new ConcurrentHashMap<>();
public BookRepository() {
// 初始化数据
Book book1 = new Book("1", "Java编程思想", "Bruce Eckel", 880, 79.0, new ArrayList<>());
Book book2 = new Book("2", "Spring实战", "Craig Walls", 420, 59.0, new ArrayList<>());
books.put("1", book1);
books.put("2", book2);
}
public List<Book> findAll() {
return new ArrayList<>(books.values());
}
public Book findById(String id) {
return books.get(id);
}
public Book save(Book book) {
String id = String.valueOf(books.size() + 1);
book.setId(id);
books.put(id, book);
return book;
}
public List<Book> findByAuthor(String author) {
return books.values().stream()
.filter(b -> b.getAuthor().equalsIgnoreCase(author))
.collect(Collectors.toList());
}
}
// ReviewRepository.java
@Repository
public class ReviewRepository {
private final Map<String, List<Review>> reviews = new ConcurrentHashMap<>();
public ReviewRepository() {
// 初始化评论数据
reviews.put("1", Arrays.asList(
new Review("1", 5, "经典著作", "张三"),
new Review("2", 4, "内容深入", "李四")
));
}
public List<Review> findByBookId(String bookId) {
return reviews.getOrDefault(bookId, new ArrayList<>());
}
public Review save(String bookId, Review review) {
String id = UUID.randomUUID().toString();
review.setId(id);
reviews.computeIfAbsent(bookId, k -> new ArrayList<>()).add(review);
return review;
}
}
GraphQL 控制器
// BookController.java
@Controller
public class BookController {
@Autowired
private BookRepository bookRepository;
@Autowired
private ReviewRepository reviewRepository;
@QueryMapping
public List<Book> books(@Argument String author, @Argument String titleContains) {
if (author != null) {
return bookRepository.findByAuthor(author);
}
if (titleContains != null) {
return bookRepository.findAll().stream()
.filter(b -> b.getTitle().toLowerCase().contains(titleContains.toLowerCase()))
.collect(Collectors.toList());
}
return bookRepository.findAll();
}
@QueryMapping
public Book bookById(@Argument String id) {
return bookRepository.findById(id);
}
@QueryMapping
public List<Review> reviews(@Argument String bookId) {
return reviewRepository.findByBookId(bookId);
}
@MutationMapping
public Book addBook(@Argument String title, @Argument String author,
@Argument int pages, @Argument double price) {
Book book = new Book(null, title, author, pages, price, new ArrayList<>());
return bookRepository.save(book);
}
@MutationMapping
public Review addReview(@Argument String bookId, @Argument int rating,
@Argument String comment, @Argument String user) {
Review review = new Review(null, rating, comment, user);
return reviewRepository.save(bookId, review);
}
// 为Book类型添加reviews的关联查询
@SchemaMapping(typeName = "Book", field = "reviews")
public List<Review> getReviews(Book book) {
return reviewRepository.findByBookId(book.getId());
}
}
应用配置 (application.yml)
spring:
graphql:
graphiql:
enabled: true # 开启GraphiQL测试界面
schema:
locations: classpath:graphql/
测试查询示例
访问 http://localhost:8080/graphiql 打开GraphiQL界面,可以执行以下查询:
# 查询所有书籍
query {
books {
id author
pages
price
}
}
# 带参数的查询
query {
bookById(id: "1") { author
reviews {
rating
comment
user
}
}
}
# 新增书籍
mutation {
addBook(title: "Python编程", author: "Guido", pages: 500, price: 69.0) {
id }
}
# 新增评论
mutation {
addReview(bookId: "1", rating: 5, comment: "非常好的一本书", user: "王五") {
id
rating
}
}
主要优势
- 精确的数据获取:客户端只需要请求需要的数据
- 单一端点:所有接口都通过
/graphql端点访问 - 强类型系统:Schema定义明确了数据类型和关系
- 版本控制友好:通过Schema演进,不需要版本号
最佳实践
- N+1查询问题:使用DataLoader解决
- 安全性:实现深度限制、查询复杂度分析
- 缓存策略:合理使用HTTP缓存和持久化缓存
- 错误处理:统一的错误格式和异常处理
这个案例展示了Java实现GraphQL的基本方式,可以根据实际需求进行扩展和优化。