spring-boot 中使用graphql的正確姿勢


在spring-boot中使用graphql

參照graphql-java-kick-to-start

首先構建spring-boot項目,pom.xml文件中加入

<dependency>
  <groupId>com.graphql-java-kickstart</groupId>
  <artifactId>graphql-java-tools</artifactId>
  <version>5.4.0</version>
</dependency>
<!-- graphql -->
<dependency>
   <groupId>com.graphql-java</groupId>
   <artifactId>graphql-spring-boot-starter</artifactId>
   <version>5.0.2</version>
</dependency>
<!-- 這個是graphiql,跟上面的不一樣 -->
 <dependency>
    <groupId>com.graphql-java</groupId>
    <artifactId>graphiql-spring-boot-starter</artifactId>
    <version>5.0.2</version>
</dependency>

接着定義graphql的schema,在resources目錄下任意位置的*.graphqls文件都會被掃描到,作為graphql 的schema。

這里在resources下先建一個文件夾/graphql,建立schema文件

  • schema.graphqls
type Query {
    user(nickname: String): User
    users: [User]
    article(title: String!): Article
}
type Mutation {
    addUser(mail: String!, nickname: String!, password: String!): User
    addArticle(title: String!, content: String!, authorId: String!): Article
}
type User {
    id: String!
    mail: String!
    nickname: String!
    password: String!
    description: String
}

type Article {
    id: String!
    author: User!
    title: String!
    content: String!
    createBy: String
    thumbUp: Int
}

Resolver 和數據類

GraphQL Java Tools可以將schema中定義的類型的屬性與java對象的屬性或方法對應起來。即上面的User類型,可以使用一個類與之對應

public class User {
    @Id
    private String id;
    private String nickname;
    private String mail;
    private String password;
    private String description;
    // 構造器,getter和setter
}

但是在Article類型中author的屬性是User,我們該如何解決呢?

這時我們可以使用一個GraphQLResolver指定某個類型的解析

@Component
public class ArticleResolver implements GraphQLResolver<Article> {
    private final UserRepository userRepository;

    public ArticleResolver(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public User author(Article article) {
        return userRepository.findById(article.getAuthorId()).get();
    }
}

指定Article類型的解析方式,其中標量類型可以直接從Aritcle的java類屬性中獲取,所以不必寫方法,對於author這個屬性,其類型為User,我們指定author()方法進行解析。

那么到底type Article {...}schema里面的屬性怎么解析呢?是與數據類進行映射,還是與resolver中的方法進行映射?

官網上給出了映射的優先級:

首先是resolver

  1. method 屬性名(...)
  2. method is屬性名(...)
  3. method get屬性名(...)
  4. method getField屬性名(...)

其次是Data Class(即與類型對應的java類)

  1. method 屬性名(...)
  2. method is屬性名(...)
  3. method get屬性名(...)
  4. method getField屬性名(...)
  5. field 屬性名

所以首先在ArticleResolver中查找author的映射,找不到的屬性則一致向下找到屬性的java類的get方法/屬性本身。

另外,要給Query和Mutation至少創建一個Resolver

@Component
public class QueryResolver implements GraphQLQueryResolver {

    private final UserRepository userRepository;
    private final ArticleRepository articleRepository;

    public QueryResolver(UserRepository userRepository, ArticleRepository articleRepository) {
        this.userRepository = userRepository;
        this.articleRepository = articleRepository;
    }

    public Article article(String title) {
        return articleRepository.findArticleByTitle(title);
    }

    public User user(String nickname) {
        return userRepository.findUserByNickname(nickname);
    }

    public List<User> users() {
        return userRepository.findAll();
    }
}

@Component
public class MutationResolver implements GraphQLQueryResolver, GraphQLMutationResolver {

    private final ArticleRepository articleRepository;
    private final UserRepository userRepository;
    private final BCryptPasswordEncoder encoder;

    public MutationResolver(ArticleRepository articleRepository, UserRepository userRepository, BCryptPasswordEncoder encoder) {
        this.articleRepository = articleRepository;
        this.userRepository = userRepository;
        this.encoder = encoder;
    }
    public User addUser(String mail, String nickname, String password) {
        if(userRepository.findUserByNickname(nickname) != null){
            return null;
        }
        return userRepository.save(User.builder()
                .nickname(nickname)
                .mail(mail)
                .password(encoder.encode(password))
                .build());
    }

    public  Article addArticle(String title, String content, String authorId) {
        if(!userRepository.findById(authorId).isPresent()){
            return null;
        }
        return articleRepository.save(Article.builder()
                .authorId(authorId)
                .title(title)
                .content(content)
                .createBy(new Date())
                .thumbUp(0)
                .build());
    }

}

這里使用mongodb存儲數據。

運行,在http://localhost:8080/graphiql 中進行操作

具體代碼戳這里


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM