【Go言語】WebフレームワークBeegoのviewフォルダ配下のページへ移動する方法

# サンプル
#### 真ん中のタスク登録ボタンをクリックすると...
![BeegTodo遷移元.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/a577d2a9-62f8-0ba8-3419-5a774c786d21.png)

#### こちらのTodo登録画面へ遷移する、機能を作っていきたいと思います。
![BeegTodo遷移先.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/b17ccd87-b846-9304-d14d-ef9ee11f2ab5.png)

# ディレクトリ構成

`viewsフォルダ`の配下に新しく`mytoフォルダ`を作ります。
この中のファイルを`Controllerクラス`を使って呼び出す機能を作っていきます。

```
MY-FIRST-BEEGO-PROJECT
├─ conf
│  └─ app.conf
├─ controllers
│  └─ default.go
├─ crypt
│  └─ crypt.go
├─ models
│  └─ todo.go
├─ routers
│  └─ router.go
└─ static
   ├─ css
   ├─ img
   ├─ js
   │  ├─ form.js
   │  ├─ login.js
   │  ├─ reload.min.js
   │  ├─ todoCreate.js
   │  ├─ todoCard.js
   │  └─ todoList.js
   ├─ lib
   │  └─ bootstrap
   │     ├─ css
   │     │  ├─ bootstrap-grid.min.css
   │     │  └─ bootstrap.min.css
   │     ├─ js
   │     │  ├─ bootstrap-bundle.min.js
   │     │  └─ bootstrap.min.js
   │     ├─ jquery
   │     │  └─ jquery.js
   │     └─ upload
   ├─ views
   │  ├─ mytodo
   │  │  ├─ addTodo.tpl
   │  │  └─ myList.tpl
   │  ├─ index.tpl
   │  ├─ subIndex.tpl
   │  └─ thirdIndex.tpl
   └─ main.go

```

# ルーティングの方法

`Controllerクラス`に構造体を定義して、関数に`viewsフォルダ`配下のパスを記述するように記載します。

```controllers/default.go
// タスクの登録画面
type TodoCreateController struct {
	beego.Controller
}

func (c *TodoCreateController) Get() {
	c.TplName = "mytodo/addTodo.tpl" 
}
```
コントローラクラスで記述したパス情報を、`router.go`クラスにも記載します。
```routers/router.go
func init() {
	//前略
	beego.Router("/mytodo/addTodo", &controllers.TodoCreateController{})
    //後略
}
```
これだけで、`viewフォルダ`配下のフォルダのファイルにもルーティングできました。

さいごに、この記事のコードを記載しておきます。

# フロント側のコード

```views/subIndex.tpl
<!DOCTYPE>
<html>
    <head>
        <title>Todoリスト</title>
        <!--共通-->
        <link rel="stylesheet" type="text/css" href="/static/lib/bootstrap/css/bootstrap.min.css"/>
        <script type="text/javascript" src="/static/lib/jquery/jquery.js"></script>
        <!--個別-->
        <script type="text/javascript" src="/static/js/todoList.js"></script>        
    </head>
    <body>
        <nav class="navbar navbar-expand-lg bg-body-tertiary">
          <div class="container-fluid">
            <button id="backToTopPage" class="btn btn-primary">
                トップページへ
            </button>
            <div class="collapse navbar-collapse">
                <ul class="navbar-nav me-auto mb-2 mb-lg-0">
                    <li class="nav-item">
                        
                        <button id="myTaskCreate" class="btn btn-primary">
                            タスク登録
                        </button>                        
                    </li>
                    <li class="nav-item">
                        <button id="logout" class="btn btn-secondary">
                            ログアウト
                        </button>                        
                    </li>
                </ul>
            </div>
          </div>  
        </nav>

        <h1>{{.Page}}</h1>
    </body>
</html>
```

```static/js/todoList.js
$(document).ready(function(){
    //トップページに戻るボタンをクリックしたときの処理
    $('#backToTopPage').on('click',function(){

    });

    //タスク登録ボタンをクリックし時の処理
    $('#myTaskCreate').on('click',function(){
        location.replace('/mytodo/addTodo'); //location.replace('myTodo/addTodo');
    });

    //ログアウトボタンをクリックしたときの処理
    $('#logout').on('click',function(){
        sessionStorage.removeItem('user');
        location.replace('/');
    });

});
```

# サーバ側のコード

