はじめに
こんにちは。某学校でプログラミング等の勉強中のサーバーサイドのプログラマーのワタタクです。
さて今回は「Go言語を真剣に勉強してみた〜番外編〜」と言うことでこれまで紹介してきたもので簡単なWEBアプリケーションを作れるようになったので作ってみたいと思います。
今回はGoとMysqlを使って簡単なWEBアプリケーションを作っていきます。
では、早速いってみましょう
完成形
※ここから各種ボタンを押すことによって、各種の適切な動きが出てくるアプリケーション。
テーブル作成
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言語を真剣に勉強してみた〜パッケージ編〜」から。
package entitys
type Dept struct {
Deptno int
Dname string
Loc string
}
type DeptList []Dept
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)編〜」から。
ついでにその他更新系などのメソッドも作っちゃいましょう。
/**
*主キー検索
*引数: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アプリケーション開発編〜」
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)
}
テンプレート
<!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>
<!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>部門番号 <span class="required">必須</span></th>
<td><input type="text" name="addDeptDeptno" id="addDeptDeptno" value=""></td>
</tr>
<tr>
<th>部門名 <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>
<!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>部門名 <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>
<!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>
おまけ
@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でした。申し訳ありません。