本文目录导读:

- 项目依赖配置 (pom.xml)
- 实体类
- Repository层
- GraphQL Schema定义
- GraphQL Resolver实现
- 应用启动类
- 配置文件
- 测试GraphQL API
- Web页面访问
- 使用Postman测试
我将为您提供一个完整的Java GraphQL案例,包括基础配置、数据模型、查询和变更操作。
项目依赖配置 (pom.xml)
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>graphql-demo</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.14</version>
<relativePath/>
</parent>
<properties>
<java.version>11</java.version>
<graphql-java.version>20.1</graphql-java.version>
</properties>
<dependencies>
<!-- GraphQL Java -->
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-java</artifactId>
<version>${graphql-java.version}</version>
</dependency>
<!-- GraphQL Spring Boot Starter -->
<dependency>
<groupId>com.graphql-java-kickstart</groupId>
<artifactId>graphql-spring-boot-starter</artifactId>
<version>13.0.0</version>
</dependency>
<!-- Spring Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Data JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- H2 Database -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
实体类
用户实体 (User.java)
package com.example.graphql.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "users")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String username;
@Column(nullable = false)
private String email;
private String fullName;
private Integer age;
private String city;
@OneToMany(mappedBy = "author", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Post> posts = new ArrayList<>();
@Column(name = "created_at")
private LocalDateTime createdAt;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
updatedAt = LocalDateTime.now();
}
@PreUpdate
protected void onUpdate() {
updatedAt = LocalDateTime.now();
}
}
帖子实体 (Post.java)
package com.example.graphql.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.time.LocalDateTime;
@Entity
@Table(name = "posts")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String title;
@Column(columnDefinition = "TEXT")
private String content;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "author_id", nullable = false)
private User author;
private Integer likes = 0;
@Column(name = "created_at")
private LocalDateTime createdAt;
@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
}
}
评论实体 (Comment.java)
package com.example.graphql.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.time.LocalDateTime;
@Entity
@Table(name = "comments")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, columnDefinition = "TEXT")
private String content;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "post_id", nullable = false)
private Post post;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;
@Column(name = "created_at")
private LocalDateTime createdAt;
@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
}
}
Repository层
UserRepository.java
package com.example.graphql.repository;
import com.example.graphql.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByAgeGreaterThanEqual(int age);
List<User> findByCityIn(List<String> cities);
List<User> findByUsernameContaining(String keyword);
}
PostRepository.java
package com.example.graphql.repository;
import com.example.graphql.entity.Post;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface PostRepository extends JpaRepository<Post, Long> {
List<Post> findPostByAuthorId(Long authorId);
List<Post> findTop10ByOrderByLikesDesc();
}
CommentRepository.java
package com.example.graphql.repository;
import com.example.graphql.entity.Comment;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface CommentRepository extends JpaRepository<Comment, Long> {
List<Comment> findByPostId(Long postId);
List<Comment> findByUserId(Long userId);
}
GraphQL Schema定义
schema.graphqls
type Query {
# 用户查询
getAllUsers: [User]
getUserById(id: ID!): User
getUsersByAge(age: Int!): [User]
getUsersByCity(cities: [String!]!): [User]
searchUsers(keyword: String!): [User]
# 帖子查询
getAllPosts: [Post]
getPostById(id: ID!): Post
getPostsByAuthor(authorId: ID!): [Post]
getTopPosts(limit: Int = 10): [Post]
# 评论查询
getCommentsByPost(postId: ID!): [Comment]
}
type Mutation {
# 用户操作
createUser(input: UserInput!): User
updateUser(id: ID!, input: UserUpdateInput!): User
deleteUser(id: ID!): Boolean
# 帖子操作
createPost(input: PostInput!): Post
updatePost(id: ID!, input: PostUpdateInput!): Post
deletePost(id: ID!): Boolean
# 评论操作
addComment(input: CommentInput!): Comment
deleteComment(id: ID!): Boolean
}
type User {
id: ID!
username: String!
email: String!
fullName: String
age: Int
city: String
posts: [Post]
createdAt: String
updatedAt: String
}
type Post {
id: ID! String!
content: String
author: User
likes: Int
comments: [Comment]
createdAt: String
}
type Comment {
id: ID!
content: String!
post: Post
user: User
createdAt: String
}
input UserInput {
username: String!
email: String!
fullName: String
age: Int
city: String
}
input UserUpdateInput {
username: String
email: String
fullName: String
age: Int
city: String
}
input PostInput { String!
content: String!
authorId: ID!
}
input PostUpdateInput { String
content: String
}
input CommentInput {
content: String!
postId: ID!
userId: ID!
}
GraphQL Resolver实现
QueryResolver.java
package com.example.graphql.resolver;
import com.example.graphql.entity.Post;
import com.example.graphql.entity.User;
import com.example.graphql.repository.PostRepository;
import com.example.graphql.repository.UserRepository;
import graphql.kickstart.tools.GraphQLQueryResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class QueryResolver implements GraphQLQueryResolver {
@Autowired
private UserRepository userRepository;
@Autowired
private PostRepository postRepository;
// User queries
public List<User> getAllUsers() {
return userRepository.findAll();
}
public User getUserById(Long id) {
return userRepository.findById(id).orElse(null);
}
public List<User> getUsersByAge(int age) {
return userRepository.findByAgeGreaterThanEqual(age);
}
public List<User> getUsersByCity(List<String> cities) {
return userRepository.findByCityIn(cities);
}
public List<User> searchUsers(String keyword) {
return userRepository.findByUsernameContaining(keyword);
}
// Post queries
public List<Post> getAllPosts() {
return postRepository.findAll();
}
public Post getPostById(Long id) {
return postRepository.findById(id).orElse(null);
}
public List<Post> getPostsByAuthor(Long authorId) {
return postRepository.findPostByAuthorId(authorId);
}
public List<Post> getTopPosts(int limit) {
return postRepository.findTop10ByOrderByLikesDesc();
}
}
MutationResolver.java
package com.example.graphql.resolver;
import com.example.graphql.entity.Comment;
import com.example.graphql.entity.Post;
import com.example.graphql.entity.User;
import com.example.graphql.repository.CommentRepository;
import com.example.graphql.repository.PostRepository;
import com.example.graphql.repository.UserRepository;
import graphql.kickstart.tools.GraphQLMutationResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Component
public class MutationResolver implements GraphQLMutationResolver {
@Autowired
private UserRepository userRepository;
@Autowired
private PostRepository postRepository;
@Autowired
private CommentRepository commentRepository;
// User mutations
@Transactional
public User createUser(String username, String email, String fullName, Integer age, String city) {
User user = new User();
user.setUsername(username);
user.setEmail(email);
user.setFullName(fullName);
user.setAge(age);
user.setCity(city);
return userRepository.save(user);
}
@Transactional
public User updateUser(Long id, String username, String email, String fullName, Integer age, String city) {
User user = userRepository.findById(id)
.orElseThrow(() -> new RuntimeException("User not found"));
if (username != null) user.setUsername(username);
if (email != null) user.setEmail(email);
if (fullName != null) user.setFullName(fullName);
if (age != null) user.setAge(age);
if (city != null) user.setCity(city);
return userRepository.save(user);
}
@Transactional
public Boolean deleteUser(Long id) {
try {
userRepository.deleteById(id);
return true;
} catch (Exception e) {
return false;
}
}
// Post mutations
@Transactional
public Post createPost(String title, String content, Long authorId) {
User author = userRepository.findById(authorId)
.orElseThrow(() -> new RuntimeException("Author not found"));
Post post = new Post();
post.setTitle(title);
post.setContent(content);
post.setAuthor(author);
return postRepository.save(post);
}
@Transactional
public Post updatePost(Long id, String title, String content) {
Post post = postRepository.findById(id)
.orElseThrow(() -> new RuntimeException("Post not found"));
if (title != null) post.setTitle(title);
if (content != null) post.setContent(content);
return postRepository.save(post);
}
@Transactional
public Boolean deletePost(Long id) {
try {
postRepository.deleteById(id);
return true;
} catch (Exception e) {
return false;
}
}
// Comment mutations
@Transactional
public Comment addComment(String content, Long postId, Long userId) {
Post post = postRepository.findById(postId)
.orElseThrow(() -> new RuntimeException("Post not found"));
User user = userRepository.findById(userId)
.orElseThrow(() -> new RuntimeException("User not found"));
Comment comment = new Comment();
comment.setContent(content);
comment.setPost(post);
comment.setUser(user);
return commentRepository.save(comment);
}
@Transactional
public Boolean deleteComment(Long id) {
try {
commentRepository.deleteById(id);
return true;
} catch (Exception e) {
return false;
}
}
}
字段级Resolver (FieldResolver.java)
package com.example.graphql.resolver;
import com.example.graphql.entity.Comment;
import com.example.graphql.entity.Post;
import com.example.graphql.entity.User;
import com.example.graphql.repository.CommentRepository;
import com.example.graphql.repository.PostRepository;
import graphql.kickstart.tools.GraphQLResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class FieldResolver implements GraphQLResolver<User> {
@Autowired
private PostRepository postRepository;
// 为User类型提供posts字段解析
public List<Post> posts(User user) {
return postRepository.findPostByAuthorId(user.getId());
}
}
@Component
class PostFieldResolver implements GraphQLResolver<Post> {
@Autowired
private CommentRepository commentRepository;
// 为Post类型提供comments字段解析
public List<Comment> comments(Post post) {
return commentRepository.findByPostId(post.getId());
}
}
应用启动类
GraphqlDemoApplication.java
package com.example.graphql;
import com.example.graphql.entity.Post;
import com.example.graphql.entity.User;
import com.example.graphql.repository.PostRepository;
import com.example.graphql.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class GraphqlDemoApplication {
public static void main(String[] args) {
SpringApplication.run(GraphqlDemoApplication.class, args);
}
@Bean
CommandLineRunner initDatabase(UserRepository userRepository, PostRepository postRepository) {
return args -> {
// 示例数据
User user1 = new User();
user1.setUsername("john_doe");
user1.setEmail("john@example.com");
user1.setFullName("John Doe");
user1.setAge(30);
user1.setCity("New York");
userRepository.save(user1);
User user2 = new User();
user2.setUsername("jane_smith");
user2.setEmail("jane@example.com");
user2.setFullName("Jane Smith");
user2.setAge(25);
user2.setCity("Los Angeles");
userRepository.save(user2);
// 创建帖子
Post post1 = new Post();
post1.setTitle("Hello GraphQL!");
post1.setContent("This is my first GraphQL post.");
post1.setAuthor(user1);
postRepository.save(post1);
Post post2 = new Post();
post2.setTitle("Getting Started with GraphQL Java");
post2.setContent("GraphQL Java is a powerful tool for building APIs.");
post2.setAuthor(user2);
postRepository.save(post2);
};
}
}
配置文件
application.yml
spring:
datasource:
url: jdbc:h2:mem:graphqldb
driver-class-name: org.h2.Driver
username: sa
password:
h2:
console:
enabled: true
jpa:
hibernate:
ddl-auto: create-drop
show-sql: true
properties:
hibernate:
format_sql: true
graphql:
servlet:
mapping: /graphql
enabled: true
cors-enabled: true
tools:
schema-location-pattern: "**/*.graphqls"
server:
port: 8080
测试GraphQL API
查询所有用户
query {
getAllUsers {
id
username
email
fullName
age
city
posts {
id
title
}
}
}
创建新用户
mutation {
createUser(
username: "alice",
email: "alice@example.com",
fullName: "Alice Johnson",
age: 28,
city: "Chicago"
) {
id
username
email
createdAt
}
}
查询特定用户的帖子
query {
getUserById(id: 1) {
id
username
posts {
id
title
content
}
}
}
添加评论
mutation {
addComment(
content: "Great post!",
postId: 1,
userId: 2
) {
id
content
createdAt
user {
username
}
}
}
Web页面访问
启动应用后,可以访问以下地址:
- GraphQL Playground: http://localhost:8080/playground
- GraphQL API: http://localhost:8080/graphql
- H2 Console: http://localhost:8080/h2-console
使用Postman测试
在Postman中发送POST请求到 http://localhost:8080/graphql,请求体格式:
{
"query": "query { getAllUsers { id username email } }"
}
这个完整的案例展示了:
- ✅ GraphQL Schema定义
- ✅ 查询和变更操作
- ✅ 字段级Resolver
- ✅ Spring Boot集成
- ✅ JPA数据持久化
- ✅ 关系映射
- ✅ 完整的CRUD操作