golang web實戰之三(基於iris框架的 web小應用,數據庫採用 sqlite3 )

1、效果:一個圖片應用javascript

一、可上傳圖片到uploads目錄。css

二、可瀏覽和評論圖片(用富文本編輯器輸入)html

2、梳理一下相關知識:java

一、iris框架(模板輸出,session)jquery

二、富文本編輯器、sqlite3(保存評論文字內容)git

 2、參考MVC設計模式,手工建如下目錄結構和文件,- 表示目錄層級  \表示目錄,github

-irisMVCgolang

--main.go                    //go主程序sql

--config.json               //配置文件數據庫

--m\               //model層,處理數據庫

---m.go     

--v\                            //view ,視圖

---index.html          //首頁模板;

---upload.html     //上傳圖片

---comment.html  //評論圖片

--db\                         //保存sqlite3格式數據庫

---pic.db                //這個文件是在代碼中自動生成的   

--uploads\                 //保存上傳圖片

--static\                      //靜態文件,css,js,logo

注:說是MVC,爲簡化代碼,我將controller控制器層、路由都寫在main.go中了

另外,可以使用項目熱重啓,參考http://www.javashuo.com/article/p-ddpeveyh-z.html  

3、從main.go開始寫代碼

一、main.go 

 
/*
//config.json
{
  "appname": "IrisDemo",
  "port": 8000
}
*/
package main

import (
    "encoding/json"
    "fmt"
    "html/template"
    "io"
    "io/ioutil"
    "os"
    "strconv"
    "time"

    "github.com/kataras/iris/sessions"

    "github.com/kataras/iris"

    _ "github.com/mattn/go-sqlite3"

    "irisMVC/m"
)

//配置文件結構
type Coniguration struct {
    Appname   string    `json:appname`
    Port      string    `json:port`
    CreatedAt time.Time `json:"created"`
}

//全局變量conf,包含了配置文件內容
var conf Coniguration

//初始化
func init() {
    //讀配置文件
    file, _ := os.Open("config.json")
    defer file.Close()
    decoder := json.NewDecoder(file)
    err := decoder.Decode(&conf)
    if err != nil {
        fmt.Println("Error:", err)
    }
    fmt.Println(conf.Port)
}

