part 1
https://qiita.com/dossy/items/721db0ab74afd8e78599
さぁ、part 1でhttp requestとdb 接続ができるようになりましたので、本格的にcrudの処理を行いましょう。
main.goにそれぞれのrequestが呼べるように記述しておきましょう。
http.HandleFunc("/new", handle.New)
http.HandleFunc("/create", handle.Create)
http.HandleFunc("/edit", handle.Edit)
http.HandleFunc("/update", handle.Update)
http.HandleFunc("/delete", handle.Delete)
createを定義
createするときは
formが必要なのでformがあるnew.htmlを呼び出します。これは/newのリクエストを送ってhtmlを表示させます。
func New(w http.ResponseWriter, r *http.Request) {
tem, _ := template.ParseFiles("new.html")
tem.Execute(w, "")
//どうやら、Executeは引数を2つ必要とするみたいです。
//new.htmlが呼び出せるように追記。
func Create(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" {
r.ParseForm() // Bodyデータを扱うには、事前にパースを行う
// Formデータを取得
form := r.PostForm
body := form["body"][0]
image := form["image"][0] //form is map value is []string of slice
serv.Create(body, image) //insert to db
http.Redirect(w, r, "/", http.StatusMovedPermanently) //code 301
//rootにredirectさせてます
}
}
}
<form action="/create" method="POST">
<div>
<label for="say">Let's write a comment!</label>
<input class="textarea" name="body" id="say" placeholder="input commnet" maxlength="100" required>
</div>
<div>
<label for="to">imageのurlを貼り付け</label>
<input class="textarea" name="image" id="to" placeholder="input image" required>
</div>
<div>
<button>Send my greetings</button>
</div>
</form>
func Create(body string, image string) {
db := database.ConnectDB()
defer db.Close()
create_time := time.Now() //time.Time型で現時刻を取得
rows, err := db.Prepare("INSERT INTO posts(body,image,created_at,updated_at) VALUES(?,?,?,?)")
if err != nil {
log.Fatal(err)
}
rows.Exec(body, image, create_time, create_time)
// Exec()にプリペアードステートメントを指定してSQLを実行する
}
formから情報を送れるようになりました。formに情報を入れてsubmitすればpost のリクエストがきます。
(注)この辺りから、ゴリゴリの自己実装です。あくまで参考程度でお願いします。何かいい方法などありましたら、コメントまで!!
さて、create funcではpost methodかどうかを判別するために条件分岐を入れています。
*http.Requestの情報をもつ?? rに対してparseをかけて情報を読める状態にします。
その後、formの中身を取り出しますが、どうやら中身はmapとsliceの二重構造になっているらしく、form["image"][0]みたいな取り方になりました。
そして、serv.Create funcが動いて取得したformの情報をinsertを使って、dbに入れ込みます。
edit deleteを定義
editとdeleteがかなり詰まったのを覚えています。
なぜなら、どのidの情報を編集、削除するのかを機械にどうやって渡すかがかなり悩ましかったですね。
httpのリクエストには/edit/2みたいなidをつけて渡すことができなかったんです。
探しあぐねましたが、しかし、見つけました。?をつけるとリクエストに値をつけれるみたいです。
http://cai.cs.shinshu-u.ac.jp/sugsi/Lecture/php/http/2-arg.html
func Edit(w http.ResponseWriter, r *http.Request) {
tem, _ := template.ParseFiles("edit.html")
params := r.URL.Query() //Queryで取得 map
e := serv.Edit(Getid(params)) //return []serv.Vertex
tem.Execute(w, e[0])
//newとほぼ一緒
func Update(w http.ResponseWriter, r *http.Request) {
if r.PostFormValue("_method") == "PUT" {
r.ParseForm()
form := r.PostForm
params := r.URL.Query()
id := Getid(params)
body := form["body"][0]
image := form["image"][0]
serv.Update(id, body, image)
http.Redirect(w, r, "/", http.StatusMovedPermanently)
}
}
func Delete(w http.ResponseWriter, r *http.Request) {
if r.Method == "DELETE" {
params := r.URL.Query() //to use Getid
serv.Delete(Getid(params)) //use sql delete func
http.Redirect(w, r, "/", http.StatusMovedPermanently)
}
}
func Getid(params url.Values) int { //get id from httprequest
var num string
for k, _ := range params { //get map_key
num = k
}
i, _ := strconv.Atoi(num) //string to int
return i
}
}
func Edit(id int) []Vertex {
db := database.ConnectDB()
defer db.Close()
rows, err := db.Query("SELECT * FROM posts WHERE id = ?", id)
//where分は配列で取得しよる
if err != nil {
log.Fatal(err)
}
var sli []Vertex // sliceをVertexで定義
var v1 Vertex //structをv1で使用する宣言
for rows.Next() { //next is needed to use scan
if err := rows.Scan(&v1.Id, &v1.Body, &v1.Image, &v1.Created_time, &v1.Updated_time); err != nil {
log.Fatal(err)
}
sli = append(sli, v1) // [{v1}]
}
return sli
}
func Update(id int, body string, image string) {
db := database.ConnectDB()
defer db.Close()
update_time := time.Now()
rows, err := db.Prepare("UPDATE posts SET body =?,image =?,updated_at = ? WHERE id = ?")
if err != nil {
log.Fatal(err)
}
rows.Exec(body, image, update_time, id)
}
func Delete(id int) {
db := database.ConnectDB()
defer db.Close()
rows, err := db.Prepare("DELETE FROM posts WHERE id=?")
if err != nil {
log.Fatal(err)
}
rows.Exec(id)
}
苦労したのが、
params := r.URL.Query() id := Getid(params)
この部分でしょうか。
rのURLの情報をQueryで取得。ただ、そのままだと扱えないのでidの情報だけを取るGetid funcを作成しました。
urlの情報はurl.Valuesという型だそうです。
https://golang.org/pkg/net/url/
http://golang.jp/pkg/strconv
https://qiita.com/nakabonne/items/2720bac7027115b1d004