【Go】Webアプリケーションの作成方法

Goによるローカルファイルを使用したWEBアプリケーションのサンプルページの製造方法をメモします。
これをもとに、DBを利用したWEBアプリケーションの足掛かりにしてもよいかもしれません。


##ファイル構成
・main.go（処理）
・view.html（テンプレート）
・edit.html（テンプレート）
・test.txt(ページ保存ファイル)

##main.go
```go
package main

import (
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"regexp"
)

type Page struct {
	Title string
	Body  []byte
}

//ページ情報をファイルに保存する
func (p *Page) save() error {
	filename := p.Title + ".txt"
	return ioutil.WriteFile(filename, p.Body, 0600)
}

//ページ情報をファイルから読み込む
func loadPage(title string) (*Page, error) {
	filename := title + ".txt"
	body, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	return &Page{Title: title, Body: body}, nil
}

//Templateをキャッシュ化する
var templates = template.Must(template.ParseFiles("edit.html", "view.html"))

//Templateを読み込む関数
func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {

	err := templates.ExecuteTemplate(w, tmpl+".html", p)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

//表示ページ
func viewHandler(w http.ResponseWriter, r *http.Request, title string) {
	p, err := loadPage(title)
	if err != nil {
		http.Redirect(w, r, "/edit/"+title, http.StatusFound)
	}
	renderTemplate(w, "view", p)
}

//修正ページ
func editHandler(w http.ResponseWriter, r *http.Request, title string) {
	p, err := loadPage(title)
	if err != nil {
		p = &Page{Title: title}
	}
	renderTemplate(w, "edit", p)
}

//保存処理
func saveHandler(w http.ResponseWriter, r *http.Request, title string) {
	body := r.FormValue("body")
	p := &Page{Title: title, Body: []byte(body)}
	err := p.save()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	http.Redirect(w, r, "/view/"+title, http.StatusFound)
}

var validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-A0-9]+)$")

//各種ハンドラを生成するメソッド
func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		m := validPath.FindStringSubmatch(r.URL.Path)
		if m == nil {
			http.NotFound(w, r)
			return
		}
		fn(w, r, m[2])
	}
}

//実行処理。WEBサーバの起動とルーティングを行います。
func main() {
	http.HandleFunc("/view/", makeHandler(viewHandler))
	http.HandleFunc("/edit/", makeHandler(editHandler))
	http.HandleFunc("/save/", makeHandler(saveHandler))
	log.Fatal(http.ListenAndServe(":8080", nil))
}
```

## view.html
```html
<h1>{{.Title}}</h1>
<p>[<a href="/edit/{{.Title}}">Edit</a>]</p>
<div>{{printf "%s" .Body}}</div>
```

## edit.html
```html
<h1>Editing {{.Title}}</h1>

<form action="/save/{{.Title}}" method="POST">
    <div>

        <textarea name="body" rows="20" cols="80">{{printf "%s" .Body}}</textarea>
    </div>
    <div>
        <input type="submit" value="Save">
    </div>
</form>
```
##test.txt
```text
This is a sample Page.
```

##起動

###表示ページ
http://localhost:8080/view/test
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561175/66a0d316-143a-34f1-2435-e8dd53cf3b74.png)


###編集ページ
http://localhost:8080/edit/test
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561175/cabe5983-fe77-42c0-f56e-d0aa78c9271c.png)

###参考
【Go公式】Writing Web Applications
https://golang.org/doc/articles/wiki/