LoginSignup
1
0

More than 5 years have passed since last update.

Go言語を真剣に勉強してみた〜番外編〜

Last updated at Posted at 2018-10-16

はじめに

こんにちは。某学校でプログラミング等の勉強中のサーバーサイドのプログラマーのワタタクです。:relaxed:
さて今回は「Go言語を真剣に勉強してみた〜番外編〜」と言うことでこれまで紹介してきたもので簡単なWEBアプリケーションを作れるようになったので作ってみたいと思います。
今回はGoとMysqlを使って簡単なWEBアプリケーションを作っていきます。
では、早速いってみましょう:point_up:

完成形

スクリーンショット 2018-10-16 9.50.44.png
※ここから各種ボタンを押すことによって、各種の適切な動きが出てくるアプリケーション。

テーブル作成

CREATE TABLE dept (
    deptno INT(2), 
    dname TEXT, 
    loc TEXT,
    PRIMARY KEY(deptno)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

次にカラムを追加します。

INSERT INTO dept (deptno, dname, loc) VALUES (10,'ACCOUNTING','NEW YORK');
INSERT INTO dept (deptno, dname, loc) VALUES (20,'RESEARCH','DALLAS');
INSERT INTO dept (deptno, dname, loc) VALUES (30,'SALES','CHICAGO');
INSERT INTO dept (deptno, dname, loc) VALUES (40,'OPERATIONS','BOSTON');

ディレクトリ構成

scottadmin
 |-Pkg
 |  |-entitys
 |  |    |-dept.go
 |  |-dao
 |     |-deptDAO.go
 |-server.go
 |-static
    |-css
    |   |-main.css
    |-view
    |   |-deptList.html.tpl
    |-add
    |   |-goDeptadd.html.tpl
    |-edit
    |   |-deptEdit.html.tpl
    |-delete
        |-confirmDeptDelete.html.tpl

以上で準備完了なので早速作っていきましょう

パッケージ(entitys、dao)

パッケージについてはこちらを参照「Go言語を真剣に勉強してみた〜パッケージ編〜」から。

dept.go
package entitys

type Dept struct {
    Deptno int
    Dname  string
    Loc    string
}

type DeptList []Dept
deptDAO.go
package dao

import (
    "../entitys"
    "database/sql"
    "fmt"
    _ "github.com/go-sql-driver/mysql"
    "log"
)

/**
 *全件取得
 *引数:dbオブジェクト
 *戻り値:構造体のDeptList
 */
func FindAll(db *sql.DB) *entitys.DeptList {
    rows, err := db.Query("SELECT * FROM dept")
    if err != nil {
        log.Fatal(err);
    }

    defer rows.Close()
    var d entitys.Dept
    var deptList entitys.DeptList
    for rows.Next() {
        err := rows.Scan(&d.Deptno, &d.Dname, &d.Loc)
        if err != nil {
            log.Fatal(err)
        }
        deptList = append(deptList, d)//構造体のDeptを配列「DeptList」に入れている
        fmt.Println(deptList);
    }
    return &deptList
}

データベースの扱いについては「Go言語を真剣に勉強してみた〜データベース接続(MySQL)編〜」から。

ついでにその他更新系などのメソッドも作っちゃいましょう。

deptList.go
/**
 *主キー検索
 *引数:dbオブジェクト、部門番号
 *戻り値:構造体Dept
 */
func FindByPk(db *sql.DB, deptno string) *entitys.Dept {
    stmt, err := db.Prepare("SELECT * FROM dept WHERE deptno = ?")
    if err != nil {
        log.Fatal(err)
    }
    var d entitys.Dept
    err = stmt.QueryRow(deptno).Scan(&d.Deptno, &d.Dname, &d.Loc)
    if err != nil {
        log.Fatal(err)
    } 
    return &d
}

/**
 *削除
 *引数:dbオブジェクト、部門番号
 *戻り値:なし
 */
func Delete(db *sql.DB, deptno string) {
    tr,err := db.Begin()
    if err != nil {
        log.Fatal(err)
    }
    stmt, err := db.Prepare("DELETE FROM dept WHERE deptno=?")
    if err != nil {
        log.Fatal(err)
        tr.Rollback()
    }
    res, err := stmt.Exec(deptno)
    if err != nil {
        log.Fatal(err)
        tr.Rollback()
    }
    tr.Commit()
    fmt.Println(res)
    fmt.Println("部門番号" + deptno + "を削除しました")

}

/**
 *更新
 *引数:dbオブジェクト、部門名、所在地、部門番号
 *戻り値:なし
 */
func Update(db *sql.DB, dname, loc, deptno string) {
    tr,err := db.Begin()
    if err != nil {
        log.Fatal(err)
    }
    stmt, err := db.Prepare("UPDATE dept SET dname=?,loc=? WHERE deptno=?")
    if err != nil {
        log.Fatal(err)
        tr.Rollback()
    }
    res, err := stmt.Exec(dname,loc, deptno)
    if err != nil {
        log.Fatal(err)
        tr.Rollback()
    }
    tr.Commit()
    fmt.Println(res)
    fmt.Println("部門番号" + deptno + "を更新しました")
}

/**
 *追加
 *引数:dbオブジェクト、部門番号、部門名、所在地
 *戻り値:なし
 */
func Insert(db *sql.DB, deptno string, dname string, loc string) {
    tr,err := db.Begin()
    if err != nil {
        log.Fatal(err)
    }
    stmt, err := db.Prepare("INSERT INTO dept(deptno, dname, loc) VALUES(?, ?, ?)")
    if err != nil {
        log.Fatal(err)
        tr.Rollback()
    }
    res, err := stmt.Exec(deptno, dname, loc)
    if err != nil {
        log.Fatal(err)
        tr.Rollback()
    }
    fmt.Println(res)

}

main処理

サーバの起動法などについては「Go言語を真剣に勉強してみた〜WEBアプリケーション開発編〜」

server.go
package main

import (
    "./Pkg/entitys"
    "./Pkg/dao"
    "database/sql"
    "fmt"
    "html/template"
    "log"
    "net/http"
    "os"
)

func deptList(w http.ResponseWriter, r *http.Request) {
    path, _ := os.Getwd()
    // テンプレートをパース
    t := template.Must(template.ParseFiles(path + "/static/view/deptList.html.tpl"))
    //DB処理
    db, err := sql.Open("mysql", "scott:tiger@tcp(127.0.0.1:8889)/wp32scott")//通常:ポート番号3306、*manp:8889
    if err != nil {
        log.Fatal(err)
    }
    err = db.Ping()
    if err != nil {
        fmt.Println("データベース接続失敗")
    }

    defer db.Close()
     deptList := dao.FindAll(db)
     if deptList == nil {
        fmt.Println("から")
     }

    // テンプレートを描画
    if err := t.ExecuteTemplate(w, "deptList.html.tpl", deptList); err != nil {
      log.Fatal(err)
    }



}

func add(w http.ResponseWriter, r *http.Request)  {
    path, _ := os.Getwd()
    // テンプレートをパース
    t := template.Must(template.ParseFiles(path + "/static/add/goDeptAdd.html.tpl"))
    // テンプレートを描画
    if err := t.ExecuteTemplate(w, "goDeptAdd.html.tpl", nil); err != nil {
        log.Fatal(err)
    }
}

func addNow (w http.ResponseWriter, r *http.Request) {
    deptno := r.FormValue("addDeptDeptno")
    dname := r.FormValue("addDeptDname")
    loc := r.FormValue("addDeptLoc")
    db, err := sql.Open("mysql", "scott:tiger@tcp(127.0.0.1:8889)/wp32scott")//通常:ポート番号3306、*manp:8889
    if err != nil {
        log.Fatal(err)
    }
    err = db.Ping()
    if err != nil {
        fmt.Println("データベース接続失敗")
    }
    defer db.Close()

    dao.Insert(db, deptno, dname, loc)

    http.Redirect(w, r, "/view", http.StatusMovedPermanently)

}

func edit(w http.ResponseWriter, r *http.Request) {
    var deptno string
    deptno = r.FormValue("editDeptDeptno")

    path, _ := os.Getwd()
    // テンプレートをパース
    t := template.Must(template.ParseFiles(path + "/static/edit/deptEdit.html.tpl"))
    //DB処理
    db, err := sql.Open("mysql", "scott:tiger@tcp(127.0.0.1:8889)/wp32scott")//通常:ポート番号3306、*manp:8889
    if err != nil {
        log.Fatal(err)
    }
    err = db.Ping()
    if err != nil {
        fmt.Println("データベース接続失敗")
    }

    defer db.Close()
    deptList := dao.FindByPk(db, deptno)
    if deptList == nil {
        fmt.Println("空")
    }

    // テンプレートを描画
    if err := t.ExecuteTemplate(w, "deptEdit.html.tpl", deptList); err != nil {
        log.Fatal(err)
    }
}

func editNow(w http.ResponseWriter, r *http.Request)  {
    dname := r.FormValue("editDeptDname")
    loc := r.FormValue("editDeptLoc")
    deptno := r.FormValue("editDeptDeptno")
    db, err := sql.Open("mysql", "scott:tiger@tcp(127.0.0.1:8889)/wp32scott")//通常:ポート番号3306、*manp:8889
    if err != nil {
        log.Fatal(err)
    }
    err = db.Ping()
    if err != nil {
        fmt.Println("データベース接続失敗")
    }
    defer db.Close()

    dao.Update(db, dname, loc, deptno)

    http.Redirect(w, r, "/view", http.StatusMovedPermanently)

}


func delete(w http.ResponseWriter, r *http.Request) {
    var deptno string
    deptno = r.FormValue("deleteDeptDeptno")
    path, _ := os.Getwd()
    // テンプレートをパース
    t := template.Must(template.ParseFiles(path + "/static/delete/confirmDeptDelete.html.tpl"))
    //DB処理
    db, err := sql.Open("mysql", "scott:tiger@tcp(127.0.0.1:8889)/wp32scott")//通常:ポート番号3306、*manp:8889
    if err != nil {
        log.Fatal(err)
    }
    err = db.Ping()
    if err != nil {
        fmt.Println("データベース接続失敗")
    }

    defer db.Close()
    deptList := dao.FindByPk(db, deptno)
    if deptList == nil {
        fmt.Println("空")
    }

    // テンプレートを描画
    if err := t.ExecuteTemplate(w, "confirmDeptDelete.html.tpl", deptList); err != nil {
        log.Fatal(err)
    }
}

func deleteNow(w http.ResponseWriter, r *http.Request) {
    deptno := r.FormValue("deleteDeptDeptno")

    db, err := sql.Open("mysql", "scott:tiger@tcp(127.0.0.1:8889)/wp32scott")//通常:ポート番号3306、*manp:8889
    if err != nil {
        log.Fatal(err)
    }
    err = db.Ping()
    if err != nil {
        fmt.Println("データベース接続失敗")
    }
    defer db.Close()

    dao.Delete(db,deptno)

    http.Redirect(w, r, "/view", http.StatusMovedPermanently)

}

func main() {
    http.Handle("/", http.FileServer(http.Dir("static")))

    /**
     *部門リスト
     */
    http.HandleFunc("/view/", deptList)
    http.HandleFunc("/add/", add)
    http.HandleFunc("/add/now", addNow)
    http.HandleFunc("/edit", edit)
    http.HandleFunc("/edit/now", editNow)
    http.HandleFunc("/delete", delete)
    http.HandleFunc("/delete/now", deleteNow)

    http.ListenAndServe(":9000", nil)
}

テンプレート

deptList.html.tpl
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <title>部門情報リスト|ScottAdmin</title>
    <link rel="stylesheet" type="text/css" href=" ../css/main.css">
</head>
<body>
<h1>部門情報リスト</h1>
<nav>
    <ul>
        <li><a href="/">TOP</a></li>
        <li>部門情報リスト</li>
    </ul>
</nav>
<section>
    <p>
        新規登録は<a href="/add">こちら</a>から
    </p>
</section>

<section>
    <table>
        <thead>
        <tr>
            <th>部門番号</th>
            <th>部門名</th>
            <th>所在地</th>
            <th colspan="2">操作</th>
        </tr>
        </thead>
        <tbody>
        {{ range .}}
        <tr>
            <td>{{.Deptno}}</td>
            <td>{{.Dname}}</td>
            <td>{{.Loc}}</td>
            <td>
                <form action=" /edit" method="post">
                    <input type="hidden" name="editDeptDeptno" id="editDeptDeptno" value="{{.Deptno}}">
                    <input type="submit" value="編集">
                </form>
            </td>
            <td>
                <form action=" /delete" method="post">
                    <input type="hidden" name="deleteDeptDeptno" id="deleteDeptDeptno" value="{{.Deptno}}">
                    <input type="submit" value="削除">
                </form>
            </td>
        </tr>
        {{ end }}
        </tbody>
    </table>
</section>
</body>
</html>
goDeptAdd.html.tpl
<!DOCTYPE html>
<html lang="ja">
<head>
    <title>部門情報追加|ScottAdmin</title>
    <link rel="stylesheet" type="text/css" href=" ../css/main.css">
    <meta charset="utf-8">
</head>
<body>
<h1>部門情報追加</h1>
<nav>
    <ul>
        <li><a href=" /">TOP</a></li>
        <li><a href=" /view">部門リスト</a></li>
        <li>部門情報追加</li>
    </ul>
</nav>

<section>
    <p>情報を入力し、登録ボタンをクリックしてください</p>

    <form action=" /add/now" method="post">
        <table>
            <tbody>
            <tr>
                <th>部門番号&nbsp;<span class="required">必須</span></th>
                <td><input type="text" name="addDeptDeptno" id="addDeptDeptno" value=""></td>
            </tr>
            <tr>
                <th>部門名&nbsp;<span class="required">必須</span></th>
                <td><input type="text" name="addDeptDname" id="addDeptDname" value="" ></td>
            </tr>
            <tr>
                <th>所在地</th>
                <td><input type="text" name="addDeptLoc" id="addDeptLoc" value=""></td>
            </tr>
            <tr>
                <td colspan="2" class="submit"><input type="submit" value="登録"></td>
            </tr>
            </tbody>
        </table>
    </form>
</section>
</body>
</html>
deptEdit.html.tpl
<!DOCTYPE html>
<html lang="ja">
<head>
    <title>部門情報編集|ScottAdmin</title>
    <link rel="stylesheet" type="text/css" href=" ../css/main.css">
    <meta charset="utf-8">
</head>
<body>
<h1>部門情報編集</h1>
<nav>
    <ul>
        <li><a href=" /">TOP</a></li>
        <li><a href=" /view">部門リスト</a></li>
        <li>部門情報編集</li>
    </ul>
</nav>
<section>
    <p>情報を入力し、更新ボタンをクリックしてください</p>

    <form action=" /edit/now" method="post">
        <table>
            <tbody>
            <tr>
                <th>部門番号</th>
                <td>{{ .Deptno }}<input type="hidden" name="editDeptDeptno" id="editDeptDeptno" value="{{ .Deptno}}"></td>
            </tr>
            <tr>
                <th>部門名&nbsp;<span class="required">必須</span></th>
                <td><input type="text" name="editDeptDname" id="editDeptDname" value="{{ .Dname}}" required></td>
            </tr>
            <tr>
                <th>所在地</th>
                <td><input type="text" name="editDeptLoc" id="editDeptLoc" value="{{ .Loc }}"></td>
            </tr>
            <tr>
                <td colspan="2" class="submit"><input type="submit" value="更新"></td>
            </tr>
            </tbody>
        </table>
    </form>
</section>
</body>
</html>
confirmDeptDelete.html.tpl
<!DOCTYPE html>
<html lang="ja">
<head>
    <title>部門情報削除|ScottAdmin</title>
    <link rel="stylesheet" type="text/css" href=" ../css/main.css">
    <meta charset="utf-8">
</head>
<body>
<h1>部門情報削除</h1>
<nav>
    <ul>
        <li><a href=" /">TOP</a></li>
        <li><a href=" /view">部門リスト</a></li>
        <li>部門情報削除</li>
    </ul>
</nav>

<section>
    <p>以下の部門情報を削除します。よろしければ、削除ボタンを押してください。</p>

    <form action=" /delete/now " method="post">
        <table border="1">
            <tbody>
            <tr>
                <th>部門番号</th>
                <td>{{ .Deptno }}<input type="hidden" name="deleteDeptDeptno" id="deleteDeptDeptno" value="{{ .Deptno}}"></td>
            </tr>
            <tr>
                <th>部門名</th>
                <td>{{ .Dname }}</td>
            </tr>
            <tr>
                <th>所在地</th>
                <td>{{ .Loc }}</td>
            </tr>
            <tr>
                <td colspan="2" class="submit"><input type="submit" value="削除"></td>
            </tr>
            </tbody>
        </table>
    </form>
</section>
</body>
</html>

おまけ

main.css
@charset "UTF-8";
table{
    border-collapse: collapse;
}
table th{
    border:solid 1px black;
}
table td{
    border:solid 1px black;
}
nav ul li{
    display: inline;
    list-style-type: none;
}
nav ul .current{
    color: red;
}
nav ul li:before{
    content:">";
}
nav ul li:first-child:before{
    content:none;
}
.submit{
    text-align: center;
}
.required{
    color: red;
    font-size: 20px;
}
#errorMsg{
    border:solid 1px orange;
    color: red;
    padding: 10px;
    margin:20px;
    width: 400px;
}

以上。

最後に

もし何か間違っている等のご指摘があればご連絡ください。

※このサンプルで作ったアプリケーションはエラーメッセージやフラッシュメッセージ等が出ません。更にエラー処理などもしていません。
出し方などについてはまたこれから頑張ります。
まだまだ勉強しないとダメだな〜w

最後まで読んで頂きありがとうございました。

追記(2018/10/17)

ご指摘があったので訂正。
パッケージ名entitysなのですが、entityの複数形はentitysではなくentitiesでした。申し訳ありません。

1
0
1

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