フレームワーク「GIN」を使ってみた（CRUD処理）


とりあえず、ソースを保存。
備忘用なので、説明は後で。

```go:main.go
package main

import (
	"routes"
	"github.com/gin-gonic/gin"
)

func main() {
	router := gin.Default()

	// 事前にテンプレートをロード 相対パス
	router.LoadHTMLGlob("templates/*.html")

	// グルーピング
	user := router.Group("/user")
	{
		// Railsのようなマッピングは重複エラーになり不可。
		// 更新・削除は、PATCH・DELETEで対応できないので、POST・GETで対応
		user.GET("/", routes.Index)            // ユーザ一覧
		user.GET("/show/:id", routes.Show)     // ユーザー参照
		user.GET("/new", routes.New)           // 新規ユーザー登録
		user.POST("/new", routes.Create)       // 新規ユーザー作成
		user.GET("/edit/:id", routes.Edit)     // ユーザー編集
		user.POST("/edit/:id", routes.Update)  // ユーザー更新
		user.GET("/delete/:id", routes.Delete) // ユーザー削除
	}

	router.Run(":8080")
}

```

```go:routes/users_controller.go
package routes

import (
	"database/sql"
	"log"
	"net/http"

	"github.com/gin-gonic/gin"

	_ "github.com/mattn/go-sqlite3"
)

var DbConnection *sql.DB

type Users struct {
	Id     int
	UserId string
	Name   string
}

func Index(c *gin.Context) {
	log.Print("一覧画面")
	DbConnection, _ := sql.Open("sqlite3", "./db/sqlite3/test.db") // main.goからのパスを指定
	defer DbConnection.Close()

	/* テーブルが存在しない場合に作成する
	cmd := `CREATE TABLE IF NOT EXISTS m_users(
		id integer PRIMARY KEY AUTOINCREMENT,
		user_id string,
		name string)`
	_, err := DbConnection.Exec(cmd)
	if err != nil {
		log.Fatalln(err)
	}
	*/

	cmd := "SELECT id, user_id, name FROM m_users"
	rows, _ := DbConnection.Query(cmd)
	defer rows.Close()

	var pp []Users // 取得するデータの構造体を用意（複数取得するのでスライス）
	for rows.Next() {
		var p Users                                 // 取得の格納用
		err := rows.Scan(&p.Id, &p.UserId, &p.Name) // Scanで指定した変数に格納
		if err != nil {
			log.Println(err)
		}
		pp = append(pp, p)
	}

	for _, p := range pp {
		log.Println(p.Id, p.UserId, p.Name)
	}

	c.HTML(http.StatusOK, "index", gin.H{"Users": pp})
}

func Show(c *gin.Context) {
	log.Print("参照画面")
	DbConnection, _ := sql.Open("sqlite3", "./db/sqlite3/test.db") // main.goからのパスを指定
	defer DbConnection.Close()

	id := c.Param("id") // URLの:idを取得

	cmd := "SELECT id, user_id, name FROM m_users where id = ?"
	row := DbConnection.QueryRow(cmd, id) // ?の条件にidを指定
	// QueryRowの場合、close処理は不要

	var p Users
	err := row.Scan(&p.Id, &p.UserId, &p.Name) // Scanで指定した変数に格納
	if err != nil {
		if err == sql.ErrNoRows {
			log.Println("No row")
		} else {
			log.Println(err)
		}
	}
	log.Print(p.Id, p.UserId, p.Name)

	c.HTML(http.StatusOK, "show", gin.H{"User": p})

}

func New(c *gin.Context) {
	log.Print("登録画面")
	c.HTML(http.StatusOK, "new", gin.H{})
}

func Create(c *gin.Context) {
	log.Print("登録処理")
	DbConnection, _ := sql.Open("sqlite3", "./db/sqlite3/test.db") // main.goからのパスを指定
	defer DbConnection.Close()

	userid := c.PostForm("userID")
	name := c.PostForm("name")

	cmd := "INSERT INTO m_users (user_id, name) VALUES (?, ?)"
	_, err := DbConnection.Exec(cmd, userid, name)
	if err != nil {
		log.Fatalln(err)
	}
	c.Redirect(http.StatusMovedPermanently, "/user")

}

func Edit(c *gin.Context) {
	log.Print("編集画面")
	DbConnection, _ := sql.Open("sqlite3", "./db/sqlite3/test.db") // main.goからのパスを指定
	defer DbConnection.Close()

	id := c.Param("id") // URLの:idを取得

	cmd := "SELECT id, user_id, name FROM m_users where id = ?"
	row := DbConnection.QueryRow(cmd, id) // ?の条件にidを指定
	// QueryRowの場合、close処理は不要

	var p Users
	err := row.Scan(&p.Id, &p.UserId, &p.Name) // Scanで指定した変数に格納
	if err != nil {
		if err == sql.ErrNoRows {
			log.Println("No row")
		} else {
			log.Println(err)
		}
	}
	log.Print(p.Id, p.UserId, p.Name)

	c.HTML(http.StatusOK, "edit", gin.H{"User": p})

}

func Update(c *gin.Context) {
	log.Print("更新処理")
	DbConnection, _ := sql.Open("sqlite3", "./db/sqlite3/test.db") // main.goからのパスを指定
	defer DbConnection.Close()

	id := c.Param("id") // URLの:idを取得

	userid := c.PostForm("userID") // 画面の値を取得
	name := c.PostForm("name")     // 画面の値を取得

	cmd := "UPDATE m_users SET user_id = ?, name = ? WHERE id = ?"
	_, err := DbConnection.Exec(cmd, userid, name, id)
	if err != nil {
		log.Fatalln(err)
	}

	c.Redirect(http.StatusMovedPermanently, "/user")

}

func Delete(c *gin.Context) {
	log.Print("削除処理")
	DbConnection, _ := sql.Open("sqlite3", "./db/sqlite3/test.db") // main.goからのパスを指定
	defer DbConnection.Close()

	id := c.Param("id") // URLの:idを取得

	cmd := "DELETE FROM m_users WHERE id = ?"
	_, err := DbConnection.Exec(cmd, id)
	if err != nil {
		log.Fatalln(err)
	}

	c.Redirect(http.StatusMovedPermanently, "/user")

}

```

