网络上有很多使用各种语言实现GraphQL通信的文章,感觉很复杂,最近在熟悉SpringBoot3的相关文档,发现里面支持GraphQL的接入,小试牛刀,尝试了一把,比网络上其他的demo简洁很多,下面开始SpringBoot GraphQL Hello World,参考如下官方文档。
https://docs.spring.io/spring-graphql/docs/current/reference/html/#client.requests.document-source
首先引入主要的依赖,当然还需要spring-boot-starter-webflux,这个是基于响应式的,读者可以自行引入。
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-graphql</artifactId></dependency>
然后编写GraphQL Schema,只有一个查询的方法,GraphQL Schema可以参考官网或者其他教程脑补,这块很重要,类似于gprc中的proto。下面的Schema放在src/main/resources/graphql目录(自定义的位置可以在配置文件里指定的,这块可以参考官方文档)下,命名为test.gqls
type Query { greeting(name:String):String }
接着就是定义一个实现类,其实就是一个controller,主要是靠两个陌生的注解@QueryMapping和@Argument
importorg.springframework.graphql.data.method.annotation.Argument; importorg.springframework.graphql.data.method.annotation.QueryMapping; importorg.springframework.stereotype.Controller; publicclassGreetingController { publicStringgreeting(Stringname){ return"Hello,World!"+name; } }
最后就是测试调用,这里使用HttpGraphQlClient,即spring-boot-starter-graphql自带的客户端以http协议访问我们实现的GraphQL服务端,官方还有其他协议,可以继续学习尝试。
importorg.springframework.graphql.client.HttpGraphQlClient; importorg.springframework.web.reactive.function.client.WebClient; importreactor.core.publisher.Mono; importjava.io.IOException; importjava.net.URISyntaxException; publicclassClientTest { publicstaticvoidmain(String [] args) throwsURISyntaxException, IOException, InterruptedException { WebClientclient=WebClient.create("http://localhost:9999/graphql"); HttpGraphQlClienthttpGraphQlClient=HttpGraphQlClient.builder(client).build(); Mono<String>result=httpGraphQlClient.document("{ greeting(name:\"anis\") } ").retrieve("greeting").toEntity(String.class).map(response->response); System.out.println(result.block()); } }
http://localhost:9999/graphql为服务地址,9999是端口,graphql是默认的,比较懒,就按照官方文档使用默认的,暂时不知道怎么自定义,应该可以自定义,上述代码输出结果如下
10:33:23,544 |-INFO in ch.qos.logback.classic.LoggerContext[default] - This is logback-classic version 1.4.5 10:33:23,608 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback-test.xml] 10:33:23,609 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Found resource [logback.xml] at [jar:file:/C:/Users/Administrator/.m2/repository/org/apache/rocketmq/rocketmq-streams/1.1.0/rocketmq-streams-1.1.0.jar!/logback.xml] 10:33:23,634 |-INFO in ch.qos.logback.core.joran.spi.ConfigurationWatchList@22ef9844 - URL [jar:file:/C:/Users/Administrator/.m2/repository/org/apache/rocketmq/rocketmq-streams/1.1.0/rocketmq-streams-1.1.0.jar!/logback.xml] is not of type file 10:33:23,809 |-WARN in ch.qos.logback.classic.joran.action.LevelAction - <level> element is deprecated. Near [level] on line 37 10:33:23,809 |-WARN in ch.qos.logback.classic.joran.action.LevelAction - Please use "level" attribute within <logger> or <root> elements instead. 10:33:24,042 |-INFO in ch.qos.logback.core.model.processor.AppenderModelHandler - Processing appender named [DefaultAppender_inner] 10:33:24,042 |-INFO in ch.qos.logback.core.model.processor.AppenderModelHandler - About to instantiate appender of type [ch.qos.logback.core.rolling.RollingFileAppender] 10:33:24,116 |-INFO in ch.qos.logback.core.rolling.FixedWindowRollingPolicy@6283d8b8 - No compression will be used 10:33:24,123 |-INFO in ch.qos.logback.core.model.processor.ImplicitModelHandler - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property 10:33:24,181 |-INFO in ch.qos.logback.core.rolling.RollingFileAppender[DefaultAppender_inner] - Active log file name: C:\Users\Administrator/logs/rocketmq-streams/streams_default.log 10:33:24,182 |-INFO in ch.qos.logback.core.rolling.RollingFileAppender[DefaultAppender_inner] - File property is set to [C:\Users\Administrator/logs/rocketmq-streams/streams_default.log] 10:33:24,185 |-INFO in ch.qos.logback.core.model.processor.AppenderModelHandler - Processing appender named [DefaultAppender] 10:33:24,185 |-INFO in ch.qos.logback.core.model.processor.AppenderModelHandler - About to instantiate appender of type [ch.qos.logback.classic.AsyncAppender] 10:33:24,191 |-INFO in ch.qos.logback.core.model.processor.AppenderRefModelHandler - Attaching appender named [DefaultAppender_inner] to ch.qos.logback.classic.AsyncAppender[DefaultAppender] 10:33:24,191 |-INFO in ch.qos.logback.classic.AsyncAppender[DefaultAppender] - Attaching appender named [DefaultAppender_inner] to AsyncAppender. 10:33:24,195 |-INFO in ch.qos.logback.classic.AsyncAppender[DefaultAppender] - Setting discardingThreshold to 51 10:33:24,196 |-INFO in ch.qos.logback.core.model.processor.AppenderModelHandler - Processing appender named [console] 10:33:24,196 |-INFO in ch.qos.logback.core.model.processor.AppenderModelHandler - About to instantiate appender of type [ch.qos.logback.core.ConsoleAppender] 10:33:24,222 |-INFO in ch.qos.logback.classic.model.processor.LevelModelHandler - ROOT level set to INFO 10:33:24,222 |-INFO in ch.qos.logback.core.model.processor.AppenderRefModelHandler - Attaching appender named [console] to Logger[ROOT] 10:33:24,222 |-INFO in ch.qos.logback.core.model.processor.AppenderRefModelHandler - Attaching appender named [DefaultAppender] to Logger[ROOT] 10:33:24,222 |-INFO in ch.qos.logback.core.model.processor.DefaultProcessor@3b6ddd1d - End of configuration. 10:33:24,224 |-INFO in ch.qos.logback.classic.joran.JoranConfigurator@3f6b0be5 - Registering current configuration as safe fallback point Hello,World!anis
主要是最后一行Hello,World!anis,各位可以自己试试。其他复杂的类型的请求,比如参数是po或者list的,返回为po或者list的,都是可以在Schema中约定好,然后在controller类中定义相应的实现。
总结,首次尝试这个GraphQL,接触GraphQL这个概念还是马斯克入驻twitter的时候喷twitter客户端首页要发起上千个GraphQL调用,所以引起了自己的关注,感觉这个跟Proto很像。网上给出的例子很复杂,猜测是SpringBoot封装了很多,让我们上手容易一些。有的说是微服务之间调用使用的,客户端使用的较少。在此不做评论,反正自己项目常用的还是http json的,哈哈!