```controllers/default.go
package controllers

import (
	"fmt"
	"time"

	"my-first-beego-project/models"
	_ "my-first-beego-project/models"

	"github.com/astaxie/beego"
	"github.com/beego/beego/v2/client/orm"

	"my-first-beego-project/crypto"

	"os"
	"path/filepath"
)

type MainController struct {
	beego.Controller
}

func (c *MainController) Get() {
	c.Data["Website"] = "beego.me"
	c.Data["Email"] = "astaxie@gmail.com"
	c.TplName = "index.tpl"
}

// 20250205追加
type SubController struct {
	beego.Controller
}

type ThirdController struct {
	beego.Controller
}

type UserController struct {
	beego.Controller
}

// ログイン画面
type LoginController struct {
	beego.Controller
}

// タスクの登録画面
type TodoCreateController struct {
	beego.Controller
}

// タスク登録
type TodoAddController struct {
	beego.Controller
}

// 20250205
func (c *SubController) Get() {
	c.Data["Page"] = "SubPage"
	c.TplName = "subIndex.tpl"
}

// @router :id[get]
func (this *ThirdController) Get() {
	this.Data["ID"] = this.Ctx.Input.Param(":id")
	this.TplName = "thirdIndex.tpl"
}

// ログイン画面コントローラ
func (c *LoginController) Get() {
	c.TplName = "login.tpl"
}

func (c *UserController) Post() {
	//フォームデータを取得する
	name := c.GetString("name")
	email := c.GetString("email")
	password := c.GetString("password")

	//デバッグ用
	//fmt.Println("フォーム画面から取得したNameは：", name)
	//fmt.Println("フォーム画面から取得したEmailは：", email)
	//fmt.Println("フォーム画面から取得したPasswordは：", password)

	c.Data["json"] = map[string]interface{}{
		"status":  "成功",
		"message": "フォーム画面からデータを受け取りました。",
		"requestData": map[string]string{
			"Name":     name,
			"Email":    email,
			"Password": password,
		},
	}
	/*
		c.Data["json"] = map[string]string{
			"status":"成功",
			"message":"フォーム画面からデータを受け取りました。",
		}
	*/
	//パスワードのハッシュ化
	generatedHashedPassword, error := crypto.GeneratedPasswordHashed(password)

	if error != nil {
		fmt.Println("パスワードを暗号化中にエラーが発生しました。", error)
		c.Data["json"] = map[string]string{
			"status":  "失敗",
			"message": "パスワードのハッシュ化に失敗しました。",
		}
		c.ServeJSON()
		return
	}
	//ORMを取得する
	o := orm.NewOrm()
	//モデルTodoのインスタンスを生成
	var registerUser models.Register //var todo models.Todo
	//トランザクション開始
	tx, err := o.Begin()

	if err != nil {
		fmt.Println("トランザクション開始エラー", err)
		c.Data["json"] = map[string]string{
			"status":  "失敗",
			"message": "トランザクションの開始に失敗しました。",
		}
	}

	registerUser.Name = name
	registerUser.Email = email
	registerUser.Password = generatedHashedPassword
	registerUser.CreatedAt = time.Now()

	_, err = tx.Insert(&registerUser)
	if err != nil {
		tx.Rollback()
		fmt.Println("エラー発生", err)
		c.Data["json"] = map[string]string{
			"status":  "失敗",
			"message": "ユーザ登録に失敗しました。",
		}
		c.ServeJSON()
		return
	}
	//成功した場合コミット
	err = tx.Commit()

	if err != nil {
		fmt.Println("トランザクションのコミットに失敗しました。", err)
		c.Data["json"] = map[string]string{
			"status":  "失敗",
			"message": "トランザクションのコミットに失敗しました。",
		}
		c.ServeJSON()
		return
	}

	//登録したデータを取得する
	var registeredUser models.Register
	err = o.QueryTable("register").Filter("Email", email).One(&registeredUser)

	if err != nil {
		fmt.Println("ユーザ情報の取得に失敗しました。", err)
		c.Data["json"] = map[string]string{
			"status":  "失敗",
			"message": "ユーザー情報の取得に失敗しました。",
		}
		c.ServeJSON()
		return
	}

	fmt.Println("登録されたユーザは、", registeredUser.Name)
	fmt.Println("登録されたEmailは、", registeredUser.Email)

	//成功時のレスポンス
	c.Data["json"] = map[string]interface{}{
		"status":  "成功",
		"message": "ユーザーが正常に登録されました",
		"requestData": map[string]string{
			"Name":  registeredUser.Name,
			"Email": registeredUser.Email,
		},
	}

	//JSONデータを返却する
	c.ServeJSON()
}

func (c *LoginController) Post() {

	//フォームデータを取得する
	email := c.GetString("email")
	password := c.GetString("password")

	fmt.Println("ログイン画面から渡されたメールアドレスは、", email)
	fmt.Println("ログイン画面から渡されたパスワードは、", password)

	//ORMを定義する
	o := orm.NewOrm()

	//登録済みのデータを取得する
	var targetUser models.Register
	// `err` を宣言
	err := o.QueryTable("register").Filter("Email", email).One(&targetUser)

	if err != nil {
		fmt.Println("ユーザ情報を取得できませんでした。", err)
		c.Data["json"] = map[string]string{
			"status":  "失敗",
			"message": "ユーザ情報をしゅとくできませんでした。",
		}
		c.ServeJSON()
		return
	}
	fmt.Println("ここまで1", err)
	err = crypto.ComparedHashedPassword(targetUser.Password, password)
	fmt.Println("ここまで2", err)
	if err != nil {
		fmt.Println("パスワードが一致しませんでした。", err)
		c.Data["json"] = map[string]string{
			"status":  "失敗",
			"message": "パスワードが一致しませんでした。",
		}
		c.ServeJSON()
		return
	}
	fmt.Println("ここまで3")
	c.Data["json"] = map[string]string{
		"status":  "成功",
		"message": "ログインに成功しました。",
	}
	c.ServeJSON()
}

func (c *TodoCreateController) Get() {
	//fmt.Println("TodoCreateControllerに来た")
	c.TplName = "mytodo/addTodo.tpl" //c.TplName = "mytodo/addTodo.tpl"
	//fmt.Println("TodoCreateControllerに来たよ")
}

// タスク登録用コントローラ
func (c *TodoAddController) Post() {
	//フォームデータから入力情報を取得する
	task := c.GetString("myTask")
	taskDescription := c.GetString("myTaskDescription")
	taskPriority := c.GetString("myTaskPriority")

	fmt.Println("フォーム画面から取得したタスク名は、", task)
	fmt.Println("フォーム画面から取得したタスク説明は、", taskDescription)
	fmt.Println("フォーム画面から取得したタスク画像は、は、", taskPriority)

	//ファイルをアップロード
	f, h, err := c.GetFile("myTaskImage")
	if err != nil {
		fmt.Println("ファイルエラー", err)
		c.Ctx.ResponseWriter.WriteHeader(500)
		c.Ctx.WriteString("画像アップロード失敗")
		return
	}

	defer f.Close()
	// 画像を保存するパスを指定
	uploadPath := "static/upload/"
	err = os.MkdirAll(uploadPath, os.ModePerm) // ディレクトリがない場合に作成

	if err != nil {
		fmt.Println("ファイル保存エラー", err)
		c.Ctx.ResponseWriter.WriteHeader(500)
		c.Ctx.WriteString("画像保存失敗")
		return
	}

	// ファイル名を表示
	//fmt.Println("ファイル名は", fileName)

	// 画像ファイル名を取得して保存
	fileName := h.Filename
	savePath := filepath.Join(uploadPath, fileName)

	// ファイルを保存
	outFile, err := os.Create(savePath)
	if err != nil {
		fmt.Println("ファイル保存エラー", err)
		c.Ctx.ResponseWriter.WriteHeader(500)
		c.Ctx.WriteString("画像保存に失敗しました")
		return
	}

	defer outFile.Close()

	// アップロードされたファイルの内容を保存
	_, err = f.Seek(0, 0) // ファイルの最初に戻す
	if err != nil {
		fmt.Println("ファイル読み込みエラー", err)
		c.Ctx.ResponseWriter.WriteHeader(500)
		c.Ctx.WriteString("ファイル読み込みに失敗しました")
		return
	}

	_, err = outFile.ReadFrom(f)
	if err != nil {
		fmt.Println("ファイル書き込みエラー", err)
		c.Ctx.ResponseWriter.WriteHeader(500)
		c.Ctx.WriteString("ファイル書き込みに失敗しました")
		return
	}

	// ファイル名を表示
	fmt.Println("ファイル名は", fileName)

	// 成功レスポンスを返す
	c.Ctx.ResponseWriter.WriteHeader(200)
	c.Ctx.WriteString("タスク登録が成功しました")
	//c.SaveFile("uploadname", "static/upload/"+h.Filename)
}

```

```routers/router.go
package routers

import (
	"my-first-beego-project/controllers"

	"github.com/astaxie/beego"
)

func init() {
	beego.Router("/", &controllers.MainController{})
	//追加
	beego.Router("/sub", &controllers.SubController{})
	beego.Router("/:id", &controllers.ThirdController{})
	beego.Router("/controllers/user", &controllers.UserController{})
	beego.Router("/login", &controllers.LoginController{})
	beego.Router("/controllers/login", &controllers.LoginController{})
	beego.Router("/mytodo/addTodo", &controllers.TodoCreateController{})
	beego.Router("/controllers/todoAdd", &controllers.TodoAddController{})
}


```

以上です。