##ビュー

```html:index.html
{{define "index"}}
<!DOCTYPE html>
<html lang="jp">
<head>
    <meta charset="UTF-8">
    <title>一覧</title>
</head>
<body>
    <a href="/user/new">新規</a> 
 <ul>
    {{range .Users}}
    <li>
      {{.Id}} {{.UserId}} {{.Name}} 
      <a href="/user/show/{{.Id}}">参照</a> 
      <a href="/user/edit/{{.Id}}">編集</a> 
      <a href="/user/delete/{{.Id}}" onclick="return confirm(`削除しますか？`)">削除</a> 
    </li>
    {{end}}
  </ul>
</body>
</html>
{{end}}
```

```html:show.html
{{define "show"}}
<!DOCTYPE html>
<html lang="jp">
<head>
    <meta charset="UTF-8">
    <title>参照</title>
</head>
<body>
 <ul>
    <li>
      {{.User.Id}} {{.User.UserId}} {{.User.Name}} 
    </li>
  </ul>
</body>
</html>
{{end}}
```

```html:edit.html
{{define "edit"}}
<!DOCTYPE html>
<html lang="jp">
<head>
    <meta charset="UTF-8">
    <title>編集</title>
</head>
<body>
 <ul>
    <form action="/user/edit/{{.User.Id}}" method="POST">
      <input type="text" name="userID" value="{{.User.UserId}} ">
      <br>
      <input type="text" name="name" value="{{.User.Name}} ">
      <br>
      <input type="submit" value="更新">
    </form>
  </ul>
</body>
</html>
{{end}}
```

```html:new.html
{{define "new"}}
<!DOCTYPE html>
<html lang="jp">
<head>
    <meta charset="UTF-8">
    <title>新規登録</title>
</head>
<body>
    <form action="/user/new" method="POST">
        user_id:<input type="text" name="userID">
        <br>
        name: <input type="text" name="name">
        <br>
        <input type="submit" value="登録">
  </form>
</body>
</html>
{{end}}
```