func main() {
    app := iris.New()
    //session
    sess := sessions.New(sessions.Config{Cookie: "sessionscookieid", Expires: 45 * time.Minute})

    //靜態文件目錄,如http://localhost:8000/staticwwwurl/1.txt
    app.StaticWeb("/staticwwwurl", "./mystatic")
    //得到model層數據庫對象,用於操做數據庫,同時,初始化數據庫
    db := m.NewDb()
    // onInterrupt contains a list of the functions that should be called when CTRL+C/CMD+C or a unix kill //command received.
    iris.RegisterOnInterrupt(func() {
        db.ORM.Close()
    })

    tmpl := iris.HTML("./v", ".html")
    //增長模板函數
    tmpl.AddFunc("Itoa", func(i int64) string {
        return strconv.FormatInt(i, 10)
    })
    //解決富文本輸出轉義問題
    tmpl.AddFunc("unescaped", func(x string) interface{} { return template.HTML(x) })

    //註冊視圖目錄
    app.RegisterView(tmpl)
    //路由
    //主頁
    app.Get("/", func(ctx iris.Context) {
        //綁定數據
        ctx.ViewData("Title", conf.Appname)
        pics := db.ListPic()
        ctx.ViewData("Pic", pics)
        // 渲染視圖文件: ./v/index.html
        ctx.View("index.html")

    })
    //評論圖片
    app.Post("/comment", func(ctx iris.Context) {
        id := ctx.PostValue("Pid")
        comment := ctx.PostValue("Comment")
        db.Comment(id, comment)
        ctx.HTML("評論成功")
    }).Name = "comment" //Name用於生成urlpath

    app.Get("/comment/{Id:int}", func(ctx iris.Context) {
        id, _ := ctx.Params().GetInt("Id")
        ctx.ViewData("Pid", id)
        ctx.View("comment.html")
    }).Name = "comment1"
    //上傳圖片
    app.Get("/upload", func(ctx iris.Context) {
        ctx.View("upload.html")
    })
    //限制上傳文件大小10M,硬編碼
    app.Post("/upload", iris.LimitRequestBodySize(10<<20), func(ctx iris.Context) {
        // Get the file from the request.
        file, info, err := ctx.FormFile("uploadfile")
        if err != nil {
            ctx.StatusCode(iris.StatusInternalServerError)
            ctx.HTML("Error while uploading: <b>" + err.Error() + "</b>")
            return
        }
        defer file.Close()
        fname := info.Filename
        //建立一個具備相同名稱的文件
        //假設你有一個名爲'upload'的文件夾
        //出於安全須要,能夠在這裏過濾文件類型,處理文件名後綴
        out, err := os.OpenFile("./upload/"+fname, os.O_WRONLY|os.O_CREATE, 0666)
        if err != nil {
            ctx.StatusCode(iris.StatusInternalServerError)
            ctx.HTML("Error while uploading: <b>" + err.Error() + "</b>")
            return
        }
        defer out.Close()
        io.Copy(out, file) //能夠將,當作=,能夠理解爲:將file的值賦給out
        //而後將fname存入數據庫pic.db的PIC表
        db.SavePic(fname)
        ctx.HTML("上傳成功")
    })
    //下載圖片
    app.Get("/pic/{url}", func(ctx iris.Context) {
        //我將一張圖片更名爲3.html,並複製到upload文件夾中。
        //下面兩行是直接下載圖片
        //file := "./upload/3.html"
        //ctx.SendFile(file, "c.jpg")
        //下面是在網頁上顯示圖片
        ctx.Header("Content-Type", "image/png")
        ctx.Header("Content-Disposition", fmt.Sprint("inline; filename=\"aaa\""))
        file, err := ioutil.ReadFile("./upload/3.html")
        if err != nil {
            ctx.HTML("查無此圖片")
            return
        }
        ctx.Write(file)
    })
    //session的簡單使用
    app.Get("/admin", func(ctx iris.Context) {
        //可在這裏用sess.UseDatabase,可參考:https://blog.csdn.net/wangshubo1989/article/details/78344183
        s := sess.Start(ctx)
        //set session values
        s.Set("login name", "iris session")
        i, err := s.GetInt("num")
        if err != nil {
            i = 0
        }
        i += 1
        s.Set("num", i)
        ctx.HTML(fmt.Sprintf("%s    %d", s.GetString("name"), i))
    })

    app.Run(iris.Addr(":" + conf.Port))
}
 
2.config.json
{
  "appname": "IrisDemo 1.0",
  "port": "8000"
}

3.m.go

package m

import (
    "strconv"
    "time"

    "github.com/go-xorm/xorm"
    _ "github.com/mattn/go-sqlite3"
)

//數據庫對象DB,對xorm進行了包裝 //注意駱峯法
type Db struct {
    ORM *xorm.Engine
}

//數據庫表
//Admin 管理員表
type Admin struct {
    ID        int64 // xorm默認自動遞增
    A管理員名     string
    Password  string    `xorm:"varchar(200)"`
    CreatedAt time.Time `xorm:"created"`
}

//Pic 用戶對圖片評論的表
type Pic struct {
    Id        int64     // xorm默認自動遞增
    Url       string    //圖片保存路徑
    Comment   string    `xorm:"text"` //評論
    CreatedAt time.Time `xorm:"created"`
}

//User 用戶表
type User struct {
    Id        int64 // xorm默認自動遞增
    A用戶名      string
    Password  string    `xorm:"varchar(200)"`
    CreatedAt time.Time `xorm:"created"`
}

