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 中进行操作

具体代码戳这里

猜你喜欢

转载自www.cnblogs.com/dionysun/p/12130440.html