1. kamykn

    Posted

    kamykn
Changes in title
+RevelでInterceptorsを使って共通処理を書く
Changes in tags
Changes in body
Source | HTML | Preview

まえがき

私はGolangで開発しているときにはRevelを利用しているのですが、コントローラの機能を利用した共通処理をどこに書くのか迷ったので、個人的に至った結論をまとめていきたいと思います。

Overview

RevelではInterceptorsを使ってコントローラの前処理、後処理を記述することが出来ます。
Golangはconstructが無いため、今回のようにコントローラのアクションの前処理を実行するにはこのような仕組みを利用します。

今回はコントローラ拡張によって親相当のコントローラを作成し、そこにInterceptorsをセットしていきます。

前知識

Revelのコントローラ拡張

コントローラの拡張で親相当のコントローラが作成できます。
https://revel.github.io/quickstart/controllers.html#extending-the-controller

※ 子コントローラでは、親コントローラの参照はポインタではないことに注意

type (
    BaseController struct {
        *revel.Controller
    }
)
type (
    MyController struct {
        BaseController
    }
)

RevelのInterceptors

今回はMethod Interceptorを使います。
レシーバーに今回は親コントローラを設定するつもりです。
下記はドキュメントサイトにあるサンプル( https://revel.github.io/manual/interceptors.html#method-interceptor )。

func (c Hotels) checkUser() revel.Result {
    if user := connected(c); user == nil {
        c.Flash.Error("Please log in first")
        return c.Redirect(App.Index)
    }
    return nil
}

func init() {
    revel.InterceptMethod(Hotels.checkUser, revel.BEFORE)
}

本題:共通処理を書く

今回はMyappというアプリケーションを作成し、ログインしているアカウントデータをすべてのコントローラで扱えるようなものを作ってみましょう。

親コントローラ作成

myapp/app/controllers/core/baseController.go
package core

import (
    "github.com/revel/revel"
    "myapp/app/models"
)

type BaseController struct {
    *revel.Controller
    Account struct {
        models.Account // モデルに定義してあるAccountのデータの型
        IsLogin bool
    }
}

func (b *BaseController) setAccountData() bool {
    // gormのモデルを利用している
    accountModel := models.NewAccountModel()

    // アカウント取得
    // Revelのセッションを使ってAccountIDを取得。説明は割愛
    accountID :=  b.GetAccountID()
    b.Account.Account = accountModel.GetByID(accountID) 

    // ログインフラグを追加
    b.Account.IsLogin = true

    // Account型にモデルで定義しているメソッド
    if b.Account.IsEmpty() {
        b.Account.IsLogin = false
    }

    return nil
}

子となるコントローラで親となるコントローラを継承します。

myapp/app/controllers/app.go
package controllers

import (
    "github.com/revel/revel"
    "myapp/app/controllers/core"
)

type App struct {
    core.BaseController
}

func (a App) Index() revel.Result {
    account := a.Account

    // Viewでアカウント情報を使いたい
    return a.Render(account)
}

Interceptorsを設定

下記をベースコントローラに追記します。

myapp/app/controllers/core/baseController.go
func init () {
    revel.InterceptMethod((*BaseController).setAccountData, revel.BEFORE)
}

あとはコントローラを増やすたびに親コントローラーを継承するだけ

これで、共通処理化の準備ができました。後はログインチェックが必要なコントローラでベースコントローラを継承していくだけで共通処理として利用できるようになっていきます。