這是使用 SpringBoot 並將資料放在 MySQL 的 GraphQL sample
建立專案
在 Spring Initializer 產生 maven project,在 Dependencies 的部分增加
- Lombok
- MySQL Driver
- Spring Data JPA
- Spring Web
取得 project 後,再增加 Graphql dependencies
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-spring-boot-starter</artifactId>
<version>5.0.2</version>
</dependency>
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-java-tools</artifactId>
<version>5.2.4</version>
</dependency>
Data Model
因應 MySQL 的 Table,需要先產生 ORM 的 Data Model
Post.java
package com.example.writeup.model;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.persistence.*;
import java.util.Date;
@Getter
@Setter
@NoArgsConstructor
@Entity
@Table(name = "USER")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "USER_ID")
private Integer userId;
@Column(name = "FIRST_NAME")
private String firstName;
@Column(name = "LAST_NAME")
private String lastName;
@Column(name = "DOB")
private Date dob;
@Column(name = "ADDRESS")
private String address;
@Column(name = "POST_ID")
private Integer postId;
public User(String firstName, String lastName, Date dob, String address, Integer postId) {
this.firstName = firstName;
this.lastName = lastName;
this.dob = dob;
this.address = address;
this.postId = postId;
}
}
User.java
package com.example.writeup.model;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.persistence.*;
import java.util.Date;
@Getter
@Setter
@NoArgsConstructor
@Entity
@Table(name = "USER")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "USER_ID")
private Integer userId;
@Column(name = "FIRST_NAME")
private String firstName;
@Column(name = "LAST_NAME")
private String lastName;
@Column(name = "DOB")
private Date dob;
@Column(name = "ADDRESS")
private String address;
@Column(name = "POST_ID")
private Integer postId;
public User(String firstName, String lastName, Date dob, String address, Integer postId) {
this.firstName = firstName;
this.lastName = lastName;
this.dob = dob;
this.address = address;
this.postId = postId;
}
}
Repository
這是用來跟資料庫建立跟剛剛的 Data Model 的關聯
PostRepository.java
package com.example.writeup.repository;
import com.example.writeup.model.Post;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface PostRepository extends JpaRepository<Post,Integer> {
}
UserRepository.java
package com.example.writeup.repository;
import com.example.writeup.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
@Repository
public interface UserRepository extends JpaRepository<User, Integer> {
@Transactional
@Modifying
@Query(value = "UPDATE user SET address = ?1 WHERE user_id = ?2 ", nativeQuery = true)
int updateUserAddress(String address, Integer user_id);
}
Note: 原文說可以改為繼承 CrudRepository,但 find 會回傳一般的 List,但 JpaRepository 會回傳 iterable list ref: What is difference between CrudRepository and JpaRepository interfaces in Spring Data JPA?
DataLoader
用在 init project 時,會自動產生 MySQL table 及測試資料
DataLoader.java
package com.example.writeup.service;
import com.example.writeup.model.Post;
import com.example.writeup.model.User;
import com.example.writeup.repository.PostRepository;
import com.example.writeup.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.Calendar;
import java.util.Date;
import java.util.concurrent.ThreadLocalRandom;
@Service
public class DataLoader {
@Autowired
private UserRepository userRepository;
@Autowired
private PostRepository postRepository;
@PostConstruct
public void loadData(){
User user1 = new User("Yasas" ,"Sandeepa",DataLoader.getRandomDate(),"Mount Pleasant Estate Galle",1);
User user2 = new User("Sahan" ,"Rambukkna",DataLoader.getRandomDate(),"Delkanda Nugegoda",2);
User user3 = new User("Ranuk" ,"Silva",DataLoader.getRandomDate(),"Yalawatta gampaha",3);
Post post1 = new Post("Graphql with SpringBoot",DataLoader.getRandomDate());
Post post2 = new Post("Flutter with Firebase",DataLoader.getRandomDate());
Post post3 = new Post("Nodejs Authentication with JWT",DataLoader.getRandomDate());
postRepository.save(post1);
postRepository.save(post2);
postRepository.save(post3);
userRepository.save(user1);
userRepository.save(user2);
userRepository.save(user3);
}
public static Date getRandomDate(){
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, 1990);
calendar.set(Calendar.MONTH, 1);
calendar.set(Calendar.DATE, 2);
Date date1 = calendar.getTime();
calendar.set(Calendar.YEAR, 1996);
Date date2 = calendar.getTime();
long startMillis = date1.getTime();
long endMillis = date2.getTime();
long randomMillisSinceEpoch = ThreadLocalRandom
.current()
.nextLong(startMillis, endMillis);
return new Date(randomMillisSinceEpoch);
}
}
application.properties
產生設定檔
server.port=7000
#mysql properties
spring.jpa.generate-ddl=true
spring.datasource.url=jdbc:mysql://localhost/writeup
spring.datasource.username=user
spring.datasource.password=password
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=create
#graphql properties
graphql.servlet.corsEnabled=true
graphql.servlet.mapping=/graphql
graphql.servlet.enabled=true
GraphQL
- 一開始的 pom.xml 已增加了相關 dependencies
- 剛剛的 application.properties 增加 graphql.servlet 的設定
- 建立 GraphQL schema
schema.graphqls
schema {
query: Query,
mutation: Mutation,
}
type Query{
# Fetch All Users
getAllUsers:[User]
}
type Mutation {
# Update the user address
updateUserAddress(userId:Int,address:String): User
}
type User {
userId : ID!,
firstName :String,
lastName :String,
dob:String,
address:String,
postId : Int,
}
- 產生 Service
UserService.java
package com.example.writeup.service;
import com.coxautodev.graphql.tools.GraphQLMutationResolver;
import com.coxautodev.graphql.tools.GraphQLQueryResolver;
import com.example.writeup.model.User;
import com.example.writeup.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserService implements GraphQLQueryResolver, GraphQLMutationResolver {
@Autowired
private UserRepository userRepository;
public List<User> getAllUsers() {
return userRepository.findAll();
}
public User updateUserAddress(Integer userId, String address) throws Exception {
try {
userRepository.updateUserAddress(address, userId);
User user = userRepository.findById(userId).get();
return user;
} catch (Exception e) {
throw new Exception(e);
}
}
}
WriteupApplication
package com.example.writeup;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class WriteupApplication {
public static void main(String[] args) {
SpringApplication.run(WriteupApplication.class, args);
}
}
Altair
這是 GraphQL 的測試工具,這邊安裝了 Chrome Extension 版本
網址為 http://localhost:7000/graphql/ ,點 Docs 可取得 Query 及 Mutation 兩個介面
References
[譯]使用 SpringBoot 和 MySQL 構建 GraphQL 服務端應用程式
Build a GraphQL Server With Spring Boot and MySQL
Altair Altair GraphQL Client helps you debug GraphQL queries and implementations
沒有留言:
張貼留言