go言語(echo)を使って簡単なWEBページを作成する手順

# 概要
Go言語を使って簡単なWEBページを作成する

※dockerとgolangの動作環境が準備済みである事

# 目次
[1. dockerコンテナとgo言語環境ソースファイルのファイル構成](#1-dockerコンテナとgo言語環境ソースファイルのファイル構成)
[2. WEBサーバー構築](#2-webサーバー構築)
[3. htmlファイルの作成](#3-htmlファイルの作成)


# 1. dockerコンテナとgo言語環境ソースファイルのファイル構成

go言語の環境構築については下記記事参照
[windowsでGo言語を使ったWEBアプリケーション作成の環境を構築する](https://qiita.com/kubota_ndatacom/items/84e98d84e5859d602102)

```ファイル構成
docker
+---web-app
    |   docker-compose.yml
    +---images
        +---golang-api
                DockerFile
go
+---web-app
    |   go.mod
    |   go.sum
    |   main.go
    +---views
            MainPage.html
            MainPage2.html
            DetailPage.html
```


ローカルで作成したgo言語環境をdockerコンテナにバインドさせてAPIサーバーを作成する
dockerコンテナの作成については以前の記事参照
[go言語(echo)APIサーバーの構築手順(+reactとの接続設定手順)](https://qiita.com/kubota_ndatacom/items/65af3f33734dc12f102e)

# 2. WEBサーバー構築

main.goを下記のように記述する
html表示用のhtml/templateパッケージを使用してWEB画面を表示する

```go:main.go
package main

import (
	/* サーバー起動用のパッケージ */
	"net/http"
	/* テンプレート用パッケージ */
	"html/template"
	/* 入出力を扱うパッケージ */
	"io"
	/* ミドルウェア用パッケージ */
	"github.com/labstack/echo/middleware"
	/* メインのフレームワークにechoを使用 */
	"github.com/labstack/echo"
)

type Template struct {
	templates *template.Template
}

func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
	return t.templates.ExecuteTemplate(w, name, data)
}

/* 共通使用するデータ用の構造体 */
type CommonData struct {
	/* field名は大文字で始める */
	Title string
}

/* メインページ表示 */
func viewMainPage(c echo.Context) error {
	/* テンプレートに渡す値をセット */
	var common = CommonData{
		"メインページ",
	}
	data := struct {
		/* field名は大文字で始める */
		CommonData
		ContentString string
	}{
		CommonData:    common,
		ContentString: "文章",
	}

	/* Renderでhtmlを表示 */
	return c.Render(http.StatusOK, "mainPage", data)
}

/* メインページ表示2 */
func viewMainPage2(c echo.Context) error {
	/* テンプレートに渡す値をセット */
	var common = CommonData{
		"メインページ2",
	}
	data := struct {
		/* field名は大文字で始める */
		CommonData
	}{
		CommonData: common,
	}

	/* Renderでhtmlを表示 */
	return c.Render(http.StatusOK, "mainPage", data)
}

/* 遷移先ページ */
func viewDetailPage(c echo.Context) error {
	/* QueryParamでクエリの値を取得する */
	code := c.QueryParam("code")
	/* テンプレートに渡す値をセット */
	var common = CommonData{
		"遷移先ページ",
	}
	data := struct {
		/* field名は大文字で始める */
		CommonData
		Code string
	}{
		CommonData: common,
		Code:       code,
	}
	/* Renderでhtmlを表示 */
	return c.Render(http.StatusOK, "detailPage", data)
}

func main() {
	/* echoのインスタンス作成 */
	e := echo.New()

	/* テンプレートの設定(viewsフォルダの.htmlファイルが対象) */
	t := &Template{
		templates: template.Must(template.ParseGlob("views/*.html")),
	}
	e.Renderer = t

	/* ミドルウェア類 */
	e.Use(middleware.Logger())
	e.Use(middleware.Recover())

	/* メインページ表示 */
	e.GET("/main", viewMainPage)
	/* メインページ2表示 */
	e.GET("/main2", viewMainPage2)
	/* メインページ2からの遷移先ページ */
	e.GET("/dtlPage", viewDetailPage)

	/* サーバー起動 */
	e.Logger.Fatal(e.Start(":1323"))
}

```

# 3. htmlファイルの作成

MainPage.html,MainPage2.html,DetailPage.htmlを下記の様に記述する

templeteパッケージの記述方法については下記参照
[Go言語(golang) テンプレートの使い方](https://golang.hateblo.jp/entry/golang-text-html-template)


```html:MainPage.html
{{define "mainPage"}}
  {{template "header" .}}
<blockquote>
  {{if eq .CommonData.Title "メインページ"}}
    <div>{{.ContentString}}</div>
  {{else}}
    <div><input id="code" type="text" /></div>
    <div><button onclick="movePage()">test</button></div>
    <script>
        function movePage() {
            var code = document.getElementById("code").value;
            window.location.href = 'http://127.0.0.1:1323/dtlPage?code='+code;
        }
    </script>
  {{end}}
</blockquote>
{{end}}
```

```html:Header.html
{{define "header"}}
  <h1>{{.CommonData.Title}}</h1>
{{end}}
```

```html:DetailPage.html
{{define "detailPage"}}
  <div>{{.Code}}</div>
{{end}}

```

dokoerコンテナを起動(goサーバー起動)し
WEBブラウザでhttp://127.0.0.1:1323/main とURLを入力すると下記画面が表示される

main.goのviewMainPage関数が呼ばれる
→templeteのdefineで定義された"mainPage"にdataを渡して表示される
```go:main.go(抜粋)
func viewMainPage(c echo.Context) error {
	/* テンプレートに渡す値をセット */
	var common = CommonData{
		"メインページ",
	}
	data := struct {
		/* field名は大文字で始める */
		CommonData
		ContentString string
	}{
		CommonData:    common,
		ContentString: "文章",
	}

	/* Renderでhtmlを表示 */
	return c.Render(http.StatusOK, "mainPage", data)
}
```

![20221209-001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2749195/10175608-253a-ca79-059e-a49aa25ada4b.jpeg)


WEBブラウザでhttp://127.0.0.1:1323/main2 とURLを入力すると下記画面が表示される

main.goのviewMainPage2関数が呼ばれる
→templeteのdefineで定義された"mainPage"にdataを渡して表示される
```go:main.go(抜粋)
func viewMainPage2(c echo.Context) error {
	/* テンプレートに渡す値をセット */
	var common = CommonData{
		"メインページ2",
	}
	data := struct {
		/* field名は大文字で始める */
		CommonData
	}{
		CommonData: common,
	}

	/* Renderでhtmlを表示 */
	return c.Render(http.StatusOK, "mainPage", data)
}
```

![20221209-002.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2749195/f2e445df-ebf3-28ec-c439-08b3880648c1.jpeg)

入力欄に任意の文字を入力、testボタンをクリックすると
下記画面が表示される

mainPage.htmlに記載されたjavascriptの画面遷移処理でhttp://127.0.0.1:1323/dtlPage?code=[入力した文字] が呼ばれる
→main.goのviewDetailPage関数が呼ばれる
→templeteのdefineで定義された"detailPage"にdataを渡して表示される
```go:main.go(抜粋)
func viewDetailPage(c echo.Context) error {
	/* QueryParamでクエリの値を取得する */
	code := c.QueryParam("code")
	/* テンプレートに渡す値をセット */
	var common = CommonData{
		"遷移先ページ",
	}
	data := struct {
		/* field名は大文字で始める */
		CommonData
		Code string
	}{
		CommonData: common,
		Code:       code,
	}
	/* Renderでhtmlを表示 */
	return c.Render(http.StatusOK, "detailPage", data)
}
```

![20221209-003.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2749195/f2c433bd-9ffc-7b3b-783f-8a0c8c3c8c3e.jpeg)
　　　　　　　　　　　　　　　⬇
![20221209-004.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2749195/9ed51b3e-6972-b999-67b9-d1b06c444718.jpeg)