graphQL与数据库、web整合及实现graphql分页,动态传参
程序员文章站
2022-05-16 10:29:56
...
数据库中的数据:https://blog.csdn.net/qq_26896085/article/details/104843889
mapper包下
EmployeeMapper.java
这里使用了Mybatis-plus,如果只是对单表进行查询,接口继承BaseMapper即可
package com.woodie.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.woodie.entity.Employee;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
// 这里通过想在.xml文件中写sql语句的方式查询数据则必须使用@Mapper注解
@Mapper
public interface EmployeeMapper extends BaseMapper<Employee> {
// 这个接口继承了BaseMapper,则其包含了mybatis-plus定义的方法
// 通过在xml中写sql,通过这里的方法查询数据
Employee queryById();
}
实体类
Employee .java
package com.woodie.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@TableName("employees")
public class Employee {
// 指定表的id
// 通过type = IdType.AUTO设置id的自动增长, 由于表employees没有设置id为自动增长,因此这里不能设置这个参数,否则报错
//@TableId(value = "emp_no", type = IdType.AUTO)
@TableId(value = "emp_no")
Integer empNo;
Date birthDate;
String firstName;
String lastName;
Date hireDate;
String gender;
}
Pagination.java
用于存放 分页时的数据的总条数,当前页面,当前页面的数据条数,总页
package com.woodie.vo;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Pagination {
Long current;
Long pageSize;
Long total;
Long totalPage;
}
TableResult.java
用于存放返回数据
package com.woodie.vo;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class TableResult<T> {
List<T> list;
Pagination pagination;
}
EmployeeServiceImpl .java
用于查询数据库
package com.woodie.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.woodie.dao.EmployeeDao;
import com.woodie.entity.Employee;
import com.woodie.mapper.EmployeeMapper;
import com.woodie.service.EmployeeService;
import com.woodie.vo.Pagination;
import com.woodie.vo.TableResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class EmployeeServiceImpl implements EmployeeService {
@Autowired
EmployeeMapper employeeMapper;
@Override
public Employee queryById(int id) {
// return employeeMapper.queryById();
return employeeMapper.selectById(id);
}
@Override
public TableResult<Employee> queryListByPage(int page, int size) {
Page employeePage = new Page(page, size);
IPage<Employee> iPage = this.employeeMapper.selectPage(employeePage, null);
Pagination pagination = Pagination.builder().current(iPage.getCurrent()).pageSize(iPage.getSize()).total(iPage.getTotal()).totalPage(iPage.getPages()).build();
List<Employee> list = iPage.getRecords();
TableResult<Employee> tableResult = new TableResult<>();
tableResult.setList(list);
tableResult.setPagination(pagination);
return tableResult;
}
}
DateScalarType.java
这个类用于自定义graphql查询的标量,自定义的标量为Date,用于处理数据中的日期数据
package com.woodie.modifyoriginal;
import graphql.schema.*;
import java.text.SimpleDateFormat;
import java.util.Date;
// 需要继承GraphQLScalarType
public class DateScalarType extends GraphQLScalarType {
public DateScalarType() {
super("Date", "Date value", new Coercing<String, String>() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
public String serialize(Object input) {
return sdf.format(input);
}
public String parseValue(Object input) {
return this.serialize(sdf.format(input));
}
public String parseLiteral(Object input) {
if (!(input instanceof Date)) {
throw new CoercingParseLiteralException("Expected AST type 'Date' but was ");
} else {
return sdf.format(input);
}
}
});
}
}
GraphQLProvider.java
用于提供graphql支持
package com.woodie.graphql;
import com.woodie.modifyoriginal.DateScalarType;
import graphql.GraphQL;
import graphql.Scalars;
import graphql.schema.GraphQLSchema;
import graphql.schema.idl.RuntimeWiring;
import graphql.schema.idl.SchemaGenerator;
import graphql.schema.idl.SchemaParser;
import graphql.schema.idl.TypeDefinitionRegistry;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.List;
/**
* 实现的功能:将Graphql对象载入到Spring容器,并完成GraphQL对象的初始化功能
*/
@Component
public class GraphQLProvider {
private GraphQL graphQL;
@Autowired
private List<MyDataFetcher> myDataFetchers;
// 实现对graphql对象的初始化
@PostConstruct
public void init() throws Exception {
try {
InputStream inputStream = GraphQLProvider.class.getClassLoader().getResourceAsStream("employee.graphqls");
String content = IOUtils.toString(inputStream, "UTF-8");
this.graphQL = GraphQL.newGraphQL(buildGraphQLSchema(content)).build();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
private GraphQLSchema buildGraphQLSchema(String content){
TypeDefinitionRegistry typeRegistry = new SchemaParser().parse(content);
return new SchemaGenerator().makeExecutableSchema(typeRegistry,buildWiring());
}
private RuntimeWiring buildWiring(){
return RuntimeWiring.newRuntimeWiring()
.type("EmployeeQuery", builder -> {
for (MyDataFetcher myDataFetcher : myDataFetchers) {
builder.dataFetcher(myDataFetcher.filedName(), environment -> myDataFetcher.dataFetcher(environment));
}
return builder;
}
)
.scalar(new DateScalarType())
.build();
}
@Bean
public GraphQL graphQL(){
return this.graphQL;
}
}
MyDataFetcher.java
用于提供数据fileName, environment,当有新的查询时,实现这个接口即可,而不需要更改GraphQLProvider.java中的代码
package com.woodie.graphql;
import graphql.schema.DataFetchingEnvironment;
public interface MyDataFetcher {
/**
* GraphQL中查询的名称, 对应下面的employee
*
* type EmployeeQuery {
* employee(empNo:Int) : Employee
* }
* @return
*/
String filedName();
/**
* 数据的查询
* @param environment
* @return
*/
Object dataFetcher(DataFetchingEnvironment environment);
}
EmployeeListPageGraphQL.java
用于批量查询employee中的数据, 并进行分页
package com.woodie.graphql;
import com.woodie.service.EmployeeService;
import graphql.schema.DataFetchingEnvironment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class EmployeeListPageGraphQL implements MyDataFetcher{
@Autowired
EmployeeService employeeService;
@Override
public String filedName() {
return "employeeListPage";
}
@Override
public Object dataFetcher(DataFetchingEnvironment environment) {
Integer page = environment.getArgument("page");
Integer size = environment.getArgument("size");
if (null == page) {
page = 1;
}
if (null == size) {
size = 10;
}
return this.employeeService.queryListByPage(page, size);
}
}
EmployeeGraphQL.java
通过id进行查询employee中的单条数据
package com.woodie.graphql;
import com.woodie.service.EmployeeService;
import graphql.schema.DataFetchingEnvironment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class EmployeeGraphQL implements MyDataFetcher{
@Autowired
EmployeeService employeeService;
@Override
public String filedName() {
return "employee";
}
@Override
public Object dataFetcher(DataFetchingEnvironment environment) {
Integer id = environment.getArgument("empNo");
return this.employeeService.queryById(id);
}
}
EmployeeController.java
这里支持get,post两种请求,并支持graphql动态传参
package com.woodie.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import graphql.ExecutionInput;
import graphql.GraphQL;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@RequestMapping("employee")
@Controller
public class EmployeeController {
@Autowired
private GraphQL graphQL;
/**
* graphql 查询的实现
* @param query
* @return
*/
@GetMapping
@ResponseBody
public Map<String, Object> query(@RequestParam("query")String query,
@RequestParam(value = "variables", required = false) String variables,
@RequestParam(value = "operationName", required = false) String operationName){
Map<String, Object> variablesMap = new HashMap<>();
if (StringUtils.isNotEmpty(variables)) {
JSONObject json = JSON.parseObject(variables);
for (String key : json.keySet()) {
variablesMap.put(key, json.get(key));
}
}
return getStringObjectMap(query, variablesMap, operationName);
}
@PostMapping
@ResponseBody
public Map<String, Object> postQuery(@RequestBody Map<String, Object> param){
String query = (String) param.get("query");
String operationName = (String) param.get("operationName");
Map variablesMap = (Map) param.get("variables");
return getStringObjectMap(query, variablesMap, operationName);
}
private Map<String, Object> getStringObjectMap(String query, Map variablesMap, String operationName) {
// 查看源码,点击下面的graphQL.execute
// ExecutionResult result = graphQL.execute(query);
ExecutionInput executionInput = ExecutionInput.newExecutionInput()
.query(query)
.variables(variablesMap)
.operationName(operationName)
.build();
return this.graphQL.execute(executionInput).toSpecification();
}
}
employee.graphql配置文件
scalar Date
scalar Long
schema {
query: EmployeeQuery
}
type EmployeeQuery {
employee(empNo:Int) : Employee
employeeListPage(page: Int, size: Int): TableResult
}
type Employee {
empNo: Int
birthDate: Date
firstName: String
lastName: String
hireDate: Date
gender: String
}
type TableResult {
list: [Employee]
pagination: Pagination
}
type Pagination {
current: Long
pageSize: Long
total: Long
totalPage: Long
}
启动类
package com.woodie;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
//@MapperScan("com.woodie.mapper")
public class SpringBootStart {
/**
* 使用mybatisplus的分页插件,
* @return
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
public static void main(String[] args) {
SpringApplication.run(SpringBootStart.class, args);
}
}
测试
1、post请求,参数写死,分页查询employee的list
2、post请求,动态传参,分页查询employee的list
3、get请求,参数写死,根据id进行查询信息
4、get请求,动态传参, 根据id进行查询信息