User(id:Long) : User #查询实体类二:TableResult,对应查询名称也为TableResult UsersList(page:Int, pageSize:Int) : TableResult #查询实体类三:IndexAdResult ,对应查询名称也为IndexAdResult IndexAdList:IndexAdResult #对应实体类User type User { id:Long! name:String age:Int #对应实体类TableResult type TableResult{ list:[User] pagination:Pagination #对应实体类Pagination type Pagination{ current:Int pageSize:Int total:Int #对应实体类IndexAdResult type IndexAdResult{ # 查询类型IndexAdResult的属性为类型IndexAdResultData的集合 # 因为字段名称list对应的类型是自定类型 所以还要在其后展开 查询条件为: # IndexAdList{ # list{ # original # } list:[IndexAdResultData] #对应实体类IndexAdResultData type IndexAdResultData{ original:String
  • 存在弊端:DataFetcher增多 不好管理
  • 解决方案:定义一个DataFetcher的接口 所有DataFetcher都实现该接口 然后所有该DataFetcher的实现类 都注入到GraphqlProvider中

1、MyDataFetcher(接口)

public interface MyDataFetcher {
	//查询类型中实体类对应的查询名称
    String fieldName();
	//通过DataFetchingEnvironment 获取查询条件对象的参数值 并返回查询到的数据
    Object dataFetcher(DataFetchingEnvironment environment);

2、UserDataFetcher(MyDataFetcher实现类 对应UserQuery中User对象)

//必须注入spring 才可以在spring扫描MyDataFetcher的子类时扫描到
@Component
public class UserDataFetcher implements MyDataFetcher {
    @Autowired
    private UserService userService;
    @Override
    public String fieldName() {
    	//返回查询名称User 然后可以通过该名称找到对应的类型
        return "User";
    @Override
    public Object dataFetcher(DataFetchingEnvironment environment) {
    	//获取User查询对象的参数id
        Long id = environment.getArgument("id");
        return this.userService.queryUserById(id);

3、UserListDataFetcher(MyDataFetcher实现类 对应UserQuery中UsersList对象)

//必须注入spring 才可以在spring扫描MyDataFetcher的子类时扫描到
@Component
public class UserListDataFetcher implements MyDataFetcher {
    @Autowired
    private UserService userService;
    @Override
    public String fieldName() {
   	    //返回查询名称UsersList 然后可以通过该名称找到对应的类型
        return "UsersList";
    @Override
    public Object dataFetcher(DataFetchingEnvironment environment) {
    	//获取UsersList查询对象的参数page
        Integer page = environment.getArgument("page");
        if(null == page){
            page = 1;
        //获取UsersList查询对象的参数pageSize
        Integer pageSize = environment.getArgument("pageSize");
        if(null == pageSize){
            pageSize = 5;
        return this.userService.queryList(null, page, pageSize);

4、此处省略IndexAdList实体类的DataFetcher
5、GraphqlProvider(重新实现buildWiring方法)

@Component
public class GraphqlProvider {
    private GraphQL graphQL;
	//注入MyDataFetcher的所有实现类
    @Autowired
    private List<MyDataFetcher> myDataFetchers;
    @Bean
    private GraphQL graphQL(){
        return this.graphQL;
    //实现对GraphQL对象的初始化
    @PostConstruct
    public void init() throws FileNotFoundException {
        File file = ResourceUtils.getFile("classpath:user.graphqls");
        this.graphQL = GraphQL.newGraphQL(buildGraphQLSchema(file)).build();
    private GraphQLSchema buildGraphQLSchema(File file) {
        TypeDefinitionRegistry typeRegistry = new SchemaParser().parse(file);
        return new SchemaGenerator().makeExecutableSchema(typeRegistry, buildWiring());
    private RuntimeWiring buildWiring() {
        return RuntimeWiring.newRuntimeWiring()
                .type("UserQuery", builder -> {
                			//遍历myDataFetcher的所有实现类
                            for (MyDataFetcher myDataFetcher : myDataFetchers) {
                            	//获取查询的名称 然后找到其对应的类型
                                builder.dataFetcher(myDataFetcher.fieldName(),
                                		//调用不同的myDataFetcher实现类的dataFetcher方法 返回查询到的数据
                                        environment -> myDataFetcher.dataFetcher(environment));
                            return builder;
                .build();

6.使用方法和上一篇的controller相同

问题二.GraphQL如何不将参数写死

  • GraphQL的支持动态参数
    1. 传统静态参数查询语法
      {
          实体类查询名(字段名:"参数值"){
              查询字段1
              查询字段2
      
    2. 动态参数查询写语法
      • QUERY
        query 实体类查询名($参数名:类型){
            实体类查询名(字段名:$参数名){
                查询字段1
                查询字段2
        
      • GRAPHQL VARIABLES
        {
        	"参数名":参数值
        

        3.动态参数写法示例(查询上面的UsersList)

        • operationName-> 表示操作名称,这个随意。
        • $pageSize: Int-> 定义参数名以及参数类型
        • (pageSize: $pageSize) -> 通过参数名使用参数的值

        4.SpringBoot如何接收使用

        • 不用改动任何Provider和DataFetcher 只用改动Controller 解析前端传来数据就可以
        • 静态参数的时候 json字符串只有一个字段query:{query:"…"}
        • 静态参数的时候 json字符串只有多个字段:{query:"…",varivaables:{},operationName:"…"}
          • query:查询语句
          • varivaables:参数的map
          • operationName:就是query operationName{ },在query之后跟的那个名字
        • 注意:动态参数的variables对应的是参数和值map 不是string字符串
        @Controller
        @RequestMapping("graphql")
        public class GraphQLController {
            @Autowired
            //还是原先那个provider注入的graphQL
            private GraphQL graphQL;
        	//解析前端前端传来的json字符串
            private static ObjectMapper MAPPER=new ObjectMapper();
            @GetMapping
            @ResponseBody
        	 *	原先静态参数的时候json字符串只有一个字段 所以转成Map和String差不多 但是动态参数友三个字段 转成Map更方便
            //让SpringBoot把json字符串转化为Map类型
            public Map<String,Object> getQuery(@RequestBody Map<String,Object> params) throws IOException {
                return parseQuery(params);
            @PostMapping
            @ResponseBody
            //让SpringBoot把json字符串转化为Map类型
            public Map<String,Object> postQuery(@RequestBody Map<String,Object> params) throws IOException {
                return parseQuery(params);
        	//解析前端json字符串转化后的map对象
            public Map<String,Object> parseQuery(Map<String,Object> params) throws IOException {
            	//获取查询语句
                String query= (String) params.get("query");
                if(StringUtils.isBlank(query)){
                    Map<String, Object> error = new HashMap<>();
                    error.put("status", 500);
                    error.put("msg", "查询出错");
                    return error;
        		//获取操作名
                String operationName= (String) params.get("operationName");
                //获取变量的map
                Map<String ,Object> variables= (Map<String, Object>) params.get("variables");
        		//将query、operationName、variables构建成一个查询语句
                ExecutionInput executionInput=ExecutionInput.newExecutionInput()
                        .query(query)
                        .operationName(operationName)
                        .variables(variables)
                        .build();
                return graphQL.execute(executionInput).toSpecification();