目次
ソース分割
今回は、画面遷移をやります。
Webフレームワーク「gin」を使います
前回は「main.go」の「main」ファンクション内にすべての処理を書きました。
そのまま複数画面にして、かつ、処理を追加すると、とてもごちゃごちゃした可読性の低いソースになってしまいますので、先にソース分割します。
フォルダ構成はこんな感じにします。
templatesフォルダにHTMLを置くのは、前回と同じです。
controlsフォルダには、HTMLと1:1の関係になるGo言語のソースを置きます。
例えば、「index.html」に対応するGoのソースは「index.go」みたいにします。
routerフォルダには、routerの生成や各HTMLのロードなどの共通処理のGo言語のソースを置き、main.goには最低限の記述だけ残すようにしていきます。
ソース分割手順をサンプルで
今回HTML部分は変更しません。
前回のmain.goを分割していきます。
まず、前回のmain.goを再掲します。
package main import ( "net/http" "github.com/gin-gonic/gin" ) func main() { router := gin.Default() router.LoadHTMLGlob("templates/*.html") title := "値受け渡しのサンプル" type Data struct { Left string Right string } type datas []*Data var darr datas d1 := new(Data) d1.Left = "1行目の左側" d1.Right = "1行目の右側" darr = append(darr, d1) d2 := new(Data) d2.Left = "2行目の左側" d2.Right = "2行目の右側" darr = append(darr, d2) router.GET("/", func(ctx *gin.Context) { ctx.HTML(http.StatusOK, "index.html", gin.H{"title": title, "data": darr}) }) router.Run() }
この中のindex.html用のデータを変数にセットし、HTMLに渡す部分を、まず「controls/index.go」に切り出します。
package controls import ( "net/http" "github.com/gin-gonic/gin" ) func IndexAction(ctx *gin.Context) { title := "値受け渡しのサンプル" type Data struct { Left string Right string } type datas []*Data var darr datas d1 := new(Data) d1.Left = "1行目の左側" d1.Right = "1行目の右側" darr = append(darr, d1) d2 := new(Data) d2.Left = "2行目の左側" d2.Right = "2行目の右側" darr = append(darr, d2) ctx.HTML(http.StatusOK, "index.html", gin.H{"title": title, "data": darr}) }
functionの名前はわかりやすさ優先で「IndexAction」としました。
今度は、routerの設定を行う部分を「router/router.go]に切り出します。
package router import ( "webPrac/controls" "github.com/gin-gonic/gin" ) func GetRouter() *gin.Engine { r := gin.Default() r.LoadHTMLGlob("templates/*.html") r.GET("/", controls.IndexAction) return r }
前回初期作成「go mod init」でモジュール名を「webPrac」にしているので、インポートは「webPrac//controls」でその下の同じパッケージ内のfanctionを参照できます。
なお、ソースが別々でもパッケージが同じなら、ひとくくりに扱えます。
このように、処理を別ソースに切り出したことで、main.goのmainファンクションはこんなにシンプルになります。
package main import ( "webPrac/router" ) func main() { r := router.GetRouter() r.Run() }
これで実行すると、当然ながら、前回と同じ画面を表示します。
とりあえず、ここまではOKです。
画面遷移と?パラメータの受け渡し
画面をもうひとつ追加します。
ソース分割したので、画面追加は以下の手順になります。
- templatesの下にHTMLを追加する。
- 対応するGoプログラムを、controllsの下に追加する。
- ruter/ruter.goに上記のHTMLとGoのファンクションを追加する。
HTML作成
まずは、templatesの下に「inputSample.html」を作成します。
inputSample.html
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8" /> <meta name="description" content="HTML5 exsample" /> <meta name="author" content="boku" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" href="https://fonts.xz.style/serve/inter.css" /> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@exampledev/new.css@1.1.2/new.min.css" /> <title>Hello</title> </head> <body> <h1>{{.title}}</h1> <form method="POST" action="/"> <table> <tr> <th>適当な文字列を入力</th> <td><input type="text" name="sampletext" style="border: solid 1px" /></td> </tr> <tr> <td colspan="2"><input type="submit" value="画面遷移" /></td> </tr> </table> </form> </body> </html>
テキストボックスが一つあるだけの簡単な入力画面です。
画面を表示するGo言語のソース
この画面を表示するGo言語のソースはHTMLとあわせて「inputSample.go」とします。
package controls import ( "net/http" "github.com/gin-gonic/gin" ) func InputSampleAction(ctx *gin.Context) { title := ctx.Query("title") ctx.HTML(http.StatusOK, "inputSample.html", gin.H{"title": title}) }
GETで画面遷移とパラメータの受け渡し
そして、この画面を対応する定義を「router.go」に追加します。
r.GET("/inputSample", controls.InputSampleAction)
こうしておくことで、別のHTMLから以下のようにしてリンクで遷移できます。
<a href="/inputSample?title=何かを入力するサンプル">遷移します。</a>
このリンクには「?title=何かを入力するサンプル"」のように?でパラメータをつけています。
これを、Go言語の「InputSampleAction」内で受け取っているのが
title := ctx.Query("title")
の部分です。
リンクを使った画面遷移(GET)とパラメータの受け渡しは、このパターンでできます。
POSTで画面遷移と入力データの受け渡し
上記の「inputSample.html」の中に一つのテキストボックスと、submitボタンを置いてます。
<form method="POST" action="/">
としているので、ボタンを押すと「/」・・つまり、index.htmlにPOSTで遷移します。
これを受けるためには、まず「index.go」にPOST用のアクションを追加します。
func IndexPostAction(ctx *gin.Context) { title := "POSTで値を受け取るサンプル" txt := ctx.PostForm("sampletext") darr := strings.Split(txt, ",") ctx.HTML(http.StatusOK, "index.html", gin.H{"title": title,"data":darr}) }
入力内容を受け取る部分は
txt := ctx.PostForm("sampletext")
です。
sampletextという名前は、HTML中でテキストボックスを
<input type="text" name="sampletext" style="border: solid 1px" />
のようにnameを定義しているからです。
そして、POSTで「/」への遷移をうけられるように、router.goに、以下を追加します。
r.POST("/", controls.IndexPostAction)
Action内では、テキストボックスの入力値を受け取って、カンマ(,)をデリミタにして分割したstringの配列を、HTMLに渡してます。
それを受けてインデックスと同時に表示できるように「index.html」を修正しました。
{{range $index,$value := .data}} <tr> <th>インデックス{{$index}}</th> <td>{{$value}}</td> </tr> {{end}}
これで一通りはできました。
実行イメージです
main.goを実行して「http://localhost:8080/」でブラウザからアクセスすると。
ここから、「入力サンプルの画面に遷移します」リンクをクリックすると。
このテキストボックスに「ひとつめ,ふたつめ,みっつめ」と入力して「画面遷移」ボタンを押します。
よしよし、ちゃんと動いてます。
最後に上記にのせていないソース全文です
index.html の修正版です。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8" /> <meta name="description" content="HTML5 exsample" /> <meta name="author" content="boku" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" href="https://fonts.xz.style/serve/inter.css" /> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@exampledev/new.css@1.1.2/new.min.css" /> <title>Hello</title> </head> <body> <h1>{{.title}}</h1> <table> {{range $index,$value := .data}} <tr> <th>インデックス{{$index}}</th> <td>{{$value}}</td> </tr> {{end}} <tr> <td colspan="2"><a href="/inputSample?title=何かを入力するサンプル">入力サンプルの画面に遷移します。</a></td> </tr> </table> </body> </html>
次に「index.go」の修正版です
package controls import ( "net/http" "strings" "github.com/gin-gonic/gin" ) func IndexAction(ctx *gin.Context) { title := "GETで遷移してきたサンプル" type datas [] string var darr datas darr = append(darr, "GETで遷移してきたときの1行目") darr = append(darr, "GETで遷移してきたときの2行目のテキスト") ctx.HTML(http.StatusOK, "index.html", gin.H{"title": title, "data": darr}) } func IndexPostAction(ctx *gin.Context) { title := "POSTで値を受け取るサンプル" txt := ctx.PostForm("sampletext") darr := strings.Split(txt, ",") ctx.HTML(http.StatusOK, "index.html", gin.H{"title": title,"data":darr}) }
最後に「router.go」です。
package router import ( "webPrac/controls" "github.com/gin-gonic/gin" ) func GetRouter() *gin.Engine { r := gin.Default() r.LoadHTMLGlob("templates/*.html") r.GET("/", controls.IndexAction) r.POST("/", controls.IndexPostAction) r.GET("/inputSample", controls.InputSampleAction) return r }
今回はこんなところで。
ではでは。