golang-web框架revel一個表單提交的總結

神牛003發表於2016-05-18

這裡要介紹好是revel框架的表單post提交的列子,主要是用於入門學習,和一些知識點的講解;

首先:

  來了解一個問題那就是重複提交表單,做過form表單提交的同學都知道,如果表單提交後不做處理,那麼直接在瀏覽器按下F5,會再次提交表單內容到伺服器,這就是重複提交,當然要防止這個有多種方法,這裡簡單描述一種常見的:

  一種是加入token失效驗證,這個token其實就是一個值,驗證的原理是第一次客戶開啟頁面時候獲取到一個分配的值,每次使用者重新整理頁面的時候這個分配的值都需要變動,並且這個值在使用者提交表單時候會進行驗證,驗證頁面傳遞到後端程式儲存的值是否一致,如果提交表單成功後,這個值會失效或者來說被清空。

其次:上程式碼+分析

package controllers

import "github.com/revel/revel"
import "fmt"

//import "io/ioutil"
import "encoding/json"
import "os"
import "io"
import "time"
import "net/http"

type Concate struct {
    Name   string
    Link   string
    Concat string
    Tel    string
    Email  string
}

func WriteFileAppend(filename string, data []byte) error {

    fl, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE, 0644)
    if err != nil {
        return err
    }
    defer fl.Close()
    n, err := fl.Write(data)
    if err == nil && n < len(data) {
        err = io.ErrShortWrite
    }
    return err
}

func (c App) Add() revel.Result {

    method := c.Request.Method
    fmt.Printf(method)
    ck_name := "add_token"
    if method == "POST" {

        name := c.Params.Get("txtName")
        link := c.Params.Get("txtLink")
        concat := c.Params.Get("txtHeader")
        tel := c.Params.Get("txtTel")
        email := c.Params.Get("txtEmail")

        token := c.Params.Get("add_token")

        fmt.Printf("學校加入引數:name=%v;link=%v;concat=%v;tel=%v;email=%v;token=%V", name, link, concat, tel, email, token)

        c.Validation.Required(token).Message("token驗證失敗,請重新開啟頁面")

        c.Validation.Required(name).Message("學校名稱,必須填寫")
        c.Validation.Required(concat).Message("申請人名,必須填寫")
        c.Validation.Required(tel).Message("聯絡電話,必須填寫")
        c.Validation.Required(email).Message("聯絡郵箱,必須填寫")

        if c.Validation.HasErrors() {
            // 在flash上下文中儲存驗證錯誤並重定向
            c.Validation.Keep()
            c.FlashParams()
            return c.Render()
        }

        result := "加入園子-失敗"
        ck_Token, ck_err := c.Request.Cookie(ck_name)
        if ck_err != nil {
            return c.Render(result)
        }

        if ck_Token.Value != token {
            return c.Render(result)
        }

        concate := Concate{Name: name, Link: link, Concat: concat, Tel: tel, Email: email}
        bb, err := json.Marshal(concate)
        if err != nil {
            return c.Render(result)
        }
        bstr := string(bb) + ","
        bbNew := []byte(bstr)
        err = WriteFileAppend(`./WiKiApp/public/js/add.json`, bbNew)
        if err == nil {
            result = " 加入園子-成功,稍後會有郵件或客服人員聯絡您"
        }
        return c.Render(result)
    }

    //建立token,防止重複提交
    token := time.Now().Format("2006-01-02 15:04:05")

    ck := http.Cookie{Name: ck_name, Value: token}
    c.SetCookie(&ck)
    return c.Render(token)
}
View Code

  第一次進來路由指向這個頁面的時候是get請求,此時使用cookie儲存一下生成的token,revel框架是mvc模式,可以通過c.Render(token)把引數輸出到頁面上,在使用模板直接繫結到hidden元素上面

  <input type="hidden" name="add_token" value="{{.token}}"/>這裡把token輸出到了影藏域裡面,

  下面就是填寫表單內容,再執行儲存提交按鈕,post到後臺的地址,這裡的程式碼知識點有

 

  1.c.Request.Method:獲取請求的http方式;

  2.c.Params.Get("txtName"):獲取頁面元素name為txtName名字的引數值;

  3.fmt.Printf("%v","我愛祖國"):這裡的print就是列印資訊在後臺,%v是佔位符,類似於C#{0}效果;

  4.c.Validation.Required(token).Message("token驗證失敗,請重新開啟頁面"):c.Validation.Required是revel框架封裝的驗證方法,Message("xxxx")是不符合驗證格式了,就返回的提示資訊;

  5.c.FlashParams():revel框架的驗證錯誤資訊是一次性的,類似於.net mvc中的tempdata效果,只能被讀取一次;

  6.ck_Token, ck_err := c.Request.Cookie(ck_name):Request.Cookie是獲取對應名稱的cookie資訊,這裡看到的:=是go語言的語法,此語法的作用很大,具體請去了解go基礎;

  7.bbNew := []byte(bstr):這裡[]byte()直接吧字串資訊轉化成了byte[]看起來是不是很方便

  8.WriteFileAppend:是自定義的記錄文字資訊的方法,裡面最重要的是defer fl.Close(),這個defer意思就是等待方法執行完後,在呼叫這個close釋放資源,這裡有點像finally的感覺

 

  再發下html模板程式碼

{{set . "title" "搜-學校-加入圈子"}}
{{template "header.html" .}}

    <form action="/app/add" method="post" style="margin-bottom:20px">
          <div class="form-group">
            <label for="txtName">學校-名稱(<font style="color:#337ab7">必填</font>)</label>
            <input type="text" class="form-control"  maxlength="50" id="txtName" name="txtName" required placeholder="學校名稱">
          </div>
          <div class="form-group">
            <label for="txtLink">學校-網站地址</label>
            <input type="text" class="form-control" maxlength="200" id="txtLink" name="txtLink" placeholder="http://xxx">
          </div>
          <div class="form-group">
            <label for="txtHeader">學校-申請人(<font style="color:#337ab7">必填</font>)</label>
            <input type="text" class="form-control"  maxlength="10" id="txtHeader" name="txtHeader" required placeholder="申請人名字">
          </div>
          <div class="form-group">
            <label for="txtTel">申請-電話(<font style="color:#337ab7">必填</font>)</label>
            <input type="text" class="form-control"  maxlength="20" id="txtTel" name="txtTel" required placeholder="申請人聯絡電話號碼">
          </div>
          <div class="form-group">
            <label for="txtEmail">申請-郵箱(<font style="color:#337ab7">必填</font>)</label>
            <input type="Email" class="form-control"  maxlength="50" id="txtEmail" name="txtEmail" required placeholder="申請人郵箱如:8123@qq.com">
          </div>
          <!--<div class="form-group">
            <label for="exampleInputFile">File input</label>
            <input type="file" id="exampleInputFile">
            <p class="help-block">Example block-level help text here.</p>
          </div>-->
          <!--<div class="checkbox">
            <label>
              <input type="checkbox"> Check me out
            </label>
          </div>-->
          <button type="submit" class="btn btn-success">保 存</button>
          <input type="hidden" name="add_token" value="{{.token}}"/>
          <span>{{.result}}</span>
    </form>
<div class="container">
  <div class="row">
  <div class="span6">
    {{template "flash.html" .}}
  </div>
  </div>
</div>
{{template "footer.html" .}}
View Code

  最後,以上是一些知識點的個人認識和描述,有疑問或者有錯誤地方,歡迎來稿。

    

 

  

  

相關文章