Go言語 フレームワークレス WEBアプリその1(Mongodbを使ってデータの表示・登録・更新)
2020/03/13
2020/04/12
Go言語はC言語を拡張しインスパイヤーしたような言語だ。私のような古い人はC言語に慣れ親しんでいるので非常に入り込みやすいプログラミング言語と言える。Go言語もフレームワークが色々存在する。ただ、他の言語と違うなーと思うのは、フレームワーク使わなくてもそこそこのWEBアプリが標準で気軽に作れる印象を持っています。最終的にフレームワーク使うとしても、最初は無しで学習したほうが後々の理解度や改造時に役立つと思います。今後はバイナリー系の速度が早く、安全なWEBサイト構築はJavaからGo言語に移り変わるのではないかと私は予測しています。JavaはIT関連の著名なアメリカのマンモス企業なんかも言ってたけどもう廃れた言語とか、JavaのテクノロージーUPに対して”Ora○○e”は怠けているという評論もあるほどだ。モバイルはkotolin,scalaがjavaの代わりになるだろうと思う。DBに関してはMySQL,PostgreSQLでスケーラビリティを十分とれるためいつかはOracleは不要になるかもね。また、NoSQLはどちらかと言えばMySQL,PostgreSQLの置き換えというよりは、補完する役割だと思うので得意、不得意を勘案して部分的な機能で何れかを選ぶことになるだろう。
今回は求人検索用のシステムを作る前提で仕事登録の初期のベーシックなところから作ってみたいと思います。機能は表示、登録と更新だけ。認証は無し。
MongoDBのインストールと起動
OS毎のインストール方法が異なるので下記のリンクを参照のこと。下記はDebian9のインストールケース
https://docs.mongodb.com/manual/administration/install-on-linux/
1 2 3 4 5 6 7 |
$ sudo apt-get install gnupg $ wget -qO - https://www.mongodb.org/static/pgp/server-4.2.asc | sudo apt-key add - $ echo "deb http://repo.mongodb.org/apt/debian buster/mongodb-org/4.2 main" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.2.list $ sudo apt-get update $ sudo apt-get install -y mongodb-org $ sudo systemctl daemon-reload $ sudo systemctl start mongod |
MongoDBの操作
MongoDBにアクセスするクライントソフトはmongoです。デフォルトのポートでアクセスする場合は単純にmongoで接続可能です。
1 2 |
$ mongo # use study |
NoSQLのMongoDBの操作はある程度はコマンドが似ている。用語が少しだけ違う。
初歩的なWEBアプリ
いつもならデータベースというと、MySQLを使うところだが今回はMongodbを使ったやり方でサイトのデータを表示するアプリを作ってみようと思う。感覚的にはpythonのボトルフレームワークの感覚で使えているので標準でこれならフレームワークレスでも全く問題ない。今回は教育用にとログイン機能、バリデーション機能を導入してないが、実装は簡単だと思うので各自改造しながら実装してみてほしい。また、CSSや画像、js関連も独自でトライしてみてください。きっとそう難しく無いと思います。
本体ルーチン(server.go)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
package main import ( "log" "./newlib" "net/http" ) func main() { port := "3000" http.HandleFunc("/favicon.ico",mylib.HandleFav) http.HandleFunc("/regist/jobs",mylib.HandleJobAdd ) http.HandleFunc("/update/jobs",mylib.HandleJobUpdate ) http.HandleFunc("/", mylib.HandleIndex ) http.HandleFunc("/static/", func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, r.URL.Path[1:]) }) log.Printf("Server listening on port %s", port) log.Print(http.ListenAndServe(":"+port, nil)) } |
コンテンツハンドリングルーチン
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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
package mylib import ( "fmt" "time" "log" "strconv" //"strings" "html/template" "net/http" "github.com/globalsign/mgo" "github.com/globalsign/mgo/bson" ) //const MongoDb details const ( hosts = "localhost:3001" database = "test" username = "staff_entry" password = "Xhd6233k(%cV43" collection = "jobs" ) type WorkItem struct { ID bson.ObjectId `bson:"_id"` JobNum string `bson:"job_num"` Company string `bson:"company"` Outline string `bson:"outline"` Office string `bson:"office"` WorkTitle string `bson:"work_title"` Location string `bson:"location"` ContractStatus string `bson:"contract_status"` ContractPeriod string `bson:"contract_period"` ContractStart string `bson:"contract_start"` NearStation []string `bson:"near_station"` Holiday string `bson:"holiday"` Salary string `bson:"salary"` WorkingHours []string `bson:"working_hours"` Welfare []string `bson:"welfare"` Etc string `bson:"etc"` ViewFlag bool `bson:"view_flag"` } var info *mgo.DialInfo = &mgo.DialInfo{ Addrs: []string{hosts}, Timeout: 60 * time.Second, Database: database, Username: username, Password: password, } //先頭を大文字にして外部参照できるようにする。 func HandleJobAdd(w http.ResponseWriter, r *http.Request){ var reg_jobs WorkItem if method_type := r.Method; method_type == "GET" { t, err := template.ParseFiles("templates/add_job.html") if err != nil { log.Fatalf("template error: %v", err) } t.Execute(w, nil ) } else { t, err := template.ParseFiles("templates/reg_jobs.html") if err != nil { log.Fatalf("template error: %v", err) } reg_jobs.ID = bson.NewObjectId() reg_jobs.JobNum = r.FormValue("JobNum") reg_jobs.Company = r.FormValue("Company") reg_jobs.Outline = r.FormValue("Outline") reg_jobs.Office = r.FormValue("Office") reg_jobs.WorkTitle = r.FormValue("WorkTitle") reg_jobs.Location = r.FormValue("Location") reg_jobs.ContractStatus = r.FormValue("ContractStatus") reg_jobs.ContractPeriod = r.FormValue("ContractPeriod") reg_jobs.ContractStart = r.FormValue("ContractStart") reg_jobs.NearStation = []string{ r.FormValue("NearStation") } reg_jobs.Holiday = r.FormValue("Holiday") reg_jobs.Salary = r.FormValue("Salary") reg_jobs.WorkingHours = []string{ r.FormValue("WorkingHours") } reg_jobs.Welfare = []string{ r.FormValue("Welfare") } reg_jobs.Etc = r.FormValue("Etc") reg_jobs.ViewFlag ,_ = strconv.ParseBool( r.FormValue("ViewFlag") ) session, err1 := mgo.DialWithInfo(info) if err1 != nil { panic(err1) } defer session.Close() col := session.DB(database).C(collection) err2 := col.Insert(reg_jobs) if err2 != nil { panic(err2) } else { fmt.Println("以下のように登録されました。") fmt.Printf("data is %+v\n",reg_jobs) t.Execute(w, reg_jobs ) } //fmt.Printf("data is %+v\n",reg_jobs) //t.Execute(w, reg_jobs ) } } //先頭大文字にして外部参照できるようにする。 func HandleIndex(w http.ResponseWriter, r *http.Request) { var pwork []WorkItem session, err1 := mgo.DialWithInfo(info) if err1 != nil { panic(err1) } defer session.Close() col := session.DB(database).C(collection) if err2 := col.Find(nil).All(&pwork); err2 != nil { panic(err2) } // forward data to template engine t, err := template.ParseFiles("templates/index.html") if err != nil { log.Fatalf("template error: %v", err) } t.Execute(w, pwork ) } func HandleJobUpdate(w http.ResponseWriter, r *http.Request) { //id_num := strings.Split(r.URL.Path,"/") //idstr := id_num[len(id_num) - 1] idstr := "5e571e1a6a73dfd8af148179" if !bson.IsObjectIdHex(idstr) { log.Fatal("Not Object.") } id := bson.ObjectIdHex(idstr) var reg_jobs WorkItem if method_type := r.Method; method_type == "GET" { t, err := template.ParseFiles("templates/update_job.html") if err != nil { log.Fatalf("template error: %v", err) } session, err1 := mgo.DialWithInfo(info) if err1 != nil { panic(err1) } defer session.Close() col := session.DB(database).C(collection) if err := col.FindId(id).One(®_jobs); err != nil { panic(err) } t.Execute(w, reg_jobs ) } else { t, err := template.ParseFiles("templates/reg_jobs.html") if err != nil { log.Fatalf("template error: %v", err) } reg_jobs.ID = bson.NewObjectId() reg_jobs.JobNum = r.FormValue("JobNum") reg_jobs.Company = r.FormValue("Company") reg_jobs.Outline = r.FormValue("Outline") reg_jobs.Office = r.FormValue("Office") reg_jobs.WorkTitle = r.FormValue("WorkTitle") reg_jobs.Location = r.FormValue("Location") reg_jobs.ContractStatus = r.FormValue("ContractStatus") reg_jobs.ContractPeriod = r.FormValue("ContractPeriod") reg_jobs.ContractStart = r.FormValue("ContractStart") reg_jobs.NearStation = []string{ r.FormValue("NearStation") } reg_jobs.Holiday = r.FormValue("Holiday") reg_jobs.Salary = r.FormValue("Salary") reg_jobs.WorkingHours = []string{ r.FormValue("WorkingHours") } reg_jobs.Welfare = []string{ r.FormValue("Welfare") } t.Execute(w, reg_jobs ) } } func HandleFav(w http.ResponseWriter, r *http.Request) { // 何もしません fmt.Println("this call ignore") } |
表示テンプレート
index.html>
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 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>Mongo Test Server</title> </head> <body> <h1>Mongo DB test</h1> {{range $val := .}} <table border="1"> <tr><td>JOB番号</td><td>{{$val.JobNum}}</td></tr> <tr><td>企業名</td><td>{{$val.Company}}</td></tr> <tr><td>企業概要</td><td>{{$val.Outline}}</td></tr> <tr><td>住所</td><td>{{$val.Office}}</td></tr> <tr><td>案件内容</td><td>{{$val.WorkTitle}}</td></tr> <tr><td>勤務地</td><td>{{$val.Location}}</td></tr> <tr><td>最寄り駅</td><td>{{$val.NearStation}}</td></tr> <tr><td>雇用形態</td><td>{{$val.ContractStatus}}</td></tr> <tr><td>雇用期間</td><td>{{$val.ContractPeriod}}</td></tr> <tr><td>雇用開始日</td><td>{{$val.ContractStart}}</td></tr> <tr><td>最寄り駅</td><td>{{$val.NearStation}}</td></tr> <tr><td>休日</td><td>{{$val.Holiday}}</td></tr> <tr><td>給与</td><td>{{$val.Salary}}</td></tr> <tr><td>勤務時間</td><td>{{$val.WorkingHours}}</td></tr> <tr><td>福利厚生</td><td>{{$val.Welfare}}</td></tr> </table> <hr> {{end}} </body> </html> |
add_job.html
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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>Mongo Test Server</title> </head> <body> <h1>Mongo DB test</h1> <form class="job-entryform" action="/regist/jobs" method="post"> <p>案件情報の登録を実施してください。</p> <div class="item"> <label class="label" for="name">Job番号</label> <input id="JobNum" type="text" name="JobNum"> </div> <div class="item"> <label class="label" for="Company">企業名</label> <input id="Company" type="text" name="Company"> </div> <div class="item"> <br> <label class="label" for="Outline">企業概要</label><br> <textarea id="Outline" type="textarea" name="Outline" cols="60" rows="3" >企業概要を3行以内で記述してください</textarea> </div> <div class="item"> <label class="label" for="Office">住所</label> <input id="Office" type="text" name="Office"> </div> <div class="item"> <label class="label" for="WorkTitle">案件内容</label> <input id="WorkTitle" type="text" name="WorkTitle"> </div> <div class="item"> <label class="label" for="Location">勤務地</label> <input id="Location" type="text" name="Location"> </div> <div class="item"> <label class="label" for="ContractStatus">契約形態</label> <select name="ContractStatus"> <option value="正社員">正社員</option> <option value="契約社員">契約社員</option> <option value="派遣">派遣</option> <option value="パート">パート</option> </select> </div> <div class="item"> <label class="label" for="ContractPeriod">契約期間</label> <input id="ContractPeriod" type="text" name="ContractPeriod"> </div> <div class="item"> <label class="label" for="ContractStart">勤務開始日</label> <input id="ContractStart" type="text" name="ContractStart"> </div> <div class="item"> <label class="label" for="NearStation">最寄り駅</label> <input id="NearStation" type="text" name="NearStation"> </div> <div class="item"> <label class="label" for="Holiday">休日</label> <input id="Holiday" type="text" name="Holiday"> </div> <div class="item"> <label class="label" for="Salary">給与</label> <input id="Salary" type="text" name="Salary"> </div> <div class="item"> <label class="label" for="WorkingHours">勤務時間</label> <input id="WorkingHours" type="text" name="WorkingHours"> </div> <div class="item"> <label class="label" for="Welfare">福利厚生</label> <input id="Welfare" type="text" name="Welfare"> </div> <div class="item"> <label class="label" for="Etc">備考</label><br> <textarea id="Etc" type="text" name="Etc" cols="60" rows="3">200文字以内で書いてください</textarea> </div> <div class="item"> <label class="label" for="ViewFlag">公開フラグ</label> <input id="ViewFlag" type="radio" name="ViewFlag" value="true" checked>公開 <input id="ViewFlag" type="radio" name="ViewFlag" value="false">非公開 </div> <div class="item no-label"> <input type="submit"> </div> </form> </body> </html> |
reg_jobs.html
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 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>Mongo Test Server</title> </head> <body> <h1>Mongo DB test</h1> <table border="1"> <tr><td>JOB番号</td><td>{{.JobNum}}</td></tr> <tr><td>企業名</td><td>{{.Company}}</td></tr> <tr><td>企業概要</td><td>{{.Outline}}</td></tr> <tr><td>住所</td><td>{{.Office}}</td></tr> <tr><td>案件内容</td><td>{{.WorkTitle}}</td></tr> <tr><td>勤務地</td><td>{{.Location}}</td></tr> <tr><td>雇用形態</td><td>{{.ContractStatus}}</td></tr> <tr><td>雇用期間</td><td>{{.ContractPeriod}}</td></tr> <tr><td>雇用開始日</td><td>{{.ContractStart}}</td></tr> <tr><td>最寄り駅</td><td> {{range $val := .NearStation}} {{$val}} {{end}} </td></tr> <tr><td>休日</td><td>{{.Holiday}}</td></tr> <tr><td>給与</td><td>{{.Salary}}</td></tr> <tr><td>勤務時間</td><td> {{range $i,$val := .WorkingHours}} {{$val}} {{if eq $i 0}} <span>~</span> {{end}} {{end}} </td></tr> </td></tr> <tr><td>福利厚生</td><td> {{range $val := .Welfare}} {{$val}} {{end}} </td></tr> <tr> <td>備考</td><td>{{ .Etc }}</td> </tr> <tr><td>公開設定</td><td>{{.ViewFlag}}</td></tr> </table> <hr> <p>現在時刻: {{.Time.Format "2006/1/2 15:04:05"}}</p> </body> </html> |
update_job.html
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 49 50 51 52 53 54 55 56 57 58 59 60 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>Mongo Test Server</title> </head> <body> <h1>Mongo DB test</h1> <form class="job-entryform" action="/update/jobs" method="post"> <table border="1"> <tr><td>ID</td><td> <input name="ID" type="text" value="{{.ID}}"> </td></tr> <tr><td>JOB番号</td><td> <input name="JobNum" type="text" value="{{.JobNum}}"> </td></tr> <tr><td>企業名</td><td> <input name="Company" type="text" value="{{.Company}}"> </td></tr> <tr><td>企業概要</td><td> <textarea name="Outline" type="text" >{{.Outline}}</textarea> </td></tr> <tr><td>住所</td><td><input name="Office" type="text" value="{{.Office}}"></td></tr> <tr><td>案件内容</td><td><input name="WorkTitle" type="text" value="{{.WorkTitle}}"></td></tr> <tr><td>勤務地</td><td><input name="Location" type="text" value="{{.Location}}"></td></tr> <tr><td>最寄り駅</td><td><input name="NearStation" type="text" value="{{.NearStation}}"></td></tr> <tr><td>雇用形態</td><td> <select name="ContractStatus"> <option value="正社員">正社員</option> <option value="契約社員">契約社員</option> <option value="派遣">派遣</option> <option value="パート">パート</option> </select> </td></tr> <tr><td>雇用期間</td><td><input name="ContractPeriod" type="text" value="{{.ContractPeriod}}"></td></tr> <tr><td>雇用開始日</td><td><input name="ContractStart" type="text" value="{{.ContractStart}}"></td></tr> <tr><td>最寄り駅</td><td><input name="NearStation" type="text" value="{{.NearStation}}"></td></tr> <tr><td>休日</td><td><input name="Holiday" type="text" value="{{.Holiday}}"></td></tr> <tr><td>給与</td><td><input name="Salary" type="text" value="{{.Salary}}"> <tr><td>勤務時間</td><td><input name="WorkingHours" type="text" value="{{.WorkingHours}}"></td></tr> <tr><td>福利厚生</td><td><input name="Welfare" type="text" value="{{.Welfare}}"></td></tr> <tr><td>備考</td><td> <textarea name="Etc" type="text" > {{.Etc}}</textarea> </td></tr> <tr><td>公開フラグ</td><td> <input name="ViewFlag" type="radio" value="true">公開 <input name="ViewFlag" type="radio" value="false">非公開 </td></tr> </table> <div class="item no-label"> <input type="submit"> </div> </form> <hr> </body> </html> |
アプリの起動
1 |
$ go run server.go |
登録データの確認
http://localhost:3001/
新規登録
http://localhost:3001/regist/jobs
登録情報の更新
http://localhost:3001/update/jobs