プログラミング初学者向け Go入門 #2

## 概要
前回の続き。
前回  [プログラミング初学者向け Go入門 #1](https://qiita.com/takuma-goto/items/3807564307fd1bd8f37b)
前回はGoプロジェクトを作成して起動までやったので、今回はDBを使用していく。
これも超簡単。
### 今回のソース
https://github.com/takuma-goto310/sample_golang_2
## 準備
前回同様、git cloneしたあと、mysqlを入れていない人はmysqlの設定から。
参考 : https://qiita.com/hkusu/items/cda3e8461e7a46ecf25d

### mysqlの準備ができたら、dbの追加をする

```sql
mysql> create database gosample;
```
### go-sql-driverをインストール
```console
run $ go get -u github.com/go-sql-driver/mysql
```

### ディレクトリ構成

```console
.
├── README.md
├── app
│   ├── controller
│   │   └── app.go
│   ├── db
│   │   └── db.go
│   ├── models
│   │   └── user.go
│   └── view
│       ├── detail.html
│       ├── footer.html
│       ├── header.html
│       ├── home.html
│       └── index.html
├── public
│   ├── css
│   │   └── bootstrap-3.3.6.min.css
│   ├── fonts
│   │   ├── glyphicons-halflings-regular.ttf
│   │   ├── glyphicons-halflings-regular.woff
│   │   └── glyphicons-halflings-regular.woff2
│   ├── img
│   │   └── favicon.png
│   └── js
│       ├── bootstrap-3.3.6.min.js
│       └── jquery-2.2.4.min.js
└── run
    ├── main
    ├── main.go
    ├── run
    └── src
        └── github.com
            └── go-sql-driver
                └── mysql
                    ├── AUTHORS
                    ├── CHANGELOG.md
                    ├── CONTRIBUTING.md
                    ├── LICENSE
                    ├── README.md
                    ├── appengine.go
                    ├── auth.go
                    ├── auth_test.go
                    ├── benchmark_test.go
                    ├── buffer.go
                    ├── collations.go
                    ├── connection.go
                    ├── connection_test.go
                    ├── const.go
                    ├── driver.go
                    ├── driver_test.go
                    ├── dsn.go
                    ├── dsn_test.go
                    ├── errors.go
                    ├── errors_test.go
                    ├── fields.go
                    ├── infile.go
                    ├── packets.go
                    ├── packets_test.go
                    ├── result.go
                    ├── rows.go
                    ├── statement.go
                    ├── statement_test.go
                    ├── transaction.go
                    ├── utils.go
                    └── utils_test.go
```
## 起動方法
ターミナルでrunディレクトリに移動する。

```console
run $ go run main.go
```
## 内容
重要な部分だけここで紹介。

- sample_golang_2/app/controller/app.go

```go

// Home is method to render Name page.
func Home(rw http.ResponseWriter, request *http.Request){
	tmpl := parseTemplate()

	// db connection
	dbm := db.ConnDB()
	users := []models.User{}

	rows, err := dbm.Query("select id, name from users")
	for rows.Next() {
		user := models.User{}
		if err = rows.Scan(&user.ID, &user.Name); err != nil {
			// 変換に失敗した場合、INDEX画面表示
			toIndex(tmpl, rw, request, "ユーザ データ変換 失敗", err)
			return
		}
		users = append(users, user)
	}

	// HOME画面表示
	err = tmpl.ExecuteTemplate(rw, "home.html", struct {
		Users []models.User
	}{
		Users: users,
	})
	if err != nil {
		outputErrorLog("HTML 描画 エラー", err)
	}
}

// Detail is method to render Detail page.
func Detail(rw http.ResponseWriter, request *http.Request){
	tmpl := parseTemplate()

	// ID取得
	id := request.URL.Query().Get("id")
	log.Println("id : ", id)

	// db connection
	dbm := db.ConnDB()
	user := new(models.User)
	row := dbm.QueryRow("select id, name from users where id = ?", id)
	if err := row.Scan(&user.ID, &user.Name); err != nil {
		// 変換に失敗した場合、INDEX画面表示
		toIndex(tmpl, rw, request, "ユーザ データ変換 失敗", err)
		return
	}

	// Detail画面表示
	err := tmpl.ExecuteTemplate(rw, "detail.html", struct {
		User     *models.User
	}{
		User:     user,
	})
	if err != nil {
		outputErrorLog("HTML 描画 エラー", err)
	}
}

// ユーザー情報更新
func Edit(rw http.ResponseWriter, request *http.Request){
	tmpl := parseTemplate()

	// 変更する名前とIDを取得
	err := request.ParseForm()
	if err != nil {
		// パースに失敗したらエラー
		toIndex(tmpl, rw, request, "フォーム パース エラー", err)
		return
	}
	name := request.Form.Get("name")
	log.Println("変更する名前：", name)

	id := request.Form.Get("id")
	log.Println("変更する対象ID：", id)

	// db connection
	dbm := db.ConnDB()
	_, err = dbm.Exec("update users set name = ? where id = ?", name, id)
	if err != nil {
		log.Println("ユーザー 更新 失敗")
	} else {
		log.Println("ユーザー 更新 成功")
		log.Println("更新したユーザーID：", id)
	}

	// HOME画面表示
	http.Redirect(rw, request, "/home", http.StatusFound)
}
```
DBの
- 複数行検索
- 単一行検索
- 更新
をし、GET/POSTメソッドのvalueの受け取り、値の画面への受け渡しをしている。
ここを抑えてしまえば、単純なwebアプリケーションは大概作成できるといっても過言ではないはず。

- sample_golang_2/app/db/db.go

```go
import (
	"database/sql"
	"log"

	_ "github.com/go-sql-driver/mysql"
)

var db *sql.DB

// InitDB is method to initialize DB
func InitDB() {

	// DB接続
	log.Println("== DB 接続 ==")
	db, err := sql.Open("mysql", "root@/gosample")
	if err != nil {
		log.Println("DB 接続 エラー")
		log.Fatalln(err)
	}
	log.Println("== DB 接続 成功 ==")

	// 既存のテーブル削除
	log.Println("== DB 削除 ==")
	db.Exec("DROP TABLE users")
	log.Println("== DB 削除 成功 ==")

	// テーブル生成
	log.Println("== DB テーブル 作成 ==")
	_, err = db.Exec(`CREATE TABLE users ( 
		id INTEGER AUTO_INCREMENT PRIMARY KEY, 
		name VARCHAR(32) NOT NULL
		)`)
	if err != nil {
		outputErrorLog("usersテーブル作成失敗", err)
	}

	// データ投入
	log.Println("== DB データ投入 ==")
	_, err = db.Exec(`INSERT INTO users 
		(name)
		VALUES
		('George Washington'),
		('John Adams'),
		('Thomas Jefferson'),
		('James Madison')
	`)
	if err != nil {
		outputErrorLog("データ投入 失敗", err)
	}
	log.Println("== DB データ投入 完了 ==")
}

// CloseDB is method to close DB connection
func CloseDB() {
	if db != nil {
		db.Close()
	}
}

// ConnDB is method to get DB connection
func ConnDB() *sql.DB {
	if db == nil {
		var err error
		db, err = sql.Open("mysql", "root@/gosample")
		if err != nil {
			log.Println("DB 接続 エラー")
			log.Fatalln(err)
		}
	}
	return db
}

// output error log and stop app
func outputErrorLog(message string, err error) {
	log.Println(message)
	log.Fatalln(err)
}
```
ここではDB接続と、初期データの投入をしている。
`github.com/go-sql-driver/mysql`を使用すれば、`sql.Open`でコネクションができるので簡単。
アプリケーションでは多用するので、コネクション接続はファンクション化しておくのが良いと思う。

## 実際に動かしてみる
### TOP画面
<img width="1552" alt="スクリーンショット 2018-11-29 16.42.04.png" src="https://qiita-image-store.s3.amazonaws.com/0/317878/300175ba-62ec-2ef8-ad7b-4cedf83c4b91.png">
### ユーザー 一覧画面
<img width="1552" alt="スクリーンショット 2018-11-29 16.42.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/317878/5fa7ff8e-e1bb-c33d-e0d7-3c02a2fc5fc6.png">
### ユーザーデータ編集画面
<img width="1552" alt="スクリーンショット 2018-11-29 16.42.40.png" src="https://qiita-image-store.s3.amazonaws.com/0/317878/1a1dd7df-2e0a-a812-59cc-4f39d1d9a451.png">
### 編集する
<img width="1552" alt="スクリーンショット 2018-11-29 16.42.53.png" src="https://qiita-image-store.s3.amazonaws.com/0/317878/d590e352-6556-8070-8151-73c8b50f927f.png">
### 更新ボタンクリック後
<img width="1552" alt="スクリーンショット 2018-11-29 16.42.56.png" src="https://qiita-image-store.s3.amazonaws.com/0/317878/2e54b09d-9b85-6ea8-ed5d-56d5324377a0.png">

更新されました。

### 次回
ログイン画面を実装し、基本的なWEBアプリケーションのセキュリティ設定をしていく。
が、最後かな。
アイデアがあれば作るけど、なかなか思いつかない。