post Image
Go言語でDIを試す

Go言語でDIを使ってみる。

利用するFW

アプリ説明

下記をリファクタリング
Mithril+golang Gin を試す

コード

  • jsonとDBアクセスで使う構造体 $GOPATH/src/app/model/todo.go
  • リファクタリング前と変化なし。
todo.go
package model

type Todo struct {
    Id int64 `db:"pk" json:"id"`
    Description string `json:"description"`
    Done bool `json:"done"`
}

dbアクセス

  • DBアクセスするコーッドをinterfaceで抽象化する。
  • repository $GOPATH/src/app/repo/repo.go
repo.go
package repo
import "app/model"

type Repo interface{
    FindAll() []model.Todo
    Save(todo *model.Todo)
}

  • DBアクセス用のセットアップ。
  • グローバル変数使わないようにリファクタリング
db.go
package db
import (
    _ "github.com/mattn/go-sqlite3"
    "github.com/naoina/genmai"
    "app/model"
    "github.com/gin-gonic/gin"
    "fmt"
)
func InitDB() *genmai.DB {

    DB, err := genmai.New(&genmai.SQLite3Dialect{}, ":memory:")
    if err != nil {
        panic(err)
    }

    if err := DB.CreateTable(&model.Todo{}); err != nil {
        panic(err)
    }

    initData := []model.Todo{
        {1, "なんかやる", false},
        {2, "なんかやる2", true},
    }
    if _, err = DB.Insert(&initData); err != nil {
        panic(err)
    }

    return DB
}

/**
トランザクション制御のミドルウェア
 */
func  GetTransactionHandlerFunc(DB *genmai.DB) gin.HandlerFunc {
    return func(c *gin.Context) {
        defer func() {
            if err := recover(); err != nil {
                fmt.Println("END TRANSACTION ROLLBACK")
                DB.Rollback()
                panic(err)
            } else {

                DB.Commit()
                fmt.Println("END TRANSACTION COMMIT")
            }
        }()

        fmt.Println("START TRANSACTION")
        if err := DB.Begin(); err != nil {
            panic(err)
        }

        c.Next()

    }
}
  • reposigoryの実装。
repo.go
package db
import (
    "app/model"
    "github.com/naoina/genmai"
)

type RepoDbImpl struct {
    DB *genmai.DB `inject:""`
}

func (r *RepoDbImpl) FindAll() []model.Todo {

    var todos []model.Todo
    if err := r.DB.Select(&todos, r.DB.OrderBy("id", genmai.ASC)); err != nil {
        panic(err)
    }
    return todos
}

func (r *RepoDbImpl) Save(todo *model.Todo) {

    if num, err := r.DB.Update(todo); err != nil {
        panic(err)

    }else if num == 0 {
        if  _, err := r.DB.Insert(todo);err != nil {
            panic(err)
        }
    }

}

  • mainに書いていたコントローラの記述を別パッッケージに切り出す。 $GOPATH/src/app/ctrl/todoCtrl.go
todoCtrl.go
package ctrl
import (
    "app/repo"
    "github.com/gin-gonic/gin"
    "net/http"
    "app/model"
)

type BaseCtrl struct {
    Repo repo.Repo `inject:""`
}

func (base *BaseCtrl) Index(c *gin.Context) {

    c.HTML(http.StatusOK, "index.html", nil)
}

func (base *BaseCtrl) GetTodo(c *gin.Context) {

    c.JSON(http.StatusOK, base.Repo.FindAll())
}

func (base *BaseCtrl) AddTodo(c *gin.Context) {

    var todo model.Todo
    if c.BindJSON(&todo) == nil {

        base.Repo.Save(&todo)
        c.JSON(http.StatusOK, todo)

    }else {
        c.JSON(http.StatusBadRequest, nil)
    }

}


  • mainでは初期化,DI,ルーティングを記述 $GOPATH/src/app/main/app.go
main.go

package main
import (
    "github.com/gin-gonic/gin"
    "app/db"
    "github.com/facebookgo/inject"
    "app/ctrl"
)

func main() {

    r := gin.Default()
    r.Static("/static", "static")
    r.LoadHTMLGlob("templates/*")

    //dbの初期化
    DB:=db.InitDB()
    r.Use(db.GetTransactionHandlerFunc(DB))


    //コントローラのDI
    ctrl := new(ctrl.BaseCtrl)
    if err := inject.Populate(ctrl, new(db.RepoDbImpl),db.DB); err != nil {
        panic(err)
    }

    r.GET("/", ctrl.Index)
    r.GET("/todo", ctrl.GetTodo)
    r.POST("/todo", ctrl.AddTodo)

    r.Run(":9000")

}

  • インデックスページ(htmlテンプレート)
    $GOPATH/templates/index.html
index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="/static/js/mithril.min.js" type="text/javascript" charset="utf-8"></script>
    <title>Mithril TODO</title>
</head>
<body>
<div id="$contents"></div>

<script type="text/javascript">
    //todo component
    var todo = {};
    //model
    todo.Todo = function (data) {
        this.description = m.prop(data.description);
        this.done = m.prop(data.done);
    };

    todo.TodoList = Array;

    //define the view-model
    todo.vm = (function () {
        var vm = {}
        vm.init = function () {
            //a running list of todos
            vm.list = new todo.TodoList();

            //a slot to store the name of a new todo before it is created
            vm.description = m.prop("");

            //init
            m.request({method: "GET", url: "/todo"}).then(function (todoList) {

                todoList.forEach(function (v) {
                    vm.list.push(new todo.Todo({description: v.description, done: v.done}));
                });

            });

            vm.add = function () {
                if (vm.description()) {

                    m.request({
                        method: "POST",
                        url: "/todo",
                        data: {id:t.id,description: vm.description()}
                    }).then(function (t) {

                        vm.list.push(new todo.Todo({id:t.id,description: t.description}));

                        vm.description("");

                    },function(error){
                        console.log("error ");
                    });
                }
            };
            vm.update = function (task) {

                m.request({
                    method: "POST",
                    url: "/todo",
                    data: {id: task.id(),
                           description:task.description(),
                           done:task.done()}
                }).then(function () {
                    console.log("updated");
                }, function (error) {
                    console.log("error ");
                });
            };

        }
        return vm
    }())

    todo.controller = function () {
        todo.vm.init()
    }

    todo.view = function () {
        return m("div", [
            m("input", {onchange: m.withAttr("value", todo.vm.description), value: todo.vm.description(),}),
            m("button", {onclick: todo.vm.add}, "Add"),
            m("table", [
                todo.vm.list.map(function (task, index) {
                    return m("tr", [
                        m("td", [
                            m("input[type=checkbox]",
                               {
                               onclick:function (e) {
                                    task.done(e.target.checked)
                                    todo.vm.update(task)
                                }
                               ,checked: task.done()
                               })
                        ]),
                        m("td", {style: {textDecoration: task.done() ? "line-through" : "none"}}, task.description()),
                    ])
                })
            ])
        ]);
    };
    m.mount($contents, {controller: todo.controller, view: todo.view});
</script>
</body>
</html>

  • mithrilの置き場
    $GOPATH/static/mithril.js

実行

rerun app/main

感想

かなりすっきりした。


『 Go 』Article List
Category List

Eye Catch Image
Read More

Androidに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

AWSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Bitcoinに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

CentOSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

dockerに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

GitHubに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Goに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Javaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

JavaScriptに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Laravelに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Pythonに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Rubyに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Scalaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Swiftに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Unityに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Vue.jsに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Wordpressに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

機械学習に関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。