美文网首页
GraphQL--springBoot java demo

GraphQL--springBoot java demo

作者: 小眼睛的露鹿酱 | 来源:发表于2019-08-26 18:21 被阅读0次

    GraphQL is a query language :

    搭建server, 供前端与后端使用的时候 参考:howtoGraphQL
    简单的语法学习: learn

    GraphQL 是一个新的API标准, 可以比Rest更有效的 强大的 灵活;它是由FaceBook开发并开源
    API defines how a clientcan load data from a server.
    Graph QL是一种都API的查询语言, 不是数据库查询语言, 比Rest更优越

    GraphiQL An in-browser IDE for exploring GraphQL.

    自己创建参看: readme

    简单的搭建一个自己的server

    参考 Getting started with GraphQL Java and Spring Boot

    1. 安装Java: download JDK1.8, 然后安装JDK与JRE, 配置环境变量
    2. 安装Gradle: download zip文件, 解压到相关路径, 并配置环境变量; 参考install
      显示如下便成功了:
    gradle -v
    
    Welcome to Gradle 5.6!
    
    1. 按照文档中的示例, 创建spring app: https://start.spring.io/.
      选择
      --Gradle Project
      --Java
      --Spring Boot 2.1.x
      --Group: com.graphql-java.tutorial
      --Artifact: book-details
      -- select Web.这个我自己选择的是
    1. 点击后, 会生成一个项目文件的压缩包, 直接解压到电脑中, 然后倒入Idea IDE, 注意导入后, 自己去seeting中设置JDK与Gradle为自己电脑上安装的location
    2. 粘贴文档中的代码 作者放在了github
    3. build 项目

    代码分析

    报错了:

    在浏览器中输入: http://localhost:8080/graphql
    显示的结果是:

    Whitelabel Error Page
    This application has no explicit mapping for /error, so you are seeing this as a fallback.
    
    Tue Aug 27 14:59:09 CST 2019
    There was an unexpected error (type=Bad Request, status=400).
    Required String parameter 'query' is not present
    

    在idea中显示如下:

    "D:\Install\IdeaUI\IntelliJ IDEA 2019.2.1\jbr\bin\java.exe" -XX:TieredStopAtLevel=1 -noverify -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true "-javaagent:D:\Install\IdeaUI\IntelliJ IDEA 2019.2.1\lib\idea_rt.jar=59523:D:\Install\IdeaUI\IntelliJ IDEA 2019.2.1\bin" -Dfile.encoding=UTF-8 -classpath D:\springBoot\book-details\build\classes\java\main;D:\springBoot\book-details\build\resources\main;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-web\2.1.7.RELEASE\fa43baf40bde3ecdb93ac9c545dd39f82ab29c35\spring-boot-starter-web-2.1.7.RELEASE.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.springframework.session\spring-session-core\2.1.8.RELEASE\2fe4df49293b18373c1050649192ff444be65f6\spring-session-core-2.1.8.RELEASE.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\com.graphql-java\graphql-java-spring-boot-starter-webmvc\1.0\4cf4fe366b11da5db76127a6b0607909b16977c5\graphql-java-spring-boot-starter-webmvc-1.0.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\com.graphql-java\graphql-java-spring-webmvc\1.0\93bd3420e9fd1c9e03cf2de0f438f9da2af923b4\graphql-java-spring-webmvc-1.0.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\com.graphql-java\graphql-java\11.0\1f670532643686b9816a871e2c9b9e5dce205eb6\graphql-java-11.0.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\com.google.guava\guava\26.0-jre\6a806eff209f36f635f943e16d97491f00f6bfab\guava-26.0-jre.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-json\2.1.7.RELEASE\9c12f046a7c4ae110d89163a491ad0d7cf036e79\spring-boot-starter-json-2.1.7.RELEASE.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter\2.1.7.RELEASE\e23f4e9460e0e2220b444e40fc7fd6e95f66e0fe\spring-boot-starter-2.1.7.RELEASE.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-tomcat\2.1.7.RELEASE\11f2a86aefefba72a4efe5ff18f4165a4b4e78b\spring-boot-starter-tomcat-2.1.7.RELEASE.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.hibernate.validator\hibernate-validator\6.0.17.Final\af73055fc4a103ab347c56e7da5a143d68a0170\hibernate-validator-6.0.17.Final.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.springframework\spring-webmvc\5.1.9.RELEASE\b9d4a2140488f0e6f9aa231e7938ae18da77b637\spring-webmvc-5.1.9.RELEASE.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.springframework\spring-web\5.1.9.RELEASE\9fe4390420fdd0b63dc4ed90d9027dafa9f74f80\spring-web-5.1.9.RELEASE.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-autoconfigure\2.1.7.RELEASE\2c9d3e2c6ea3cb435e99e2973009636b62a9d816\spring-boot-autoconfigure-2.1.7.RELEASE.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot\2.1.7.RELEASE\1599a2ad1fc6d36dbfc2a7c0dd5dab3a0bb27c61\spring-boot-2.1.7.RELEASE.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.springframework\spring-context\5.1.9.RELEASE\c37f8fe15a5ae4ea1f351bd46167fd492a84eefa\spring-context-5.1.9.RELEASE.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.springframework\spring-aop\5.1.9.RELEASE\bc2312ffad02251b9d472e4a7c0e472a58f50fbf\spring-aop-5.1.9.RELEASE.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.springframework\spring-beans\5.1.9.RELEASE\5a03b3983108d73978aec2fa3e681aedad6782c\spring-beans-5.1.9.RELEASE.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.springframework\spring-expression\5.1.9.RELEASE\db3a2468c1b7d697ec3b3ec6e5652dc282994fe3\spring-expression-5.1.9.RELEASE.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.springframework\spring-core\5.1.9.RELEASE\dc3815439579b4fa0c19970e6b8e5d774af8d988\spring-core-5.1.9.RELEASE.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.springframework\spring-jcl\5.1.9.RELEASE\7c372790c999777d20f364960cf557dd74f890cf\spring-jcl-5.1.9.RELEASE.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.antlr\antlr4-runtime\4.7.1\946f8aa9daa917dd81a8b818111bec7e288f821a\antlr4-runtime-4.7.1.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-logging\2.1.7.RELEASE\6e829f739992a7f368c0af44a08ed89ad2a1972f\spring-boot-starter-logging-2.1.7.RELEASE.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\ch.qos.logback\logback-classic\1.2.3\7c4f3c474fb2c041d8028740440937705ebb473a\logback-classic-1.2.3.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.apache.logging.log4j\log4j-to-slf4j\2.11.2\6d37bf7b046c0ce2669f26b99365a2cfa45c4c18\log4j-to-slf4j-2.11.2.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.slf4j\jul-to-slf4j\1.7.26\8031352b2bb0a49e67818bf04c027aa92e645d5c\jul-to-slf4j-1.7.26.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.slf4j\slf4j-api\1.7.26\77100a62c2e6f04b53977b9f541044d7d722693d\slf4j-api-1.7.26.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\com.graphql-java\java-dataloader\2.1.1\2ac1e4f0764030853195bf89eb4bd0bbe2151eb2\java-dataloader-2.1.1.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.reactivestreams\reactive-streams\1.0.2\323964c36556eb0e6209f65c1cef72b53b461ab8\reactive-streams-1.0.2.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\com.google.code.findbugs\jsr305\3.0.2\25ea2e8b0c338a877313bd4672d3fe056ea78f0d\jsr305-3.0.2.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.checkerframework\checker-qual\2.5.2\cea74543d5904a30861a61b4643a5f2bb372efc4\checker-qual-2.5.2.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\com.google.errorprone\error_prone_annotations\2.1.3\39b109f2cd352b2d71b52a3b5a1a9850e1dc304b\error_prone_annotations-2.1.3.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\com.google.j2objc\j2objc-annotations\1.1\ed28ded51a8b1c6b112568def5f4b455e6809019\j2objc-annotations-1.1.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.codehaus.mojo\animal-sniffer-annotations\1.14\775b7e22fb10026eed3f86e8dc556dfafe35f2d5\animal-sniffer-annotations-1.14.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\javax.annotation\javax.annotation-api\1.3.2\934c04d3cfef185a8008e7bf34331b79730a9d43\javax.annotation-api-1.3.2.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.datatype\jackson-datatype-jdk8\2.9.9\4b04126963103216c9c43b0f34bbc36315654204\jackson-datatype-jdk8-2.9.9.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.datatype\jackson-datatype-jsr310\2.9.9\a33df137557793b0404a486888dbe049f7abeeeb\jackson-datatype-jsr310-2.9.9.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.module\jackson-module-parameter-names\2.9.9\a92facb55a2538e7b2fe14294570a18b823ad431\jackson-module-parameter-names-2.9.9.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.yaml\snakeyaml\1.23\ec62d74fe50689c28c0ff5b35d3aebcaa8b5be68\snakeyaml-1.23.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.core\jackson-databind\2.9.9\d6eb9817d9c7289a91f043ac5ee02a6b3cc86238\jackson-databind-2.9.9.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.apache.tomcat.embed\tomcat-embed-websocket\9.0.22\45974d3443cc15ad9d10239d762d5e15759e6364\tomcat-embed-websocket-9.0.22.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.apache.tomcat.embed\tomcat-embed-core\9.0.22\79f39903498b28adacb18fe2ea046edd306295a6\tomcat-embed-core-9.0.22.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.apache.tomcat.embed\tomcat-embed-el\9.0.22\4da4b778b635a7e78ca7cd7288253e2e47b88a9f\tomcat-embed-el-9.0.22.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\javax.validation\validation-api\2.0.1.Final\cb855558e6271b1b32e716d24cb85c7f583ce09e\validation-api-2.0.1.Final.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.jboss.logging\jboss-logging\3.3.2.Final\3789d00e859632e6c6206adc0c71625559e6e3b0\jboss-logging-3.3.2.Final.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\com.fasterxml\classmate\1.4.0\291658ac2ce2476256c7115943652c0accb5c857\classmate-1.4.0.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.core\jackson-annotations\2.9.0\7c10d545325e3a6e72e06381afe469fd40eb701\jackson-annotations-2.9.0.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.core\jackson-core\2.9.9\bfff5af9fb8347d26bbb7959cb9b4fe9a2b0ca5e\jackson-core-2.9.9.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\ch.qos.logback\logback-core\1.2.3\864344400c3d4d92dfeb0a305dc87d953677c03c\logback-core-1.2.3.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.apache.logging.log4j\log4j-api\2.11.2\f5e9a2ffca496057d6891a3de65128efc636e26e\log4j-api-2.11.2.jar com.graphqljava.tutorial.bookdetails.BookDetailsApplication
    
      .   ____          _            __ _ _
     /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
    ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
     \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
      '  |____| .__|_| |_|_| |_\__, | / / / /
     =========|_|==============|___/=/_/_/_/
     :: Spring Boot ::        (v2.1.7.RELEASE)
    
    2019-08-27 16:20:05.959  INFO 12308 --- [           main] c.g.t.b.BookDetailsApplication           : Starting BookDetailsApplication on EPCNSZUW0073 with PID 12308 (D:\springBoot\book-details\build\classes\java\main started by Winfery_Wen in D:\springBoot\book-details)
    2019-08-27 16:20:05.960  INFO 12308 --- [           main] c.g.t.b.BookDetailsApplication           : No active profile set, falling back to default profiles: default
    2019-08-27 16:20:06.639  INFO 12308 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
    2019-08-27 16:20:06.658  INFO 12308 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
    2019-08-27 16:20:06.659  INFO 12308 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.22]
    2019-08-27 16:20:06.743  INFO 12308 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
    2019-08-27 16:20:06.749  INFO 12308 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 757 ms
    2019-08-27 16:20:07.035  INFO 12308 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
    2019-08-27 16:20:07.178  INFO 12308 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
    2019-08-27 16:20:07.181  INFO 12308 --- [           main] c.g.t.b.BookDetailsApplication           : Started BookDetailsApplication in 1.444 seconds (JVM running for 1.923)
    2019-08-27 16:21:15.060  INFO 12308 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
    2019-08-27 16:21:15.060  INFO 12308 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
    2019-08-27 16:21:15.066  INFO 12308 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 6 ms
    2019-08-27 16:21:15.092  WARN 12308 --- [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'query' is not present]
    
    

    Resolution

    follow the log
    install GraphQL Playground; open new workspace and
    use url: http://localhost:8080/graphql?query=%7B__schema%20%7B%20types%20%7Bname%7D%20%7D%7D

    一下的结果是在浏览器的url中输入的结果
    {"data":{
        "__schema":
            {"types":
            [
                {"name":"__TypeKind"},
                {"name":"__Field"},
                {"name":"Query"},
                {"name":"__Schema"},
                {"name":"__Type"},
                {"name":"__EnumValue"},
                {"name":"__DirectiveLocation"},
                {"name":"String"},
                {"name":"Int"},
                {"name":"Book"},
                {"name":"Author"},
                {"name":"ID"},
                {"name":"__InputValue"},
                {"name":"Boolean"},
                {"name":"__Directive"}
                ]
               }
            }
    }
    

    打开GraphQL playground后就能进行使用; 但是只能使用他规定的query语句

    {
      bookById(id:"book-1"){
        id
        name
        author{
          firstName
          lastName
        }
      }
    }
    

    return:

    {
      "data": {
        "bookById": {
          "id": "book-1",
          "name": "Harry Potter and the Philosopher's Stone",
          "author": {
            "firstName": "Joanne",
            "lastName": "Rowling"
          }
        }
      }
    }
    

    schema:

    directive @defer on FIELD
    type Author {
      id: ID
      firstName: String
      lastName: String
    }
    
    type Book {
      id: ID
      name: String
      pageCount: Int
      author: Author
    }
    
    type Query {
      bookById(id: ID): Book
    }
    
    
    

    introspection

    在该示例代码中, 其实是使用了GraphQL的schema来定义了只能使用的query; 其实就是使用了graphQL中的introSpection(自我检测);我们定义了type, 但是有时候我们并不知道里面包含了哪些type, 这个时候我们就可以通过query: __schema来获取这个系统相关的信息:

    {
      __schema {
        types {
          name
        }
      }
    }
    

    对应的结果就是

    {
      "data": {
        "__schema": {
          "types": [
            {
              "name": "Query"
            },
            {
              "name": "Episode"
            },
            {
              "name": "Character"
            },
            {
              "name": "ID"
            },
            {
              "name": "String"
            },
            {
              "name": "Int"
            },
            {
              "name": "FriendsConnection"
            },
            {
              "name": "FriendsEdge"
            },
            {
              "name": "PageInfo"
            },
            {
              "name": "Boolean"
            },
            {
              "name": "Review"
            },
            {
              "name": "SearchResult"
            },
            {
              "name": "Human"
            },
            {
              "name": "LengthUnit"
            },
            {
              "name": "Float"
            },
            {
              "name": "Starship"
            },
            {
              "name": "Droid"
            },
            {
              "name": "Mutation"
            },
            {
              "name": "ReviewInput"
            },
            {
              "name": "__Schema"
            },
            {
              "name": "__Type"
            },
            {
              "name": "__TypeKind"
            },
            {
              "name": "__Field"
            },
            {
              "name": "__InputValue"
            },
            {
              "name": "__EnumValue"
            },
            {
              "name": "__Directive"
            },
            {
              "name": "__DirectiveLocation"
            }
          ]
        }
      }
    }
    

    而上面的例子中, 其实输入的就是该query。
    现在, 我们需要知道哪些query是我们可以做的,当我们定义type系统的时候, 我们需要指定所有query的起始type, 这个时候需要使用introspection来帮我们得到:



    所以query 是我们开始的类型;
    查询某个type对象的信息

    {
      __type(name:"Author"){
        name
        kind
        description
        
      }
    }
    
    {
      "data": {
        "__type": {
          "name": "Author",
          "kind": "OBJECT",
          "description": null
        }
      }
    }
    

    查询type内容中子域的type信息

    {
      __type(name:"Author"){
        name
        kind
        fields{
          name
          type{
            name
            kind
          }
        }
        
      }
    }
    

    return

    {
      "data": {
        "__type": {
          "name": "Author",
          "kind": "OBJECT",
          "fields": [
            {
              "name": "id",
              "type": {
                "name": "ID",
                "kind": "SCALAR"
              }
            },
            {
              "name": "firstName",
              "type": {
                "name": "String",
                "kind": "SCALAR"
              }
            },
            {
              "name": "lastName",
              "type": {
                "name": "String",
                "kind": "SCALAR"
              }
            }
          ]
        }
      }
    }
    

    创建一个GraphQL service就是通过定义type和field, 然后为每一个type中的每一个field提供functions, 例如:

    type Query {
      me: User
    }
    
    type User {
      id: ID
      name: String
    }
    
    function Query_me(request) {
      return request.auth.user;
    }
    
    function User_name(user) {
      return user.getName();
    }
    

    一旦一个service开始运行(一般是web sevice上的url), 这个服务器上就能发送query并执行, 收到的query首先会被检查并确保所涉及的type都是正确的, 然后运行代码中对应的函数来得到结果。
    例如:

    {
      me {
        name
      }
    }
    

    return

    {
      "me": {
        "name": "Luke Skywalker"
      }
    }
    

    具体语法参照

    相关文章

      网友评论

          本文标题:GraphQL--springBoot java demo

          本文链接:https://www.haomeiwen.com/subject/cxxrectx.html