cakephp3でfinderでログイン条件を追加
cakephp3になってからというか少しずつ変化しているものがあります
認証処理とかも…
環境
CensOS7.x
php 7.0.3
cakephp3.2.3
認証処理で条件を付ける際にfinderを使う
以前は"scope"がありましたがそれとは別に"finder"というものがあります。
Usersテーブルとは別にテーブルのチェックなどが必要な場合はこちらがあると便利な感じ
実装
AppController
src/Controller/AppController.php
<?php namespace App\Controller; use Cake\Controller\Controller; use Cake\Event\Event; class AppController extends Controller { public function initialize() { parent::initialize(); $this->loadComponent('RequestHandler'); $this->loadComponent('Flash'); // 認証コンポーネント $this->loadComponent('Auth', [ // ログイン後のリダイレクト 'loginRedirect' => [ 'controller' => 'Posts', 'action' => 'index' ], // ログアウト後のリダイレクト 'logoutRedirect' => [ 'controller' => 'Users', 'action' => 'login', ], // 認証 'authenticate' => [ // フォーム認証 'Form' => [ // 暗号化 'passwordHasher' => [ 'className' => 'Default', ], // 認証フィールド 'fields' => [ 'username' => 'username', 'password' => 'password' ], // モデル 'userModel' => 'Users', // 抽出メソッド 'finder' => 'login' ] ], // データ保存 'storage' => 'Session', // 権限 // isAuthorizedメソッドを実装する必要がある 'authorize' => ['Controller'], ]); } /** * アクション前処理 * @param Event $event */ public function beforeFilter(Event $event) { parent::beforeFilter($event); } /** * Before render callback. * * @param \Cake\Event\Event $event The beforeRender event. * @return void */ public function beforeRender(Event $event) { if (!array_key_exists('_serialize', $this->viewVars) && in_array($this->response->type(), ['application/json', 'application/xml']) ) { $this->set('_serialize', true); } } /** * 認証権限判定処理 * * @param $user * @return bool */ public function isAuthorized($user) { // ユーザーの権限が"admin"の場合は全てを許可する if (isset($user['role']) && $user['role'] === 'admin') { return true; } // Default deny return false; } }
※finderという項目に"login"を指定します。省略時は"all"
UsersTable.php
src/Model/Table/UsersTable.php
<?php namespace App\Model\Table; use App\Model\Entity\User; use Cake\ORM\Query; use Cake\ORM\RulesChecker; use Cake\ORM\Table; use Cake\Validation\Validator; /** * Users Model * */ class UsersTable extends Table { /** * Initialize method * * @param array $config The configuration for the Table. * @return void */ public function initialize(array $config) { parent::initialize($config); $this->table('users'); $this->displayField('id'); $this->primaryKey('id'); $this->addBehavior('Timestamp'); } /** * ログイン用メソッド * * 独自のfindメソッド * @param Query $query * @param array $options * @return Query */ public function findLogin(Query $query, array $options){ // 条件を付与 $query->where([ 'Users.status' => 0, 'Users.deleted' => 0 ]); return $query; } }
SQLのログ
SELECT Users.id AS `Users__id`, Users.username AS `Users__username`, Users.password AS `Users__password`, Users.role AS `Users__role`, Users.status AS `Users__status`, Users.deleted AS `Users__deleted`, Users.created AS `Users__created`, Users.modified AS `Users__modified` FROM users Users WHERE ( Users.username = 'test01' AND Users.status = 0 AND Users.deleted = 0 ) LIMIT 1
所感
HTMLのヘルパーって使いたくない…
生成されるまでどんな形かわからないんですよ…
多少手間がかかってもHTMLで書くべきかと思います…
なんでHTMLヘルパーってあるんだろう…
cakephp3でカスタムバリデーションプロバイダを作成
バリデーションのルールはチェックはいろいろありますが
多少細かいチェックなどがあった場合は対応できません。
各テーブルだけの機能ならともかくいろいろなテーブルクラスで使用する場合はバリデーションを使いまわしたい
対応
ディレクトリを作成
mkdir -p src/Model/Validation
バリデーションインターフェースを実装
src/Model/Validation/CustomValidationInterface.php
<?php namespace App\Model\Validation; interface CustomValidationInterface { // チェックメソッドを定義する public static function sampleCheck1($string); // チェックメソッドを定義する public static function sampleCheck2($string, $len); }
チェック処理を実装
src/Model/Validation/CustomValidation.php
<?php namespace App\Model\Validation; use Cake\Validation; class CustomValidation implements CustomValidationInterface { // チェックメソッドを実装する public static function sampleCheck1($check) { $result = null; if ($check == "check1") { $result = true; } else { $result = false; } return $result; } // チェックメソッドを実装する public static function sampleCheck2($check, $len) { $result = null; if ($check == "1234567890" && strlen($check) == $len) { $result = true; } else { $result = false; } return $result; } }
※サンプルって手抜きの方がわかりやすいと思います
テーブルのバリデーションに実装
<?php namespace App\Model\Table; use App\Model\Entity\Post; use Cake\ORM\Query; use Cake\ORM\RulesChecker; use Cake\ORM\Table; use Cake\Validation\Validator; use App\Model\Validation; /** * Posts Model * */ class PostsTable extends Table { /** * Initialize method * * @param array $config The configuration for the Table. * @return void */ public function initialize(array $config) { parent::initialize($config); $this->table('posts'); $this->displayField('title'); $this->primaryKey('id'); $this->addBehavior('Timestamp'); } /** * Default validation rules. * * @param \Cake\Validation\Validator $validator Validator instance. * @return \Cake\Validation\Validator */ public function validationDefault(Validator $validator) { // プロバイダを追加 $validator->provider('custom', Validation\CustomValidation::class); $validator ->integer('id') ->allowEmpty('id', 'create'); $validator ->requirePresence('title', 'create') ->notEmpty('title') ->add("title", [ "check1" => [ "rule" => ["sampleCheck2", 10], "message" => "カスタムプロバイダーエラー1", "provider" => "custom", // 使用するプロバイダ名を設定 ] ]); $validator ->requirePresence('body', 'create') ->notEmpty('body'); return $validator; } }
こんな感じ
参考
localized/src/Validation at master · cakephp/localized · GitHub
バリデーション — CakePHP Cookbook 3.x ドキュメント
所感
cakephp2の場合はビヘイビアに組み込むという方法で共通化していたので別の場所に配置できるようになるとメンテナンスもやりやすくなるかも…
データだけのチェックの場合とデータベースが絡む場合で難易度が変わるかもしれないので注意する必要があるかもしれないけど…
golangでajaxを使用してrssのデータを取得する
構成
. ├── main.go ├── static │ ├── css │ │ ├── bootstrap-theme.css │ │ ├── bootstrap-theme.css.map │ │ ├── bootstrap-theme.min.css │ │ ├── bootstrap-theme.min.css.map │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ ├── bootstrap.min.css │ │ └── bootstrap.min.css.map │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ ├── glyphicons-halflings-regular.woff │ │ └── glyphicons-halflings-regular.woff2 │ └── js │ ├── app.js │ ├── bootstrap.js │ ├── bootstrap.min.js │ ├── jquery-2.2.0.min.js │ ├── jquery-2.2.0.min.map │ └── npm.js └── templates └── index.html
実装
main.go
package main // インポート import ( "log" "net/http" "html/template" "github.com/gorilla/mux" "io/ioutil" "encoding/xml" "encoding/json" "fmt" ) // RSS一覧用 type RssListItem struct { Title string Url string } // RSS2用の構造体 type Rss2 struct { XMLName xml.Name `xml:"rss"` Version string `xml:"version,attr"` // Required Title string `xml:"channel>title"` Link string `xml:"channel>link"` Description string `xml:"channel>description"` // Optional PubDate string `xml:"channel>pubDate"` ItemList []Item `xml:"channel>item"` } // RSS2の各記事の部分(Item) type Item struct { // Required Title string `xml:"title"` Link string `xml:"link"` Description template.HTML `xml:"description"` // Optional Content template.HTML `xml:"encoded"` PubDate string `xml:"pubDate"` Comments string `xml:"comments"` } // RSSのjson用 type RssJsonList struct { Title string `json:"title"` List []RssJsonItem `json:"list"` } type RssJsonItem struct { Title string `json:"title"` Link string `json:"link"` Date string `json:"date"` } // 主処理 func main(){ // ルーティング初期化 r := mux.NewRouter() // 静的ファイルをサポート r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("static")))) // url別処理 r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request){ // テンプレート生成 tmpl := template.Must(template.New("index").ParseFiles("templates/index.html")) // 変数を設定 tmpl.Execute(w, struct{ RssList []RssListItem }{ RssList: []RssListItem{ { Title: "m_shige1979のささやかな抵抗と欲望の日々", Url: "http://m-shige1979.hatenablog.com/rss", }, { Title: "ぎひょーさん", Url: "http://gihyo.jp/feed/rss2", }, { Title: "@IT", Url: "http://rss.rssad.jp/rss/itmatmarkit/rss.xml", }, }, }) // log log.Print(r.URL.Path) }) r.HandleFunc("/getRss", func(w http.ResponseWriter, r *http.Request){ r.ParseForm() _url := r.FormValue("url") // httpよりRSS取得 res, err := http.Get(_url) if err != nil { panic(err) } // text形式で読み込む asText, err2 := ioutil.ReadAll(res.Body) if err2 != nil { panic(err2) } // rss2構造体を定義 rssData := Rss2{} // パースして格納 err3 := xml.Unmarshal(asText, &rssData) if err3 != nil { panic(err3) } // json用に新規に用意 var jsonData = RssJsonList{} jsonData.Title = rssData.Title jsonData.List = []RssJsonItem{} // 記事の部分を取得 for _, value := range rssData.ItemList { jsonData.List = append(jsonData.List, RssJsonItem{Title: value.Title, Link: value.Link, Date: value.PubDate}) } // jsonエンコード outputJson, err := json.Marshal(&jsonData) if err != nil { panic(err) } // jsonヘッダーを出力 w.Header().Set("Content-Type", "application/json") // jsonデータを出力 fmt.Fprint(w, string(outputJson)) // log log.Print(r.URL.Path) }) // ルーティング設定 http.Handle("/", r) // ポート待ち log.Println(":9001") http.ListenAndServe(":9001", nil) }
templates/index.html
{{ define "index" }} <!DOCType html> <html> <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>websample3</title> <link rel="stylesheet" href="/static/css/bootstrap.min.css" /> </head> <body> <div class="container-fluid"> <div class="row"> <div class="col-xs-12"> <h3>RSSリスト</h3> <ul> {{ range .RssList }} <li> <a href="javascript:void(0);" class="rss_click" data-url="{{ .Url }}"> {{ .Title }} </a> </li> {{ end }} </ul> </div> </div> <hr /> <div class="row"> <div class="col-xs-12"> <div class="rss_entry"> </div> <div class="rss_item_tag" style="display: none;"> <blockquote> <p class="date">aaaa</p> <p class="title">bbbb</p> <footer> <a href="cccc" target="_blank">xxxxx</a> </footer> </blockquote> </div> </div> </div> </div> <script src="/static/js/jquery-2.2.0.min.js"></script> <script src="/static/js/bootstrap.min.js"></script> <script src="/static/js/app.js"></script> </body> </html> {{ end }}
static/js/app.js
$(function(){ $(".rss_click").on("click", function(){ var _url = $(this).attr("data-url"); console.log(_url); // ajaxでrssを取得 $.ajax({ type: 'POST', url: '/getRss', data: { url: _url }, dataType: 'json', success: function(data, status){ console.log("success"); console.log(data); // クリア $(".rss_entry").empty(); for(var _key in data.list){ var _itemElement = $(".rss_item_tag").clone(true); _itemElement.removeClass("rss_item_tag"); _itemElement.css("display", "block"); // rss情報設定 _itemElement.find(".date").text(data.list[_key]["date"]); _itemElement.find(".title").text(data.list[_key]["title"]); _itemElement.find("footer > a").attr("href", data.list[_key]["link"]); _itemElement.find("footer > a").text(data.list[_key]["link"]); // 追加 $(".rss_entry").append(_itemElement); } }, error: function(err1, err2, err3){ console.log("error"); }, }); }); });
ソースのインデントが…まあいいか
結果
うん、まあこんなもんでいいかと
今回はこれで終わり
golangでjsonのデータを出力する
一気に気温が上がったり、下がったり大変
安定せんかな〜
実装1(シンプルな構造体)
main1.go
package main import ( "fmt" "net/http" "log" "github.com/gorilla/mux" "encoding/json" ) // 単純な構造体 type Data1 struct { Title string `json:"title"` Message string `json:"message"` Status int `json:"status"` } func main(){ // ルーティング router := mux.NewRouter() // URL別設定 router.HandleFunc("/sample1", func(w http.ResponseWriter, r *http.Request){ // 構造体を定義 var data1 = Data1{} data1.Title = "sample1" data1.Message = "hello, sample1" data1.Status = 100 // jsonエンコード outputJson, err := json.Marshal(&data1) if err != nil { panic(err) } // jsonヘッダーを出力 w.Header().Set("Content-Type", "application/json") // jsonデータを出力 fmt.Fprint(w, string(outputJson)) // log log.Print(r.URL.Path) }) // ハンドル割当 http.Handle("/", router) // log log.Print("localhost:9001") // ポート http.ListenAndServe(":9001", nil) }
↓
実装2(構造体に配列を含む)
main2.go
package main import ( "fmt" "net/http" "log" "github.com/gorilla/mux" "encoding/json" ) // 配列を含む構造体 type Data2 struct { Title string `json:"title"` Message string `json:"message"` Status int `json:"status"` List map[string]Item `json:"list"` } // 構造体の配列Item type Item struct { Name string `json:"name"` Age int `json:"age"` } func main(){ // ルーティング router := mux.NewRouter() // URL別設定 router.HandleFunc("/sample2", func(w http.ResponseWriter, r *http.Request){ // 構造体を定義 var data2 = Data2{} data2.Title = "sample2" data2.Message = "hello, sample2" data2.Status = 200 data2.List = map[string]Item{} data2.List["test1"] = Item{Name:"taro", Age: 10} data2.List["test2"] = Item{Name:"hanako", Age: 18} data2.List["test3"] = Item{Name:"pochi", Age: 50} // jsonエンコード outputJson, err := json.Marshal(&data2) if err != nil { panic(err) } // jsonヘッダーを出力 w.Header().Set("Content-Type", "application/json") // jsonデータを出力 fmt.Fprint(w, string(outputJson)) // log log.Print(r.URL.Path) }) // ハンドル割当 http.Handle("/", router) // log log.Print("localhost:9001") // ポート http.ListenAndServe(":9001", nil) }
↓
なんとかできました。
RSSの場合にもあったけど
type Data2 struct { Title string `json:"title"` Message string `json:"message"` Status int `json:"status"` List map[string]Item `json:"list"` }
右の方にjsonとか指定したらその名前になるので小文字にしたい場合などは役に立ちます…というかきまりみたいな感じかな…
テキトーにググったけどそれっぽいパッケージが見つからなかったのでこれでいいはず
golangでRSS2のデータを取得して表示
参考
[Golang] XML Parsing Example (7) - Parse RSS 2.0
※Atomや両方対応のパターンもあります
静的ファイルも参照したい
jsとかcssとか使用したいけどどうやって参照するか
web applications - Serving static content with a root URL with the Gorilla toolkit - Stack Overflow
実装
構成
. ├── main.go ├── static │ ├── css │ │ ├── bootstrap-theme.css │ │ ├── bootstrap-theme.css.map │ │ ├── bootstrap-theme.min.css │ │ ├── bootstrap-theme.min.css.map │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ ├── bootstrap.min.css │ │ └── bootstrap.min.css.map │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ ├── glyphicons-halflings-regular.woff │ │ └── glyphicons-halflings-regular.woff2 │ └── js │ ├── bootstrap.js │ ├── bootstrap.min.js │ ├── jquery-2.2.0.min.js │ ├── jquery-2.2.0.min.map │ └── npm.js └── templates └── index.html
main.go
package main // インポート import ( "log" "net/http" "html/template" "github.com/gorilla/mux" "io/ioutil" "encoding/xml" ) // RSS2用の構造体 type Rss2 struct { XMLName xml.Name `xml:"rss"` Version string `xml:"version,attr"` // Required Title string `xml:"channel>title"` Link string `xml:"channel>link"` Description string `xml:"channel>description"` // Optional PubDate string `xml:"channel>pubDate"` ItemList []Item `xml:"channel>item"` } // RSS2の各記事の部分(Item) type Item struct { // Required Title string `xml:"title"` Link string `xml:"link"` Description template.HTML `xml:"description"` // Optional Content template.HTML `xml:"encoded"` PubDate string `xml:"pubDate"` Comments string `xml:"comments"` } // 主処理 func main(){ // ルーティング初期化 r := mux.NewRouter() // 静的ファイルをサポート r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("static")))) // url別処理 r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request){ // httpよりRSS取得 _rssURL := "http://m-shige1979.hatenablog.com/rss" res, err := http.Get(_rssURL) if err != nil { panic(err) } // text形式で読み込む asText, err2 := ioutil.ReadAll(res.Body) if err2 != nil { panic(err2) } // rss2構造体を定義 rssData := Rss2{} // パースして格納 err3 := xml.Unmarshal(asText, &rssData) if err3 != nil { panic(err3) } // テンプレート生成 tmpl := template.Must(template.New("index").ParseFiles("templates/index.html")) // 変数を設定 tmpl.Execute(w, struct{ RssItemList []Item }{ RssItemList: rssData.ItemList, }) // url log.Println(r.URL.Path) }) // ルーティング設定 http.Handle("/", r) // ポート待ち log.Println(":9001") http.ListenAndServe(":9001", nil) }
templates/index.html
{{ define "index" }} <!DOCType html> <html> <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>websample3</title> <link rel="stylesheet" href="/static/css/bootstrap.min.css" /> </head> <body> <div class="container-fluid"> <div class="row"> <div class="col-xs-12"> <h3>RSSリスト</h3> </div> </div> <div class="row"> <div class="col-xs-12"> {{ range .RssItemList }} <div> <blockquote> <p>{{ .PubDate }}</p> <p>{{ .Title }}</p> <footer> <a href="{{ .Link }}" target="_blank">{{ .Link }}</a> </footer> </blockquote> </div> {{ end }} </div> </div> </div> <script src="/static/js/jquery-2.2.0.min.js"></script> <script src="/static/js/bootstrap.min.js"></script> </body> </html> {{ end }}
結果
golangでgorillaとかいうのを使ってみる(sessions)
セッションを使用してみる
値を入れること自体はそんなに難しく無い感じですけど取り出すときになんかいろいろ手間取る感じ
基本的には構造体などで管理したほうがいい感じです
インストール
go get github.com/gorilla/sessions
実装
main.go
package main import ( "encoding/gob" "github.com/gorilla/mux" "github.com/gorilla/sessions" "net/http" "fmt" "time" "html/template" "crypto/rand" "encoding/base32" "io" "strings" ) // セッション名 var session_name string = "gsid" // Cookie型のstore情報 var store *sessions.CookieStore // セッションオブジェクト var session *sessions.Session // 構造体 type Data1 struct { Count int Msg string } // 主処理 func main(){ // 構造体を登録 gob.Register(&Data1{}) // セッション初期処理 sessionInit() // ルーティング生成 r := mux.NewRouter() // URL別の処理 r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request){ // セッションオブジェクトを取得 session, _ := store.Get(r, session_name) data1, ok := session.Values["data1"].(*Data1) if data1 != nil { data1.Count++ data1.Msg = fmt.Sprintf("%d件カウント", data1.Count) } else { data1 = &Data1{0, "データ無し"} } fmt.Println(ok) fmt.Println(data1) session.Values["data1"] = data1 // 保存 sessions.Save(r, w) // テンプレートを指定 tmpl := template.Must(template.New("index").ParseFiles("templates/index.html")) tmpl.Execute(w, struct { Detail *Data1 }{ Detail: data1, }) // logの代わり fmt.Print(time.Now()) fmt.Println(" url = " + r.URL.Path) }) r.HandleFunc("/clear", func(w http.ResponseWriter, r *http.Request){ // セッション初期化 sessionInit() // logの代わり fmt.Print(time.Now()) fmt.Println(" url = " + r.URL.Path) // redirect http.Redirect(w, r, "/", http.StatusFound) }) // rを割当 http.Handle("/", r) // ポートを割当 fmt.Println("localhost:9001") http.ListenAndServe(":9001", nil) } // セッション用の初期処理 func sessionInit(){ // 乱数生成 b := make([]byte, 48) _, err := io.ReadFull(rand.Reader, b) if err != nil { panic(err) } str := strings.TrimRight(base32.StdEncoding.EncodeToString(b), "=") // 新しいstoreとセッションを準備 store = sessions.NewCookieStore([]byte(str)) session = sessions.NewSession(store, session_name) // セッションの有効範囲を指定 store.Options = &sessions.Options{ Domain: "localhost", Path: "/", MaxAge: 0, Secure: false, HttpOnly: true, } // log fmt.Println("key data --") fmt.Println(str) fmt.Println("") fmt.Println("store data --") fmt.Println(store) fmt.Println("") fmt.Println("session data --") fmt.Println(session) fmt.Println("") }
templates/index.html
{{ define "index" }} <!DOCType html> <html> <head> <meta charset="utf-8" /> <title>websample2</title> </head> <body> count = {{ .Detail.Count }}<br /> msg = {{ .Detail.Msg }}<br /> <br /> <a href="/clear">クリア<a/> </body> </html> {{ end }}
セッションのデータ管理は?
store = sessions.NewCookieStore([]byte(str))
これで"store"とかいう変数にCookie形式の形っぽいデータをどっかに管理するみたい
ちなみにローカルファイル内に配置したい場合は
store = sessions.NewFilesystemStore("", []byte(str))
こうなる
第1引数はセッションファイルの配置場所で空文字の場合は規定の場所を指定centosとかでは"/tmp"みたい…
byteで渡す値でデータを管理しているのでデータを初期化するという意味では一度別の名前にするのが良いかと
Valuesの値を消したりしてもいいかもしれないけど面倒な感じもあるので乱数を生成してから消すのも手かと思われる
所感
なんか遅い…
手動でログを出力しているせいかもしれないけどなんか応答が結構遅い感じがする
ルーティングとセッションをとりあえずだけど対応したのでちょっと他のこともやってみる
うーんやることが増えてきたのでソースがでかくなってきた\(^o^)/
golangでgorillaとかいうのを使ってみる(mux)
ゴリラ?
Gorilla, the golang web toolkit
まあ、http関連のやつでルーティングとかセッションとかを"net/http"よりは柔軟に使える感じのもの
なんか適当に調べたけど"net/http"ではセッションは使えないとかなんとか
ちょっと今回はルーティングの"gorilla/mux"を使用する
インストール
go get github.com/gorilla/mux
実装
今回の構成
. ├── main.go └── templates ├── index.html └── save.html
main.go
package main import ( "net/http" "github.com/gorilla/mux" "fmt" "time" "html/template" ) func main(){ // 生成 r := mux.NewRouter() // "/"の場合の処理 r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { // テンプレート tmpl := template.Must(template.New("index").ParseFiles("templates/index.html")) err := tmpl.Execute(w, nil) if err != nil { panic(err) } // logの代わり fmt.Print(time.Now()) fmt.Printf(" path: " + r.URL.Path + "\n") }).Methods("GET") // "/save"の場合の処理 r.HandleFunc("/save", func(w http.ResponseWriter, r *http.Request) { // formの値を取得 r.ParseForm() data1 := r.FormValue("aaa") data2 := r.FormValue("bbb") // テンプレート tmpl := template.Must(template.New("save").ParseFiles("templates/save.html")) err := tmpl.Execute(w, struct { Data1 string Data2 string }{ Data1: data1, Data2: data2, }) if err != nil { panic(err) } // logの代わり fmt.Print(time.Now()) fmt.Printf(" path: " + r.URL.Path + "\n") }).Methods("POST") // 可変URL1 r.HandleFunc("/test1/{sample1}/", func(w http.ResponseWriter, r *http.Request) { // 画面サンプル fmt.Fprintf(w, "sample1\n") // logの代わり fmt.Print(time.Now()) fmt.Printf(" path: " + r.URL.Path + "\n") }) // 可変URL2 r.HandleFunc("/test2/{sample1}/{id:[0-9]{1,6}}/", func(w http.ResponseWriter, r *http.Request) { // 画面サンプル fmt.Fprintf(w, "sample2\n") // logの代わり fmt.Print(time.Now()) fmt.Printf(" path: " + r.URL.Path + "\n") }) // handing http.Handle("/", r) // 設定 http.ListenAndServe(":9001", nil) }
※POST、GETだけを指定したい場合など、また一部のURLが可変になる場合は楽できます。
templates/index.html
{{ define "index" }} <!DOCType html> <html> <head> <meta charaset="utf-8" /> <title>websample1</title> </head> <body> <h3>なんかいれて送信してみて</h3> <form method="post" action="/save"> <input type="text" name="aaa" value="" /><br /> <input type="text" name="bbb" value="" /><br /> <input type="submit" value="送信" /> </form> </body> </html> {{ end }}
templates/save.html
{{ define "save" }} <!DOCType html> <html> <head> <meta charaset="utf-8" /> <title>websample1</title> </head> <body> <h3>送信されたものは以下</h3> <div> aaa = {{ .Data1 }}<br /> bbb = {{ .Data2 }}<br /> </div> <a href="/">top</a> </body> </html> {{ end }}
画面
↓
↓
所感
このツールキットを使用することでネットワーク関連のコードを書くのに結構便利になる感じかと
web アプリを作成するとしたらルーティングとセッションは必須なのできちんとやっておく必要がありそうです。