Java GraphQL案例

wen java案例 2

本文目录导读:

Java GraphQL案例

  1. 项目依赖配置 (pom.xml)
  2. 实体类
  3. Repository层
  4. GraphQL Schema定义
  5. GraphQL Resolver实现
  6. 应用启动类
  7. 配置文件
  8. 测试GraphQL API
  9. Web页面访问
  10. 使用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 } }"
}

这个完整的案例展示了:

  1. ✅ GraphQL Schema定义
  2. ✅ 查询和变更操作
  3. ✅ 字段级Resolver
  4. ✅ Spring Boot集成
  5. ✅ JPA数据持久化
  6. ✅ 关系映射
  7. ✅ 完整的CRUD操作

抱歉,评论功能暂时关闭!