Spring Boot + GraphQL 应用

  

在浅尝GraphQL一文描述了GraphQL及基本使用,本文提供一个基本示例,描述如何基于spring boot的web项目快速应用。

graphql-java的官方文档:Getting started with GraphQL Java and Spring Boot,提供了相关依赖用以快速配置,但是个人真心不建议使用这个库及相关配置方式来搭建脚手架,在实际开发中,业务比较复杂的时候,会导致需要配置的业务代码比较多也比较繁琐,相对下面这种方式,代码复杂性比较高。

本文提供一种更灵活快捷的方式,在spring boot项目中快速应用开发。使用的依赖也和上面官方提供的都不一样,请注意区分。

快速开始

创建 Spring boot 工程

通过Spring Initializr快速搭建,我选的jdk版本及spring boot版本,如下所示,其它版本未做兼容性测试。

点击下方的Generate按钮:

打开工程结构如下,我将application.properties删除了替换成applicaiton.yml,因为我个人比较喜欢yaml的配置方式:

引入相关依赖

pom.xml配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.4.6</version>
  <relativePath/> <!-- lookup parent from repository -->
 </parent>
 <groupId>com.xuxd</groupId>
 <artifactId>graphql.demo</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <name>graphql.demo</name>
 <description>GraphQL Demo project for Spring Boot</description>
 <properties>
  <java.version>1.8</java.version>
  <maven.compiler.source>1.8</maven.compiler.source>
  <maven.compiler.target>1.8</maven.compiler.target>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  <lombok.version>1.18.20</lombok.version>
  <graphql-java-tools.version>11.0.1</graphql-java-tools.version>
  <gson.version>2.8.7</gson.version>
 </properties>
 <dependencies>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter</artifactId>
  </dependency>

  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
  </dependency>

  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-test</artifactId>
   <scope>test</scope>
  </dependency>

  <dependency>
   <groupId>org.projectlombok</groupId>
   <artifactId>lombok</artifactId>
   <version>${lombok.version}</version>
   <scope>provided</scope>
  </dependency>

  <dependency>
   <groupId>com.graphql-java-kickstart</groupId>
   <artifactId>graphql-java-tools</artifactId>
   <version>${graphql-java-tools.version}</version>
  </dependency>

  <dependency>
   <groupId>com.google.code.gson</groupId>
   <artifactId>gson</artifactId>
   <version>${gson.version}</version>
  </dependency>
 </dependencies>

 <build>
  <plugins>
   <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
   </plugin>
  </plugins>
 </build>

</project>

初始化GraphQL实例

我们将创建一个GraphQL实例并将其注册到spring容器中,代码如下。Spring Boot 基础就不介绍了,推荐下这个实战教程:https://www.javastack.cn/categories/Spring-Boot/

创建一个GraphQLProvider类:

@Component
public class GraphQLProvider {

    private GraphQL graphQL;

    @Autowired
    private IItemService itemService;

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

    @PostConstruct
    public void init() throws IOException {
        GraphQLSchema graphQLSchema = SchemaParser.newParser()
            .file("graphql/base.graphqls")
            .resolvers(new Query(), new Mutation())
            .file("graphql/item.graphqls")
            .resolvers(new ItemResolver(itemService))
// .file("book.graphqls")
// .resolvers(new BookResolver()) //其它定义照上面的示例,继续增加
            .build().makeExecutableSchema();

        this.graphQL = graphQL.newGraphQL(graphQLSchema).build();
    }

}

关于*.graphqls或者对应的Resolver如ItemResolver,可以参看浅尝GraphQL相关描述,这里只是作了微调整,相关代码如下:

base.grqphqls

schema {
    # 查询
    query: Query
    # 更新
    mutation: Mutation
}

type Query {
    version: String
}

type Mutation {
    version: String
}

item.graphqls

# 定义一个查询类型
extend type Query {
    queryItemList: ItemList # 定义查询项目列表
    queryById(id: ID): Item
}

extend type Mutation {
    updateName(param: Param): Item
}

# 定义项目字段
type Item {
    id: ID!
    code: String!
    name: String!
}

