演習a4

text/templateパッケージについて,極々単純なWebアプリケーションで演習します.

演習(補足:templateパッケージ)

(1)

  • Webブラウザからアクセスすると,名前を入力するフォームを表示し,フォームに名前を入力してSayHelloボタンをクリックすると,"Hello, ○○"と表示するhttpサーバ(Webサーバ)を作成せよ.このサービスのポートは123456とする.

(2)

  • Webブラウザからアクセスすると,名前と言語を入力するフォームを表示し,フォームに入力して,SayHelloボタンをクリックすると,指定された言語であいさつするhttpサーバ(Webサーバ)を作成せよ.
  • 言語は,英語,日本語,中国語,韓国語,エスペラント語とし,それぞれ,"Hello,○○","こんにちは,○○","你好 ○○","안녕하세요?○○","Bonan tagon,○○"と表示するものとする.(○○は入力した名前)

解答例(1)

ソースファイル (a4-1-template.go)

  1. package main
  2. import (
  3. "text/template"
  4. "net/http"
  5. "fmt"
  6. "log"
  7. )
  8. func helloHandler(w http.ResponseWriter, r *http.Request) {
  9. fmt.Println("hello")
  10. w.Header().Set("Content-Type", "text/html") // content-typeの指定
  11. t := template.Must(template.ParseFiles("hello1.html"))
  12. err := t.Execute(w, r.FormValue("who"))
  13. if err != nil {
  14. fmt.Println(err.Error())
  15. }
  16. }
  17. func main() {
  18. http.HandleFunc("/", helloHandler)
  19. log.Fatal(http.ListenAndServe(":10080",nil))
  20. }

HTMLテンプレート (hello1.html)

  1. <!DOCTYPE htm>
  2. <head>
  3. <meta charset="utf-8" />
  4. <title>Hello!</title>
  5. </head>
  6. <body>
  7. <form action="/" method="POST">
  8. 誰に?
  9. <input type="text" name="who" />
  10. <input type="submit" value="Say Hello" />
  11. </form>
  12. {{if .}}
  13. Hello, {{.|html}}!
  14. {{end}}
  15. </body>
  16. </html>

解説(1)

  • templateパッケージは,HTMLなどのテキスト出力を生成するためのデータ駆動型テンプレートです.
  • テンプレートは,HTMLファイルの可変部分を"{{"と"}}"でくくったもの(アクションと呼ぶ)で記述します.テンプレートファイルの文字コードはUTF-8です.
  • テンプレートの実行時に,アクション部分が,参照しているプログラム中のデータの値に応じて書き換えられ,その結果がブラウザに返されます.
  • テンプレートからプログラム中のデータにアクセスするには,プログラム側のExecuteメソッドでデータを指定し(ソースの13行目),テンプレート側で,アーギュメントを用いてそのデータを参照します(テンプレートの13行目から15行目がアクション,"."がアーギュメント).この例では,POSTメソッドで送られたwhoの値が,"."の値になります.
  • テンプレート13行目の"{{if .}}"は,アーギュメントに値がセットされていれば("who"になにか入力されてからPOSTされたのなら)14行目を実行する,ということを表しています.
  • 14行目の{{.|html}}は,アーギュメント"."の値をHTMLエスケープします.例えば,"."の値に>や<が含まれていたら,&gt;や&lt;に変換します.
  • データには,マップや構造体を渡すこともできます.
  • テンプレートの詳細は,言語仕様(英語)を参照してください.

マップで渡す

  • マップのキーをWhoとすると,その値は".Who"で参照できる.
  • ソースの13行目
    • t.Execute(w, map[string] string{"Who": r.FormValue("who")})
  • テンプレートの13行目から15行目
    • {{if .Who}}
    • Hello, {{.Who|html}}!
    • {{end}}

構造体で渡す

  • 構造体名をData,フィールド名をWhoとすると,その値は,".Who"で参照できる.構造体のフィールド名は他のパッケージから参照できるように大文字でなければならない
  • Dataの宣言
    • type Data struct {Who string}
  • ソースの13行目
    • t.Execute(w, Data{r.FormValue("who")})
  • テンプレートの13行目から15行目
    • {{if .Who}}
    • Hello, {{.Who|html}}!
    • {{end}}

解答例(2)

ソースコード

  1. package main
  2. import (
  3. "text/template"
  4. "net/http"
  5. "fmt"
  6. "log"
  7. )
  8. func handler(w http.ResponseWriter, r *http.Request) {
  9. fmt.Println("hello")
  10. w.Header().Set("Content-Type", "text/html") //***
  11. t := template.Must(template.ParseFiles("hello2.html"))
  12. err := t.Execute(w, map[string] string{"Hello": r.FormValue("lang"), "Who": r.FormValue("who")})
  13. if err != nil {
  14. fmt.Println(err.Error())
  15. }
  16. }
  17. func main() {
  18. http.HandleFunc("/", handler)
  19. log.Fatal(http.ListenAndServe(":10080",nil))
  20. }

HTMLテンプレート

  1. <!DOCTYPE htm>
  2. <head>
  3. <meta charset="utf-8" />
  4. <title>Hello!</title>
  5. </head>
  6. <body>
  7. <form action="/" method="POST">
  8. <p>誰に? <input type="text" name="who" /></p>
  9. <p>言語は?
  10. <select name="lang" size="1">
  11. <option value="Hello,">English</option>
  12. <option value="こんにちは,">Jananese</option>
  13. <option value="你好 ">Chinese</option>
  14. <option value="안녕하세요?">Korean</option>
  15. <option value="Bonan tagon,">Esperanto</option>
  16. </select>
  17. </p>
  18. <input type="submit" value="Say Hello" />
  19. </form>
  20. {{if .Who}}
  21. <p>{{.Hello}} {{.Who|html}}!</p>
  22. {{end}}
  23. </body>
  24. </html>

解説(2)

  • 二つの値を渡すので,HelloとWhoをキーとするマップを使っています(ソースの12行目).HTMLテンプレートからそれらの値にアクセスするには,.Helloと.Whoを用います(テンプレートの21行目,22行目).