//生成數據庫
func NewDb() *Db {
    //初始化數據庫
    orm, _ := xorm.NewEngine("sqlite3", "./db/db.db")
    //此時生成數據庫文件db/picdb.db,以及表USER、PIC
    _ = orm.Sync2(new(User), new(Pic))
    db := new(Db)
    db.ORM = orm
    return db
}
func (d *Db) SavePic(url string) {
    pic := new(Pic)
    pic.Url = url
    d.ORM.Insert(pic)
}
func (d *Db) ListPic() []Pic {
    var p []Pic
    _ = d.ORM.Sql("select * from pic LIMIT 3 OFFSET 0").Find(&p)
    //如下三句沒解決富文本被當成string輸出的問題。最後採起的辦法是:註冊模板函數unescaped
    //for i := range p {
    //    p[i].Comment = template.HTMLEscaper(p[i].Comment)
    //    fmt.Println(p[i].Comment)
    //}
    return p
}
func (d *Db) Comment(id, comment string) {
    var p Pic
    idi, _ := strconv.ParseInt(id, 10, 64)
    _, _ = d.ORM.ID(idi).Get(&p)
    p.Comment += comment
    //id爲int64或string均可以
    d.ORM.ID(id).Update(p)
}
 

4.幾個html模板

 4.1 index.html

<!DOCTYPE html>
<head>
<meta charset="utf-8">
<title>{{.Title}}</title>
</head>
<body> 

{{range  $i, $v := .Pic}}
{{$v.Id}}&nbsp;&nbsp;{{$v.Url}}&nbsp;&nbsp;{{$v.CreatedAt}}&nbsp;&nbsp;{{$v.Comment | unescaped}}&nbsp;&nbsp;<a href={{urlpath "comment" }}/{{Itoa $v.Id}}>點評</a>   <a href={{urlpath "comment1" $v.Url}}>未實現</a> <img src=/pic/{{$v.Url}}><br/>
{{end}}
    
</body>
</html>

 

4.2 upload.html

<!DOCTYPE html>
<head>
<meta charset="utf-8">
<title>{{.Title}}</title>
</head>
<body>
    <form enctype="multipart/form-data" action="upload" method="POST">
        <input type="file" name="uploadfile" />

        <input type="hidden" name="token" value="{{.}}" />

        <input type="submit" value="upload" />
    </form>
</body>
</html>

4.3 comment.html

<!DOCTYPE html>
<head>
<meta charset="utf-8">
<title>{{.Title}}</title>
</head>
<body> 
    <form action="/comment" method="post">
    Id: <input type="text" name="Pid" value={{.Pid}} />
        評論: <input type="text" id="Comment" name="Comment" /> <br />      
        <input type="submit" value="提交"/>
    </form>
        <!-- 注意, 只須要引用 JS,無需引用任何 CSS !!!-->  
     
   <script src="https://cdn.bootcss.com/wangEditor/10.0.13/wangEditor.min.js"></script>
    <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
    <div id="div1">
        <p>這句必須在段落標籤內</p>
    </div>
  
    <script type="text/javascript">
        var E = window.wangEditor
        var editor = new E('#div1')
        var $text1 = $('#Comment')
        editor.customConfig.onchange = function (html) {
            // 監控變化,同步更新到 input
            $text1.val(html)
        }
        editor.create()
        // 初始化 input 的值
        $text1.val(editor.txt.html())
    </script>
</body>
</html>

 

參考:

理解Golang包導入https://studygolang.com/articles/3189

圖片輸出 https://www.jianshu.com/p/583f473fe2c2、 https://blog.csdn.net/ssssny/article/details/77717287

session http://www.javashuo.com/article/p-ffadwmzc-mg.html

富文本的顯示問題 https://yq.aliyun.com/articles/348899      https://studygolang.com/articles/1741

還可經過 https://sourcegraph.com搜索相應的源碼、https://gocn.vip/question/822

修改數組元素的問題 http://www.javashuo.com/article/p-qtvlcrkd-bc.html

數據類型轉換 https://blog.csdn.net/u013485530/article/details/80906569

相關文章
相關標籤/搜索