type ItemList {
    itemList: [Item!]! #获取项目列表
    total: Int! # 获取项目总数
}

input Param {
    id: ID!
    name: String!
}

ItemResolver

public class ItemResolver implements GraphQLQueryResolver, GraphQLMutationResolver {

    private IItemService itemService;

    public ItemResolver(IItemService itemService) {
        this.itemService = itemService;
    }

    // 对应item.graphqls里的queryItemList
    public ItemList queryItemList() {
        return itemService.queryItemList();
    }

    public Item queryById(Long id) {
        return itemService.queryById(id);
    }

    public Item updateName(Param param) {
        return itemService.updateName(param);
    }
}

相关业务代码比较多,就不一一贴了。

提供API

我们需要暴露一个接口来接收请求,并作相关处理,也只需提供一个接口即可。因此我们创建一个Controller:GraphqlController.

@RestController
@RequestMapping("/graphql")
@Log
public class GraphqlController {

    @Autowired
    private GraphQL graphQL;

    @PostMapping
    public Object execute(@RequestBody GraphqlRequest request) {
        ExecutionInput executionInput = ExecutionInput.newExecutionInput()
            .query(request.getQuery())
            .variables(request.getVariables())
            .build();
        Map<String, Object> result = new HashMap<>();

        ExecutionResult executionResult = graphQL.execute(executionInput);
        List<GraphQLError> errors = executionResult.getErrors();

        if (errors != null && !errors.isEmpty()) {
            result.put("errors", errors);
            return result;
        }
        return executionResult.getData();
    }
}

到这一步,其实基本功能都已配置完成,可以启动项目进行相关测试了。

整个项目的代码结构如下,我尽量用了一个比较常规的web项目结构(controller,service,dao等):

测试

示例中总共提供了3个接口,两个查询一个更新,分别进行测试:

ItemList queryItemList();

Item queryById(Long id);

Item updateName(Param param);

查询所有项目列表(只获取每个项目的编码和名称,以及列表总数):

根据ID查询,获取项目的id和名称

更新指定ID的项目名称

我们项目Id为1编码为test的项目修改为“java项目”

再查询一下,可以看到结果更新了:

结束语

这样整个项目的GraphQL相关的基本配置已经完成,可以进行业务开发了。

地址:https://blog.csdn.net/x763795151/article/details/117604505

全部评论

相关推荐

