GraphQL+SpringBoot+Mybatisplus示例demo
发表于更新于
字数总计:1.6k阅读时长:7分钟阅读量: 北京
前言
GraphQL基本介绍可见文章:https://blog.liyi.xyz/posts/c6f3.html
1 配置
1.1 依赖导入
导入graphql、mysql、Mybatisplus相关依赖:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>
<dependency> <groupId>com.graphql-java-kickstart</groupId> <artifactId>graphql-spring-boot-starter</artifactId> <version>14.1.0</version> </dependency>
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.32</version> <scope>runtime</scope> </dependency>
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3.1</version> </dependency>
|
1.2 graphql的schema创建
在resources/graphql创建root.graphqls文件,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| type Query { bookById(id: ID!): Book }
type Book{ id: ID name: String pageCount: Int author: Author }
type Author{ id: ID firstName: String lastName: String sex: Int }
|
这个Schema定义了一个顶级字段(在Query类型中):bookById,它返回指定书籍的详情。
它也定义了类型Book,包含字段:id、name、pageCount、author,author的类型是Author。
上面用来描述Schema的专用语言叫做Schema Definition Language 或者叫DSL。更多细节可以查看:https://graphql.org/learn/schema/

1.3 项目yaml配置
配置文件:application.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai username: root password: xxxx sql: init: mode: always schema-locations: classpath:db/schema-v1.0.sql data-locations: classpath:db/data-v1.0.sql server: port: 9090 graphql: servlet: mapping: /graphql enabled: true corsEnabled: true tools: schema-location-pattern: graphql/*.graphqls graphiql: enabled: true playground: enabled: true logging: level: com.liyitongxue.graphql.dao: DEBUG
|
1.4 数据库
t_book、t_author两张表的数据如下

2 项目代码
项目结构结构如下图所示:
2.1 config
MybatisPlusConfig.java:
1 2 3 4
| @Configuration @MapperScan("com.liyitongxue.graphql.dao") public class MybatisPlusConfig { }
|
2.2 model
书籍实体类Book.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| @TableName("t_book") @Data @Builder @NoArgsConstructor @AllArgsConstructor public class Book {
@TableId(type = IdType.AUTO) private String id;
@TableField("name") private String name;
@TableField("pageCount") private int pageCount;
@TableField("authorId") private String authorId; }
|
作者实体类Author.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| @TableName("t_author") @Data @Builder @NoArgsConstructor @AllArgsConstructor public class Author {
@TableId(type = IdType.AUTO) private String id;
@TableField("firstName") private String firstName;
@TableField("lastName") private String lastName;
@TableField("sex") private int sex; }
|
2.3 dto
创建对应graphql中声明的java实体类BookDto.java:
1 2 3 4 5 6 7
| @Data public class BookDto { String id; String name; int pageCount; Author author; }
|
2.4 mapper
BookMapper.java:
1 2 3
| @Mapper public interface BookMapper extends BaseMapper<Book> { }
|
AuthorMapper.java:
1 2 3
| @Mapper public interface AuthorMapper extends BaseMapper<Author> { }
|
2.5 service
IBookService.java:
1 2 3
| public interface IBookService{ BookDto bookById(String id); }
|
BookServiceImpl.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @Service public class BookServiceImpl implements IBookService { @Resource private BookMapper bookMapper;
@Resource private AuthorMapper authorMapper;
@Override public BookDto bookById(String id) { BookDto bookDto = new BookDto(); Book book = bookMapper.selectById(id); bookDto.setId(book.getId()); bookDto.setName(book.getName()); bookDto.setPageCount(book.getPageCount());
Author author = authorMapper.selectById(book.getAuthorId()); bookDto.setAuthor(author);
return bookDto; } }
|
2.6 datafetcher
BookDataFetcher.java:
1 2 3 4 5 6 7 8 9
| @Component public class BookDataFetcher { @Resource private IBookService bookService;
public Object bookById(DataFetchingEnvironment environment) { return bookService.bookById(environment.getArgument("id")); } }
|
2.7 provider
GraphQLProvider.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| @Component public class GraphQLProvider { private final BookDataFetcher bookDataFetcher;
@Autowired public GraphQLProvider(BookDataFetcher bookDataFetcher) { this.bookDataFetcher = bookDataFetcher; }
@Bean public GraphQL graphQL() throws IOException { TypeDefinitionRegistry typeRegistry = new TypeDefinitionRegistry(); SchemaParser schemaParser = new SchemaParser(); String[] schemaArr = {"root"}; for (String str : schemaArr) { typeRegistry.merge(schemaParser.parse(new ClassPathResource("graphql/" + str + ".graphqls").getInputStream())); }
RuntimeWiring runtimeWiring = buildWiring(); SchemaGenerator schemaGenerator = new SchemaGenerator(); GraphQLSchema graphQLSchema = schemaGenerator.makeExecutableSchema(typeRegistry, runtimeWiring); return GraphQL.newGraphQL(graphQLSchema).build(); }
private RuntimeWiring buildWiring() { return RuntimeWiring.newRuntimeWiring() .type("Query", builder -> builder .dataFetcher("bookById", environment -> bookDataFetcher.bookById(environment)) ) .build(); } }
|
2.8 controller
BookController.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| @CrossOrigin @RestController @Slf4j @RequestMapping("/graphql") public class BookController { private final GraphQL graphql; private final ObjectMapper objectMapper;
@Autowired public BookController(GraphQL graphql, ObjectMapper objectMapper) { this.graphql = graphql; this.objectMapper = objectMapper; }
@GetMapping public Map<String, Object> graphqlGET(@RequestParam("query") String query, @RequestParam(value = "operationName", defaultValue = "") String operationName, @RequestParam(value = "variables", defaultValue = "{}") String variablesJson ) throws IOException { Map<String, Object> variables = new LinkedHashMap<>(); if (variablesJson != null) { variables = objectMapper.readValue(variablesJson, new TypeReference<Map<String, Object>>() { }); }
return executeGraphqlQuery(query, operationName, variables); }
@PostMapping public Map<String, Object> graphqlPOST(@RequestBody Map<String, Object> body) { String query = (String) body.get("query"); if (query == null) { query = ""; } String operationName = (String) body.get("operationName"); Map<String, Object> variables = (Map<String, Object>) body.get("variables"); if (variables == null) { variables = new LinkedHashMap<>(); } return executeGraphqlQuery(query, operationName, variables); }
private Map<String, Object> executeGraphqlQuery(String query, String operationName, Map<String, Object> variables) { ExecutionInput executionInput = ExecutionInput.newExecutionInput() .query(query) .operationName(operationName) .variables(variables) .build(); return graphql.execute(executionInput).toSpecification(); } }
|
3 浏览器可视化界面测试
启动SpringBoot后,进行图形化界面测试
浏览器访问:http://localhost:9090/playground,就会进入playground图形界面
浏览器访问:http://localhost:9090/graphiql,就会进入graphiql图形界面
输入以下GraphQL查询语句进行查询:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| # Write your query or mutation here query{ bookById(id: "book-1"){ id name pageCount author{ id firstName lastName sex } } }
|
查询结果如下:
可以看见查询结果中显示的字段与左侧需要查询的字段一致,如果需要删减字段,可在左侧直接进行删减

DOCS可以查看定义的查询

SCHEMA可以查看定义的对象类型详细信息

4 接口测试工具请求测试
此处为Apipost进行测试,Postman同理
4.1 GET请求

4.2 POST请求

参考链接
https://blog.csdn.net/LookOutThe/article/details/121673944
https://juejin.cn/post/6844904051860045831