RPC选型入门测试系列文章
GraphQL是一种用于API开发的查询语言和运行时环境。它由Facebook开发并于2015年开源。GraphQL的主要目标是提供一种更高效、灵活和易于使用的方式来获取和操作数据。与传统的RESTful API相比,GraphQL允许客户端精确地指定需要的数据,并减少了不必要的网络传输和数据处理。
采用GraphQL,甚至不需要有任何的接口文档,在定义了Schema之后,服务端实现Schema,客户端可以查看Schema,然后构建出自己需要的查询请求来获得自己需要的数据。
type Product {
id: ID!
info: String!
price: Float
}
12345
在此示例中,声明了Product对象类型,定义了3 个字段:
id:非空 ID 类型。
info:非空字符串类型。
price:浮点型。
interface Product {
id: ID!
info: String!
price: Float
}
12345
enum Status {
Yes
No
}
type Product {
id: ID!
info: String!
price: Float
stat: Status
}
12345678910
input BookInput {
isbn: ID!
title: String!
pages: Int
authorIdCardNo: String
}
123456
type Product {
id: ID!
info: String
price: Float
images: [String]
}
123456
#schema.graphqls定义操作
type Query {
allBooks: [Book]!
bookByIsbn(isbn: ID): Book
}
# 接口查询语法
query{
allBooks {
title
author {
name
age
}
}
}
12345678910111213141516
#schema.graphqls定义操作
type Mutation {
createBook(bookInput: BookInput): Book
createAuthor(authorInput: AuthorInput): Author
}
# mutation{
# createAuthor(authorInput:{
# idCardNo: "341234567891234567",
# name:"test1",
# age:38
# }
# ){
# name
# age
# }
# }
GraphQL只是一种架构设计,具体的实现需要各个技术平台自己实现,目前主流的开发语言基本都已经有现成的类库可以使用,GraphQL Java就是Java平台的实现。
spring-graphql中定义的核心注解如下:
GraphQL对应的schema.graphql定义文件
schema {
query: Query,
mutation: Mutation,
}
type Query {
getUserById(id:Int) : [User],
}
input UserInput {
username : String,
password : String,
name : String,
}
type Mutation {
createUser(userInput: UserInput): User,
updateUser(id: Int!, userInput: UserInput): User,
deleteUser(id: ID!): Int,
}
type User {
id : ID!,
username : String,
password : String,
name : String,
}
pom.xml依赖包文件
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-jpaartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-graphqlartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.23version>
dependency>
<dependency>
<groupId>com.graphql-javagroupId>
<artifactId>graphql-java-extended-scalarsartifactId>
<version>19.1version>
dependency>
dependencies>
project>
对应的数据库实体类
package com.example.graphql.dao;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String username;
private String password;
private String name;
public User(String username, String password, String name) {
this.username = username;
this.password = password;
this.name = name;
}
}
GraphQL对应的输入类
package com.example.graphql.dao;
import lombok.Data;
import java.time.OffsetDateTime;
@Data
public class UserInput {
private String username;
private String password;
private String name;
}
在Spring Data JPA中使用JpaRepository接口类完成对数据库的操作
在JpaRepository
中,当保存的实体类主键ID在数据库中存在时进行修改操作,不存在则进行保存。
@Autowired
private UserInfoRepository userInfoRepository;
public void addUserInfo() {
UserInfo userInfo = new UserInfo();
userInfo.setId("jHfnKlsCvN");
userInfo.setLoginName("登录名");
userInfo.setPassword("123456");
userInfo.setAge(18);
// 保存或修改用户信息, 并返回用户实体类
UserInfo save = userInfoRepository.save(userInfo);
}
@Autowired
private UserInfoRepository userInfoRepository;
public void deleteUserInfo() {
// 根据实体类主键删除
userInfoRepository.deleteById("111");
}
在JpaRepository
中根据某一个字段或者某几个字段查询时,就使用findBy
方法。
这里给个例子,假设,我想根据loginName
查询用户信息,就可以用findByLoginName
查询用户信息,如果有多个条件后面就继续拼接AndXXX
。
假设,我想查询loginName
等于某值,并且password
等于某值的,就可以使用findByLoginNameAndPassword
。
public interface UserInfoRepository extends JpaRepository<UserInfo, String> {
// 根据登录名查询用户信息
UserInfo findByLoginName(String loginName);
// 根据登录名和密码查询用户信息
UserInfo findByLoginNameAndPassword(String loginName, String password);
}
在JpaRepository
中根据某一个字段或者某几个字段查询时,就使用findAllBy
方法,而接口根据某个条件查询写法跟查询单个信息时一样。
这里给个例子,假设,我想查询loginName
等于某值的所有用户信息时,就写做findAllByLoginName
。
public interface UserInfoRepository extends JpaRepository<UserInfo, String> {
// 查询所有登录名叫做XXX的用户
List<UserInfo> findAllByLoginName(String loginName);
}
对应的数据库操作类
```java
package com.example.graphql.servise.Repository;
import com.example.graphql.dao.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@Repository
//必须声明事务,不然删除报错
@Transactional
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findById(int id);
// List updateById(int id);
int deleteById(int id);
}
对外服务接口类
在service层中实现查询和删除:
package com.example.graphql.servise;
import com.example.graphql.dao.User;
import com.example.graphql.servise.Repository.UserRepository;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserService {
@Resource
private UserRepository userRepository ;
public List<User> queryUser(int id) {
List<User> user = userRepository.findById(id);
return user;
}
public int deleteUser(int id) {
int bool = userRepository.deleteById(id);
return bool;
}
}
在controller层中配置增删改查接口:
package com.example.graphql.controller;
import com.example.graphql.dao.User;
import com.example.graphql.dao.UserInput;
import com.example.graphql.servise.Repository.UserRepository;
import com.example.graphql.servise.UserService;
import jakarta.annotation.Resource;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.MutationMapping;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/user")
@CrossOrigin
public class UserController {
@Resource
private UserService userService;
@Resource
private UserRepository userRepository ;
@QueryMapping
public List getUserById(@Argument int id) {
return userService.queryUser(id);
}
@MutationMapping
public int deleteUser(@Argument int id) {
return userService.deleteUser(id);
}
@MutationMapping
public User createUser(@Argument UserInput userInput) {
User user = new User();
System.out.println(userRepository);
System.out.println(user);
BeanUtils.copyProperties(userInput,user);
userRepository.save(user);
return user;
}
@MutationMapping
public User updateUser(@Argument int id,@Argument UserInput userInput) {
System.out.println(userInput);
User user = new User();
user.setId(id);
BeanUtils.copyProperties(userInput,user);
System.out.println(user);
userRepository.save(user);
return user;
}
}
使用Spring for GraphQL试用了GraphQL后,它实现按需取数据的功能。服务器开发人员和前端开发人员可以通过schema.graphqls定义文件,协定好接口和数据,省掉写接口文档的工作。
客户端可以通过一次请求获取多个数据资源,而不需要发起多个请求。相对于传统的RESTful API,GraphQL的实现和后端处理逻辑可能更加复杂。需要编写解析器、验证查询、处理复杂的字段解析和数据获取等。