Go言語を使ってメモアプリを作ってみる
以下のサイトを参考に作成をさせていただきました。
基本コード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
package main // 標準パッケージのインポート --- (*1) import ( "fmt" "html" "io/ioutil" "net/http" ) // 保存するメモファイル --- (*2) const saveFile string = "memo.txt" // メイン処理 --- (*3) func main() { fmt.Println("memo server - {URL} http://localhost:8080/¥n") http.HandleFunc("/", readHandler) http.HandleFunc("/w", writeHandler) http.ListenAndServe(":8080", nil) } // データファイルを読み込んだ上で、HTMLを生成 --- (*4) func readHandler(w http.ResponseWriter, r *http.Request) { text, err := ioutil.ReadFile(saveFile) if err != nil { text = []byte("ここにメモを記入してください") } htmlText := html.EscapeString(string(text)) s := "<html>" + "<style>textarea {width:99%; height:200px}</style>" + "<form method='POST' action='/w'>" + "<textarea name='text'>" + htmlText + "</textarea>" + "<input type='submit' value='保存' /></form></html>" w.Write([]byte(s)) } // POSTデータを読み込みデータファイルを作成する --- (*5) func writeHandler(w http.ResponseWriter, r *http.Request) { r.ParseForm() if len(r.Form["text"][0]) == 0 { w.Write([]byte("フォームから投稿してください")) return } text := r.Form["text"][0] ioutil.WriteFile(saveFile, []byte(text), 0644) http.Redirect(w, r, "/", 301) } |
標準パッケージのインポート
Go言語のソースファイルはパッケージという単位でグルーピングされ、各パッケージには1つ以上のソースファイルが所属しています。詳しくはまた別の機会に説明を加えたいと思いますが、Go言語ではこのパッケージと呼ばれるものが標準でたくさん備わっています。パッケージを使う際は以下のように記載します。
1 2 3 4 5 6 7 8 9 10 11 |
import "パッケージのパス" // 以下のようにimport 文を複数回使い複数個のパッケージの利用を宣言する import "fmt" // fmt パッケージの利用を宣言 import "net/http" // net/http パッケージの利用を宣言 // 以下のように()付きで利用するパッケージを複数個宣言する import ( "fmt" "net/http" ) |
今回利用したパッケージは以下のものです。
パッケージ名 | 説明 |
---|---|
fmt | C言語のprintfやscanfと同じようなI/Oフォーマット機能が実装されています。 |
html | HTMLテキストのエスケープとアンエスケープ用の関数が提供されています。 |
io/ioutil | 入出力処理をサポートする機能がまとめられたパッケージです。 |
net/http | HTTPクライアント/サーバー機能がまとめられたパッケージです。 |
保存するメモファイル
ここでは定数を宣言してメモファイルの保存先を設定しています。定数を宣言する際はconstを使い以下のように記述します。
1 |
const 定数名 型(省略可) = 値または書式 |
メイン処理
ここではWebサーバーを起動し、リクエストURLのパス毎に呼び出すファンクションを変えています。『/』ではreadHandlerを呼び出し『/w』でwriteHandlerを呼び出しています。
1 2 3 4 5 6 7 |
// メイン処理 --- (*3) func main() { fmt.Println("memo server - {URL} http://localhost:8080/¥n") http.HandleFunc("/", readHandler) http.HandleFunc("/w", writeHandler) http.ListenAndServe(":8080", nil) } |
http.HandleFunc関数
HandleFunc関数の第1引数にはURLのパスを、第2引数にはそのパスに対して実行される関数を指定しています。簡単に説明するとURLと関数の関連付けを行ってくれています。
http.ListenAndServe関数
ListenAndServeは、ポート番号(string型)とハンドラ(Handler型)の引数を取ります。この2つの引数をもとにWebサーバが起動し、リクエスト受付状態になります。
データファイルを読み込んだ上で、HTMLを生成
ioutil.Readfileを使い、定数で指定したメモファイルを読み込みます。その結果、読み込むべきファイルがない場合は、nilとなりデフォルトの入力値が表示されます。
また、html.EscapeStringを使い入力フォームに入力された文字をエスケープしておきます。これはセキュリティ上最低限必要な対策になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// データファイルを読み込んだ上で、HTMLを生成 --- (*4) func readHandler(w http.ResponseWriter, r *http.Request) { text, err := ioutil.ReadFile(saveFile) if err != nil { text = []byte("ここにメモを記入してください") } htmlText := html.EscapeString(string(text)) s := "<html>" + "<style>textarea {width:99%; height:200px}</style>" + "<form method='POST' action='/w'>" + "<textarea name='text'>" + htmlText + "</textarea>" + "<input type='submit' value='保存' /></form></html>" w.Write([]byte(s)) } |
POSTデータを読み込みデータファイルを作成する
Postされたフォームデータをr.ParseFormを使って取得します。フォームデータの中でテキストエリアに入力された値の長さをlen関数を用いて数え、値がない場合は『フォームから投稿してください』のメッセージを返します。
値がある場合は、ioutil.WriteFileをつかってファイルを書き込みます。各パラメータについてはまたご紹介したいと思いますので、今回は省略します。ファイルを書き込んだら、最後はhttp.Redirectでルートパスにリダイレクトし、readHandlerが実行され、書き込んだ内容が画面に表示されます。
1 2 3 4 5 6 7 8 9 10 11 |
// POSTデータを読み込みデータファイルを作成する --- (*5) func writeHandler(w http.ResponseWriter, r *http.Request) { r.ParseForm() if len(r.Form["text"][0]) == 0 { w.Write([]byte("フォームから投稿してください")) return } text := r.Form["text"][0] ioutil.WriteFile(saveFile, []byte(text), 0644) http.Redirect(w, r, "/", 301) } |
まとめ
post情報をもとにファイル生成ができるのであれば、管理者だけがアクセスできるサイトを作って、そこで設定情報なんかを書き換えることができるページを作るのもありだなーと感じた。