yzbtdiy

yzbtdiy

github
bilibili

Golangのバックエンドデータのページ分割

フロントエンドでは、データのリクエストが多すぎる場合、データのページネーション表示を検討することができます。pageSize(ページごとに表示するデータの数)とpageNumber(ページ番号)の 2 つのパラメータを使用して制御することができます。

フロントエンドでのデータのリクエストパラメータ#

Ajax リクエストを送信する際に、psizepnumの 2 つのパラメータを渡します。psizeは 10 で、1 ページあたり 10 件のデータを返すことを期待しています。pnumは 1 で、1 ページ目のデータを返すことを期待しています。

http://localhost:8848/api/datalist?psize=10&pnum=1

バックエンドでのパラメータの取得と処理#

以下の HandleFunc#

リクエストの URL からpsizepnumの値を読み取ります。URL から取得した値は文字列型なので、まず整数型に変換してからデータベースの処理に渡します。

func DataListApi(w http.ResponseWriter, r *http.Request) {
	params := r.URL.Query()
	pageSize, _ := strconv.Atoi(params.Get("psize"))
	pageNum, _ := strconv.Atoi(params.Get("pnum"))
	dataList := GetDataFromDbByPages(pageSize, pageNum)
	if dataList != nil {
		jsonData, _ := json.Marshal(dataList)
		_, err := w.Write(jsonData)
		if err != nil {
			log.Println(err)
		}
	}
}

Gorm のクエリ操作#

指定された条件でデータベースからデータをクエリします。クエリが成功した場合、構造体の配列が返されます。データが見つからない場合は nil が返されます。オフセットは(pnum-1)*psizeの値で、返すデータの数はpsizeに制限されます。

func GetDataFromDbByPages(psize, pnum int) (dataList *[]UserDataModel) {
	result := db.Offset((pnum - 1) * psize).Limit(psize).Find(&dataList)
	if result.RowsAffected == 0 {
		log.Println("データの取得に失敗しました")
		return nil
	} else {
		return dataList
	}
}

完全なバックエンドのコード(デモ)#

package main

import (
	"encoding/json"
	"log"
	"net/http"
	"strconv"

	"github.com/glebarez/sqlite"
	"gorm.io/gorm"
)

// ローカルの8848ポートをリッスンし、/api/datalistからのリクエストを処理する
func main() {
	server := http.Server{
		Addr: "127.0.0.1:8848",
	}
	http.HandleFunc("/api/datalist", DataListApi)
	log.Println("サーバーは http://127.0.0.1:8848 で実行中です")
	if err := server.ListenAndServe(); err != nil {
		log.Println(err)
	}
}

// /api/datalistのリクエストを処理する。リクエストにはpsizeとpnumのパラメータが必要です。
func DataListApi(w http.ResponseWriter, r *http.Request) {
	params := r.URL.Query()
	pageSize, _ := strconv.Atoi(params.Get("psize"))
	pageNum, _ := strconv.Atoi(params.Get("pnum"))
	dataList := GetDataFromDbByPages(pageSize, pageNum)
	if dataList != nil {
		jsonData, _ := json.Marshal(dataList)
		_, err := w.Write(jsonData)
		if err != nil {
			log.Println(err)
		}
	}
}

// データベースに保存されるデータの構造体
type UserDataModel struct {
	Id   int    `gorm:"column:id;type:INTEGER NOT NULL;primaryKey;autoIncrement;"`
	Name string `gorm:"column:name;type:TEXT NOT NULL UNIQUE;"`
	Desc string `gorm:"column:desc;type:TEXT NOT NULL;"`
}

// テーブル名をカスタマイズ
func (UserDataModel) TableName() string {
	return "user_data"
}

var db *gorm.DB

// main関数の実行前にinitでsqliteデータベースを初期化する
func init() {
	var err error
	db, err = gorm.Open(sqlite.Open("./data.db"), &gorm.Config{})
	if err != nil {
		log.Fatal(err)
	}

	sqlDB, _ := db.DB()
	sqlDB.SetMaxOpenConns(1)

	tableInit(&UserDataModel{})
}

// テーブルが存在するかどうかをチェックし、存在しない場合は作成する
func tableInit(table interface{}) {
	if db.Migrator().HasTable(table) {
		return
	} else {
		db.Migrator().CreateTable(table)
		genTestData()
	}
}

// psizeとpnumに基づいてデータベースからデータを取得する
func GetDataFromDbByPages(psize, pnum int) (dataList *[]UserDataModel) {
	result := db.Offset((pnum - 1) * psize).Limit(psize).Find(&dataList)
	if result.RowsAffected == 0 {
		log.Println("データの取得に失敗しました")
		return nil
	} else {
		return dataList
	}
}

// テストデータを生成する(100件)
func genTestData() {
	for i := 1; i <= 100; i++ {
		testData := UserDataModel{
			Id:   i,
			Name: "user" + strconv.Itoa(i),
			Desc: "Hello, I'm user" + strconv.Itoa(i),
		}
		db.Create(&testData)
	}
}

テスト#

デモのダウンロード:https://yzbtdiy.lanzoul.com/iICXi0pung7c

初回実行時には、現在のディレクトリにdata.dbという名前の SQLite データベースが生成されます。

その後、user_dataテーブルが作成され、100 件のテストデータが挿入されます。

8848 ポートをリッスンし、データを取得するために/api/datalistにアクセスできます。psizepnumの 2 つのパラメータを渡す必要があります。

ブラウザでテストするか、コマンドラインでテストすることができます。

~ $ curl "http://127.0.0.1:8848/api/datalist?psize=10&pnum=1"
[{"Id":1,"Name":"user1","Desc":"Hello, I'm user1"},{"Id":2,"Name":"user2","Desc":"Hello, I'm user2"},{"Id":3,"Name":"user3","Desc":"Hello, I'm user3"},{"Id":4,"Name":"user4","Desc":"Hello, I'm user4"},{"Id":5,"Name":"user5","Desc":"Hello, I'm user5"},{"Id":6,"Name":"user6","Desc":"Hello, I'm user6"},{"Id":7,"Name":"user7","Desc":"Hello, I'm user7"},{"Id":8,"Name":"user8","Desc":"Hello, I'm user8"},{"Id":9,"Name":"user9","Desc":"Hello, I'm user9"},{"Id":10,"Name":"user10","Desc":"Hello, I'm user10"}]

~ $ curl "http://127.0.0.1:8848/api/datalist?psize=5&pnum=3"
[{"Id":11,"Name":"user11","Desc":"Hello, I'm user11"},{"Id":12,"Name":"user12","Desc":"Hello, I'm user12"},{"Id":13,"Name":"user13","Desc":"Hello, I'm user13"},{"Id":14,"Name":"user14","Desc":"Hello, I'm user14"},{"Id":15,"Name":"user15","Desc":"Hello, I'm user15"}]
読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。