springboot 整合GraphQL-java

這裏就不再介紹GraphQL了,有興趣的同學可以看https://blog.csdn.net/qq_40794266/article/details/102961334

導入依賴

 <!--spring boot的支持-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.1.RELEASE</version>
    </parent>

    <dependencies>
        <!--springboot的web支持-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.graphql-java</groupId>
            <artifactId>graphql-java</artifactId>
            <version>11.0</version>
        </dependency>

        <!--io操作工具包-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-io</artifactId>
            <version>1.3.2</version>
        </dependency>

    </dependencies>

 

resources下創建User.graphqls文件

schema {
    query: UserQuery
}
type UserQuery {
    user(id:Long) : User
}
type User{
    id:Long!
    name:String
    age:Int
}

 

創建User類

package cn.xiechuang.pojo;


public class User {
    private Long id;
    private String name;
    private Integer age;

    public User(Long id, String name, Integer age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

 

編寫controller(接收請求)

package cn.xiechuang.controller;

import graphql.GraphQL;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.Map;

@Controller
public class GraphQLController {

    @Autowired
    private GraphQL graphQL;

    @GetMapping("/graphql")
    @ResponseBody
    public Map<String,Object> graphql(@RequestParam("query") String query){


        return graphQL.execute(query).toSpecification();
    }
}

 

創建一個GraphQLProvider

package cn.xiechuang.graphql;

import cn.xiechuang.pojo.User;
import graphql.GraphQL;
import graphql.schema.GraphQLSchema;
import graphql.schema.idl.RuntimeWiring;
import graphql.schema.idl.SchemaGenerator;
import graphql.schema.idl.SchemaParser;
import graphql.schema.idl.TypeDefinitionRegistry;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.util.ResourceUtils;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.FileNotFoundException;

@Component
public class GraphQLProvider {

    private GraphQL graphQL;


    @PostConstruct
    public void init() throws FileNotFoundException {

        File file = ResourceUtils.getFile("classpath:user.graphqls");
        GraphQLSchema graphQLSchema = createGraphQLSchema(file);
        this.graphQL = GraphQL.newGraphQL(graphQLSchema).build();
    }


    public GraphQLSchema createGraphQLSchema(File file){
        SchemaGenerator schemaGenerator = new SchemaGenerator();

        SchemaParser schemaParser = new SchemaParser();
        TypeDefinitionRegistry typeRegistry = schemaParser.parse(file);


        return schemaGenerator.makeExecutableSchema(typeRegistry, buildResolver());
    }

    public RuntimeWiring buildResolver(){
        return RuntimeWiring.newRuntimeWiring()
                .type("UserQuery",builder ->
                        builder.dataFetcher("user",
                                dataFetchingEnvironment -> {
                                    Long id = dataFetchingEnvironment.getArgument("id");
                                    return new User(id,"springboot+graphql" ,15);
                        })
                ).build();
    }



    @Bean
    public GraphQL graphQL(){
        return this.graphQL;
    }
}

 

由於沒有GraphQL客戶端調試軟件,我就對controller改造了一下..模擬測試

@GetMapping("/graphql")
    @ResponseBody
    public Map<String,Object> graphql(){
        String query = null;
        query = "{user(id:1){id,name}}";
        return graphQL.execute(query).toSpecification();
    }

 

啓動測試

 

好的,接下來我們再新增一個查詢card的功能

創建Card實體類

package cn.xiechuang.pojo;

public class Card {

    private Long id;

    private String address;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

 

編寫user.graphql文件

schema {
    query: UserQuery
}
type UserQuery {
    user(id:Long) : User
    card(id:Long) : Card
}
type Card{
    id:Long
    address:String
}
type User{
    id:Long!
    name:String
    age:Int
}

修改GraphQLProvider類(新增一個dataFetcher)

package cn.xiechuang.graphql;

import cn.xiechuang.pojo.Card;
import cn.xiechuang.pojo.User;
import graphql.GraphQL;
import graphql.schema.GraphQLSchema;
import graphql.schema.idl.RuntimeWiring;
import graphql.schema.idl.SchemaGenerator;
import graphql.schema.idl.SchemaParser;
import graphql.schema.idl.TypeDefinitionRegistry;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.util.ResourceUtils;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.FileNotFoundException;

@Component
public class GraphQLProvider {

    private GraphQL graphQL;


    @PostConstruct
    public void init() throws FileNotFoundException {

        File file = ResourceUtils.getFile("classpath:user.graphqls");
        GraphQLSchema graphQLSchema = createGraphQLSchema(file);
        this.graphQL = GraphQL.newGraphQL(graphQLSchema).build();
    }


    public GraphQLSchema createGraphQLSchema(File file){
        SchemaGenerator schemaGenerator = new SchemaGenerator();

        SchemaParser schemaParser = new SchemaParser();
        TypeDefinitionRegistry typeRegistry = schemaParser.parse(file);


        return schemaGenerator.makeExecutableSchema(typeRegistry, buildResolver());
    }

    public RuntimeWiring buildResolver(){
        return RuntimeWiring.newRuntimeWiring()
                .type("UserQuery",builder ->
                        builder.dataFetcher("user",
                                dataFetchingEnvironment -> {
                                    Long id = dataFetchingEnvironment.getArgument("id");
                                    return new User(id,"springboot+graphql" ,15);
                        }).dataFetcher("card",
                                dataFetchingEnvironment ->{
                                    Long id = dataFetchingEnvironment.getArgument("id");
                                    return  new Card(id, "futian");
                                }  )

                ).build();
    }



    @Bean
    public GraphQL graphQL(){
        return this.graphQL;
    }
}

改寫controller測試

@GetMapping("/graphql")
    @ResponseBody
    public Map<String,Object> graphql(){
        String query = null;
//        query = "{user(id:1){id,name}}";
        query = "{card(id:1){id,address}}";
        return graphQL.execute(query).toSpecification();
    }

 

當業務開始複雜的時候,每增加一類查詢,就要增加一個dataFetcher,這會顯得provider類非常的臃腫,顯然是不合適的...優化

改進思路:
 
 
1. 編寫接口
 
 
2. 所有實現查詢的邏輯都實現該接口
 
 
3. GraphQLProvider中使用該接口的實現類進行處理
 
 
4. 以後需要新增查詢邏輯只需要增加實現類即可
 
 
創建接口
 
package cn.xiechuang.graphql;

import graphql.schema.DataFetchingEnvironment;

public interface MyDataFetcher {

//  查詢名稱
    String fieldName();

    /***
     * 具體實現數據查詢的邏輯**
     * @param environment
     * * @return
     * */
    Object dataFetcher(DataFetchingEnvironment environment);
}

 

編寫實現類
package cn.xiechuang.graphql;

import cn.xiechuang.pojo.Card;
import graphql.schema.DataFetchingEnvironment;
import org.springframework.stereotype.Component;

//託管給spring
@Component
public class CardDataFatcher implements MyDataFetcher {

    @Override
    public String fieldName() {
        return "card";
    }

    @Override
    public Object dataFetcher(DataFetchingEnvironment environment) {

        Long id = environment.getArgument("id");
        return  new Card(id, "futian");
    }
}

更改provider

package cn.xiechuang.graphql;

import cn.xiechuang.pojo.Card;
import cn.xiechuang.pojo.User;
import graphql.GraphQL;
import graphql.schema.GraphQLSchema;
import graphql.schema.idl.RuntimeWiring;
import graphql.schema.idl.SchemaGenerator;
import graphql.schema.idl.SchemaParser;
import graphql.schema.idl.TypeDefinitionRegistry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.util.ResourceUtils;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.List;

@Component
public class GraphQLProvider {

    private GraphQL graphQL;

    @Autowired
    List<MyDataFetcher> fetchers;//依賴注入實現類


    @PostConstruct
    public void init() throws FileNotFoundException {

        File file = ResourceUtils.getFile("classpath:user.graphqls");
        GraphQLSchema graphQLSchema = createGraphQLSchema(file);
        this.graphQL = GraphQL.newGraphQL(graphQLSchema).build();
    }


    public GraphQLSchema createGraphQLSchema(File file){
        SchemaGenerator schemaGenerator = new SchemaGenerator();

        SchemaParser schemaParser = new SchemaParser();
        TypeDefinitionRegistry typeRegistry = schemaParser.parse(file);


        return schemaGenerator.makeExecutableSchema(typeRegistry, buildResolver());
    }

    public RuntimeWiring buildResolver(){
        return RuntimeWiring.newRuntimeWiring()
                .type("UserQuery",builder ->{
                            for (MyDataFetcher fetcher : fetchers) {
                                builder.dataFetcher(fetcher.fieldName(),
                                        dataFetchingEnvironment ->{
                                            return fetcher.dataFetcher(dataFetchingEnvironment);
                                        }
                                );
                            }
                            return builder;
                        }
//                        builder.dataFetcher("user",
//                                dataFetchingEnvironment -> {
//                                    Long id = dataFetchingEnvironment.getArgument("id");
//                                    return new User(id,"springboot+graphql" ,15);
//                        }).dataFetcher("card",
//                                dataFetchingEnvironment ->{
//                                    Long id = dataFetchingEnvironment.getArgument("id");
//                                    return  new Card(id, "futian");
//                                })

                ).build();
    }



    @Bean
    public GraphQL graphQL(){
        return this.graphQL;
    }
}

測試

 

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章