Go言語

Go言語Webアプリ開発日記(1日目)

更新日:

GoフレームワークのGin

今まで、PHPフレームワークのLaravelで社内サイトを作成してきましたが、コンパイル言語のGoで作り直すために、今勉強中です。

いくつかGo言語のフレームワークを調べてきましたが、Ginが私には、しっくり来そうなので、Ginフレームワークで学習していきたいと思います。フルススタックフレームワークのRevelや軽量高速を謳っているEchoとかも調べてみましたが、とりあえず、Ginについて調べたことを少しずつ書き込んでいきたいと思います。

もしまちがいがあれば、ご指摘いただければ幸いです。

参考サイト

開発環境

  • さくらのVPS
  • CentOS7.1 + Nginx
  • Goバージョン go1.10
  • InteliJIDEA

Nginxの設定

  • ターミナルで vi /etc/nginx/conf.d/gin.conf で下記を作成
  • 下記のようにNginxを設定することで、http://gin.sakura-server.jp(仮)にアクセスするとGinのプログラムが起動する。
server {
      listen 80;
      server_name gin.sakura-server.jp;
      location ~ / {
        proxy_pass http://127.0.0.1:8080;
        }
    }

InteliJIDEAの設定

  • InteliJIdeaでツール→デプロイ→構成をクリック
  • +(追加)をクリック
  • サーバーの追加ダイアログが表示されたらサーバー名(任意)を入力して、SFTPを選択後にOKをクリック
  • SFTPホスト:133.***.***.199
  • ポート:22
  • ルートパス:/home/***/go/src/gin
  • ユーザー名:***
  • 認証タイプ:Key pair ( OpenSSH or PuTTY)
  • プライベート・キーファイル:/Users/***/.ssh/sakura/id_rsa
  • Webサーバー・ルートURL:http://gin.sakura-server.jp
  • マッピングタブのサーバーのデプロイ・パスに / を記入してOKをクリック
  • ツール→デプロイ→次へアップロードgin.sakura-serverjpを選択
  • データがアップされたらターミナルからSakuraに接続

フォルダ構成

  • MVCパターンで作成していきたいと思いますので、まずルートフォルダにcontrollers、models、viewsフォルダを作成します。
  • そしてMainパッケージとしてserver.goファイルを作成します。

Mainパッケージの作成

  • ルートフォルダ上にserver.go名でファイルを作成し、下記のように記述
  • gin/server.go
package main

import (
    "github.com/gin-gonic/gin"
    c "gin/controllers"
)

func main() {
        r := gin.Default()
        r.LoadHTMLGlob("views/*")
        r.GET("/", c.GetUser)
        r.Run(":8080") 
}

基礎的なことですが、Go言語はmainパッケージのmain()関数から実行されます。必要なのは、ファイル名ではなくパッケージ名ですので、ファイル名はmain.goでもserver.goでも全く同じです。

  • 1行目でパッケージ名を入力します。
  • 4行目でgithubからginパッケージをインポートしています。
  • 5行目は、現在作成中のアプリケーションのcontrollersパッケージを変数cの名前でインポートしています。
  • これで、c.GetUserのようにcontrollersフォルダ内の関数を呼び出すことができます。
  • 上記でcontrollersフォルダと記入しましたが、実際には、controllersパッケージのことです。
  • 9行目のgin.Default()とgin.New()の違いは、組み込まれているmiddleweareの違いのはずです。基本的にgin.Defautl()を記入しておけば間違いがないはずです。
  • 10行目のr.LoadHTMLGlob()でビューフォルダの指定をしています。
  • 10行目のr.GET()の第1引数で、URI、第2引数で処理を指定します。第2引数のc.GetUserはcontrollersパッケージのGetUser関数を呼び出しています。
  • r.Run(":8080")でサーバーを起動して、8080番ポートを待ち受けます。

コントローラの作成

  • ルートディレクトリにcontrollersフォルダを作成し、下記のようなファイルを作成
  • gin/controllers/user.go
  • controllersパッケージの中にいくつファイルがあっても一つのパッケージとして認識しているはずですので、中の関数名は重複しないように作成する必要があります。
package controllers

import (
	"github.com/gin-gonic/gin"
	"net/http"
	m "gin/models"
)
func GetUsers(c *gin.Context){
   u := m.User{}
   users := u.GetUsers()
   c.HTML(http.StatusOK, "user.html", users)
}
  • 1行目にパッケージ名(controllers)を指定しています。
  • 6行目の"gin/models"は現在作成中のパッケージを変数mの名前で呼び出します。
  • GetUser()関数のGが大文字なのには意味があります。Go言語では、関数の最初の文字が大文字なら、他のパッケージから呼び出すことができますが、これがgetUser()なら同じパッケージ内からしか呼び出すことができません。
  • ですので、server.goのmainパッケージから呼び出されたこの関数が実行されるのです。
  • 9行目のu:=m.User{}は、modelsパッケージ内のUser構造体を初期化し、変数uに代入しています。
  • そして次にmodels内のUser構造体のGetUsers()メソッドを変数usersに代入しています。
  • 最後のc.HTML()メソッドの第1引数は、ステータスコードですので、数値の200を記入しても同じことです。第2引数はビューファイル名、第3引数は、そのビューに渡すデータを指定します。
  • 尚、PHPでは、ステータスコードとかをいちいち考える必要がなかったのですが、Go言語では、結構頻繁にステータスコードが出てきますので、再度ステータスコードを勉強する機会になりました。

