GraphQL EP 5:從資料庫讀取資料並輸出
透過GraphQL查詢資料庫的資料
在【GraphQL EP 1:GraphQL API一種更簡單、靈活的資料輸出方式】文章中,輸出的資料是直接從程式或Query帶參數產生的,但更多的應用其實是從資料庫將資料讀取出來,所以本篇就是要分享如何如何使用GraphQL透過Spring Boot JPA向資料庫讀取資料。
實作本篇前,請先:
- 安裝資料庫:在CentOS 7安裝MariaDB
- 準備資料:Spring Boot EP 9:準備資料庫(MariaDB)及資料(市場指數及個股每日股價)
- 學會Spring Boot JPA與Hibernate:Spring Boot EP 10:透過Spring Data JPA與Hibernate讀取(select)資料庫
結構
本篇專案會建立幾個Package,其用途如下:
main/java/com.example.graphqldemo:
- entities:定義資料庫欄位的資料模型,與資料庫表格為對應關係,或是對應資料輸出的欄位。
- ids:定義entities內資料模型的主鍵(Key)。
- queries:實作GraphQL的Resolver,GraphQL Query所要輸出資料的函數都在此。
- repositories:實作Spring Data JPA之所在。
- services:
- interface:讀取資料庫的程式撰寫於此,不論使用Hibernate或其他方式。
- implements:實作interface service,對應repositories。
main/
- resources:創建副檔名為”.graphqls”的檔案,裏面描述了如何對GraphQL操作Query與輸入/輸出的資料。
實作
第1步:先看一下資料表”MARKETS”這張Table。
第2步:於entities建立”MarketEntity.java”。
package com.example.graphqldemo.entities;
import lombok.*;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Getter
@Setter
@Data
@Entity
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "MARKETS")
public class MarketEntity {
@Id
@Column(name = "MARKET_CODE", nullable = false)
private String MarketCode;
@Column(name = "MARKET_NAME", nullable = false)
private String MarketName;
}
第3步:於repositories建立”MarketRepository.java”。
package com.example.graphqldemo.repositories;
import com.example.graphqldemo.entities.MarketEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface MarketRepository extends JpaRepository<MarketEntity, String> {
}
第4步:於services建立”MarketService.java”,並將操作資料庫的SQL語法撰寫於此。
package com.example.graphqldemo.services;
import com.example.graphqldemo.entities.MarketEntity;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
public interface MarketService {
@Query(value = "SELECT MARKET_CODE, MARKET_NAME FROM STOCK_MARKET.MARKETS;", nativeQuery = true)
List<MarketEntity> getAll();
@Query(value = "SELECT MARKET_CODE, MARKET_NAME FROM STOCK_MARKET.MARKETS WHERE MARKET_CODE=:MARKET_CODE", nativeQuery = true)
MarketEntity getByMarketCode(@Param("MARKET_CODE") String MarketCode);
}
第5步:於services建立”MarketServiceImpl.java”,實作”MarketService”。
package com.example.graphqldemo.services;
import com.example.graphqldemo.entities.MarketEntity;
import com.example.graphqldemo.repositories.MarketRepository;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
@AllArgsConstructor
public class MarketServiceImpl implements MarketService{
private final MarketRepository marketRepository;
@Override
public List<MarketEntity> getAll() {
return marketRepository.findAll();
}
@Override
public MarketEntity getByMarketCode(String MarketCode) {
Optional<MarketEntity> marketEntity = marketRepository.findById(MarketCode);
return marketEntity.orElse(null);
}
}
第6步:於queries建立”MarketQuery.java”,實作GraphQLQueryResolver。
package com.example.graphqldemo.queries;
import com.example.graphqldemo.entities.MarketEntity;
import com.example.graphqldemo.services.MarketService;
import graphql.kickstart.tools.GraphQLQueryResolver;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@RequiredArgsConstructor
public class MarketQuery implements GraphQLQueryResolver {
private final MarketService marketService;
public List<MarketEntity> Markets(){
return marketService.getAll();
}
public MarketEntity Market(String MarketCode){
return marketService.getByMarketCode(MarketCode);
}
}
第7步:於resources建立”market.graphqls”,對應”MarketQuery.java”所實作的GraphQLQueryResolver查詢函數。
# 定義Market的資料模型,對應資料庫的欄位
type Market {
MarketCode: String!
MarketName: String
}
# 對應GraphQLQueryResolver的函數設計查詢語法
extend type Query {
Markets: [Market]!
Market(MarketCode: String!): Market
}
第8步:透過GraphiQL的畫面可以看到剛剛定義的兩個API,如下圖紅匡處所示。
第8步:在GraphiQL下GraphQL Query,可以選擇需要的欄位,如下圖,將所有欄位都顯示出來。
也可以指定MarketName這個欄位:
~ END ~