LoginSignup
1
0

More than 3 years have passed since last update.

Go langでfwを使わずにcrudのappを作成しました 2

Last updated at Posted at 2019-12-15

part 1
https://qiita.com/dossy/items/721db0ab74afd8e78599
さぁ、part 1でhttp requestとdb 接続ができるようになりましたので、本格的にcrudの処理を行いましょう。
main.goにそれぞれのrequestが呼べるように記述しておきましょう。

main.go
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を表示させます。

handle/handle.go

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させてます
    }
}
}
new.html

<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>

serv/data.go

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

handle/handle.go
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
}

}

serv/data.go

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

part 3
https://qiita.com/dossy/items/4e05e8048a7885156a31

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0