モデルの作成

  • modelsフォルダ内にuser.goファイルを作成し、下記のように記述します。なお、controllerとmodelに同じ名前があるのに抵抗がある人は、別ファイル名で作成してもいいと思います。InteliJIDEAでは、同じファイル名を2つ開けるとフォルダ名/ファイル名としてタブに表示されるので、同じ名前でも間違えることがないと思い、同じ名前にしました。
  • gin/models/user.go
package models

import "time"

type User struct {
	ID 		int
	Name 		string          `gorm:"not null"`
	Email   	string		`gorm:"not null;unique"`
	CreatedAt	time.Time
	UpdatedAt	time.Time
	DeletedAt	*time.Time
}
func (u User) GetUsers() *[]User {
   db := GormDB()
   users := &[]User{}
   db.Find(users)
   return users
}
  • 5行目でUser構造体を作成しています。これはデータベースのusersテーブルとリンクさせます。
  • ORMはGormを使用しています。データベースを呼び出す関数は同じ、modelsパッケージ内にgorm.go名で作成します。
  • 9ー10行目のCreatedAtとUpdatedAtはGormが自動的に作成時と修正時を入力してくれます。
  • 11行目のDeletedAtはソフトデリートを実現してくれます。ソフトデリートとは、deleteコマンドで実際にデータを削除するのではなく、削除されたように見せかける仕掛けです。データを誤って削除しないための工夫です。
  • 13行目の(u User)はレシーバーと呼ばれ、User構造体を変数uとを紐づけます。
  • *[]Userは、User構造体のスライスを返します。
  • 14行目のGormDB()は、データベースを呼び出すための関数です。別ファイルgorm.goで作成します。
  • 15行目は、変数usersにUser構造体のスライスを代入しています。
  • db.Find()メソッドは、usersテーブルの全データを取得します。

Gormの設定

  • 上記と同じmodels内にgorm.goを作成し、データベースとの接続用の関数を作成します。
  • gin/models/gorm.go
package models

import (
	_ "github.com/go-sql-driver/mysql"
	"github.com/jinzhu/gorm"
)
func GormDB() *gorm.DB {
	DBMS     := "mysql"
	USER     := "root"
	PASS     := "My_password"
	PROTOCOL := "tcp(127.0.0.1:3306)"
	DBNAME   := "GODB"
	TIME 	 := "?parseTime=true"

	CONNECT := USER+":"+PASS+"@"+PROTOCOL+"/"+DBNAME + TIME
	db,err := gorm.Open(DBMS, CONNECT)

	if err != nil {
		panic(err.Error())
	}
	db.LogMode(true)
	db.AutoMigrate(&User{})
	return db
}
  • 4行目:データベースはMySQLを使用しますので、MySQLドライバーをインポートします。
  • 5行目でGormパッケージをインポートしています。
  • 7行目のGormDB()関数は、データベースに接続して、gormパッケージのDBメソッドを返します。
  • 16行目のgorm.Open()メソッドは、第1引数に接続するデータベース名、第2引数に接続情報をセットします。

ビューの作成

  • 最後にViewを作成すれば、基本的なアプリは完成します。
  • Viewは、毎回使う同じタグは、それぞれ、header.html、footer.html、navbar.html等の名称で、作成してviewsフォルダ内に置いておきます。
  • views/header.html
{{define "header"}}
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Gin入門</title>
<!-- ここにBootStrap等のリンクやScriptを記述 -->
</header>
<body>
{{end}}
  • views/footer
{{define "footer"}}
<script>
    //ここにBootstrap等のScriptを記述する
</script>
</body>
</html>
{{end}}
  • views/navbar.html
{{define "navbar"}}
<nav class="navbar navbar-fixed-top navbar-default" role="navigation">
<!-- ここに中身を記述します(省略)-->
</nav>
{{end}}
  • ビューのファイル名は、どんなファイル名を使っても全く関係ありません。{{define "header"}}から{{end}}までの間の文字列をテンプレートとして認識します。
  • ですので、実際にビューを使用するには、呼び出すビューファイル名の中に上記のテンプレートを組み込みます。
  • 実際に呼び出すテンプレートindex.htmlを下記のように記述します。
{{template "header"}}
{{template "navbar"}}
    <table class="table table-borderless table-striped">
        <tr class="table-primary">
            <th>氏名</th>
            <th>Eメール</th>
            <th>作成日</th>
        </tr>
    {{range .}}
        <tr>
            <td>{{.Name}}</td>
            <td>{{.Email}}</td>
            <td>{{.CreatedAt}}</td>
        </tr>
    {{end}}
    </table>
{{template "footer"}}
  • それぞれの{{template "header"}}、{{template "navbar"}}、{{template "footer"}}の箇所で上記で作成した、header.html、navbar.htm、footer.htmlの中身のタグ部分が適用されます。
  • {{range .}}から{{end}}までの間がデータベースの回数分繰り返し処理されます。PHPのforeach文と同じです。
  • Go言語の面白いところは、.  (ドット)だけで全てのデータを表示するところです。つまりこの .  (ドット)は、models/user.goのGetUsersメソッドから送られたusersデータです。
  • 実際にそのデータの中身に直接アクセスするには  .Nameのように .  (ドット)のあとに、フィールド名を記述します。

これで、ターミナルから、go run server.goと入力すると下記のようなWebアプリが完成します。

たった1日でこれだけのアプリが作れるのですから、Go言語(Gin)恐るべし。

今回のアプリを少しずつ修正しながら、Go言語の勉強をしてみようと思います。

-Go言語

Copyright© WinRoad徒然草 , 2018 All Rights Reserved Powered by AFFINGER5.