04-11 00:51
已编辑
门头沟学院 Java
先说一下楼主的情况:双非本大三,两段实习,javaer,想要找一个暑期大厂offer,努力了两个月,三月份每天的状态就是算法,八股,项目,四月份更是一个面试没有,最终还是没有结果,心碎了一地。期间面了一些中小厂,大厂只有腾讯约面,其他大厂都投了一遍,但是还是石沉大海。再看一下楼主的面试结果吧,就不说ttl了腾讯s3:三面挂csig:一面挂teg:三面挂wxg:一面挂没错,面了八次腾讯,两次三面挂,当时真的心都碎了。其他中小厂都有面,有的没过,有的oc,但是都没有去。其他大厂投了简历,但是不是简历挂,就是测评挂,都说今年行情好很多,各大厂都扩招,可是问题出在那里呢?学历背景吗?实习经历吗?还是简历不够好看?依稀记得,从年初七就离开了家里,回到学校,早早准备面试,当时自己认为凭借着自己的两段实习经历,以及大二就开始准备的八股算法,拿大厂offer不是问题,但是还是不敢放松,回校的状态每天就是算法,八股,还有查看各种招聘信息,想着尽早投机会多,但是事实证明,投的早,不如投的刚刚好。当时想着,先投一些中小厂开始面试,找找面试感觉,从2.10就开始有面试了,基本都是线下面试,面试的感觉都很不错,觉得自己的状态慢慢回来了,期间也有oc一些中小厂,但是自己的目标并不在此,只是想练一下手,遂拒。后面投了腾讯的暑期实习基地,不久就约面了,第一次面这么大的厂,多少有点紧张,好在运气还不错,遇到的面试官也比较好,一直干到了三面,期间看牛客有不少说一面就挂了的,感觉自己还是比较幸运的,但是没想到倒在了三面,一周后就挂了,伤心是有的,但是想到这才刚刚开始,还有很多机会,便继续准备下一次面试了,很快,被另外一个部门捞了,一进会议,面试官没开摄像头,看网上说没开摄像头很多都是kpi,但是自己给自己打气,认为面试官只是不方便开摄像头罢了,面完,感觉良好,没问什么很难得问题,基本都答出来了,算法两道也a了一道,感觉实习不会这么严格吧?还是过了一会挂了,因为这个?还是技术不太匹配?面试过程中说搞C++的,心想,搞c++的你面我干啥?唉,这时候有点气馁,然后就接下来半个月没有面试。这时已经是三月底了,看到牛客好多人都已经陆陆续续拿到了offer,看人家的面试准备也没那么早,有0实习的,有没刷算法的,有两个面的,,,唉,反正是一言难尽啊,感觉努力没有什么意义,面试多半是看面试官的感觉,主观性很大啊,只要你技术没有太大的问题。第三次面试腾讯,面试来的比较突然,期间已经有几天没看八股什么的了,临时看了一下之前自己做的面试笔记,但是面试却异常顺利,三天闯到了三面,自己也不敢相信,三面玩感觉也良好,脑子里不得不想着一些“offer结算画面”,但是过了一会查看流程显示“流程终止”,我?哎,当时真的有苦说不出啊,也是一晚没睡。后面就逐渐开始褪去大厂梦了,看着曾经跟自己交流的牛油,朋友,认识的人,觉得他们技术不太如你,算法刷的没你多,进了大厂,但是这又如何呢?能力强不强不是你了说了,面试官说了算。也逐渐知道,不是你能力好就可以了,还得有运气,运气,运气。这个过程太累了,和自己和解吧,不用非得大厂,找个合适一点的就好,放轻松一点。今天有点心事睡不着,闲着想写一些自己的面试过程,勿喷。附上一张面试的情况,公司就不方便透露了。
怒卷的斯科特:八分运气两分实力
点赞 评论 收藏
分享
程序员牛肉:主要是因为小厂的资金本来就很吃紧,所以更喜欢有实习经历的同学。来了就能上手。 而大厂因为钱多,实习生一天三四百的就不算事。所以愿意培养你,在面试的时候也就不在乎你有没有实习(除非是同级别大厂的实习。) 按照你的简历来看,同质化太严重了。项目也很烂大街。 要么换项目,要么考研。 你现在选择工作的话,前景不是很好了。
点赞 评论 收藏
分享
一面052350min1.自我介绍2.在学校里的经历3.你希望测试开发岗位里的测试工作和开发工作占比是多少?4.实习拷打,详细拷打实习中做过的接口自动化项目5.为什么接口自动化项目选择pytest?6.设计测试用例会考虑哪些点?7.用过jekins的什么功能,了解过它底层的实现吗8.技术栈是?熟悉的编程语言?9.口述思路:二叉树的遍历10.手撕:二分查找11.浏览器输入url到展示页面的全流程?12.进程和线程13.死锁14.慢查询15.读过有关测试的技术书籍吗16.写测试自动化时用过python的哪些库?17.反问(作业帮直播业务,给学生直播上课之类的)&nbsp;二面052755min1.自我介绍2...
一笑而过2222:1. String和StringBuffer区别:String是不可变、线程安全(因不可变特性)的,每次操作会创建新对象,适合只读场景;StringBuffer是可变、线程安全(方法加锁)的,可直接修改对象,适用于多线程环境下频繁修改字符串的场景 。 2. Java的垃圾回收器:Java垃圾回收器是JVM自动管理内存的组件,基于分代收集理论,通过标记-清除、复制、标记-整理等算法回收不再使用的对象,常见类型有Serial、Parallel、CMS、G1等,分别适用于不同性能需求场景。 3. Java的序列化:Java序列化是将对象转换为字节序列以便存储或传输的机制,对象所属类需实现Serializable接口,反序列化可将字节流恢复为对象,常用于分布式通信、数据持久化和对象深拷贝等场景。
查看24道真题和解析 面经...
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务