pu369com

纯go+sqlite3+html/template网站(类似MVC实现数据库CURD、上传下载文件)-最少依赖才是硬道理

一直不喜欢框架,不喜欢引入外部包,所以重新梳理了以下代码,尽量不引入外部依赖。主要实现以下目标(玩具级代码,适合精准需求的小应用):

1、可以操作sqlite3数据库

2、可以用template展示数据(需增加页面时,在v目录下增加模板html文件,在main.go中增加路由及响应函数)

3、可以上传下载文件(参考https://zhuanlan.zhihu.com/p/91606240

思路:

1、路由:参考:https://blog.csdn.net/weixin_33691817/article/details/91920458

2、Model层:将上文中sqlite3 CRUD操作封装为一个模块db/db.go,根据CRUD需要,修改此模块,在main.go中调用(还是觉得过程式思维省脑筋,就写成过程式函数,没有面向对象,Control层也直接写入main.go中)。

3、建一个目录v,存放所有html模板(View层),用template.ParseFiles载入及展示。(脑筋不够,感觉用MVC比MVVM容易些)

 目录结构

-htmlsql3(根目录)

-db(存放sqlite3数据库和db.go的目录)

--db.go

-v(存放html模板的目录,其中有index.html和upload.html)

--static(存放静态文件及上传文件的目录)

-main.go

4 、建一个名为htmlsql3的目录,其中就2两个go文件和2个html文件。

main.go

//在main.go同级目录建两个子目录:db和v,
//db目录下db.go,封装操作db.db的sql语句
//v目录下是html模板,用于呈现网页内容;router和controller直接写在main.go中
package main

import (
    "fmt"
    "html/template"
    "htmlsql3/db"
    "io/ioutil"
    "net/http"
    "regexp"
)

func main() {
    //静态文件服务
    http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))
    http.HandleFunc("/", Route)
    http.ListenAndServe(":8000", nil)

}

// 路由定义
type routeInfo struct {
    pattern string                                       // 正则表达式
    f       func(w http.ResponseWriter, r *http.Request) //Controller函数
}

// 路由添加
var routePath = []routeInfo{
    routeInfo{"^/a$", IndexHandler},       //首页
    routeInfo{"^/upload$", UploadHandler}, //上传页
}

// 使用正则路由转发
func Route(w http.ResponseWriter, r *http.Request) {
    isFound := false
    for _, p := range routePath {
        // 这里循环匹配Path,先添加的先匹配
        reg, err := regexp.Compile(p.pattern)
        if err != nil {
            continue
        }
        if reg.MatchString(r.URL.Path) {
            isFound = true
            p.f(w, r)
        }
    }
    if !isFound {
        // 未匹配到路由
        fmt.Fprint(w, "404 Page Not Found!")
    }
}

func IndexHandler(w http.ResponseWriter, r *http.Request) {
    // 解析指定文件生成模板对象
    tem, err := template.ParseFiles("v/index.html")
    checkErr(err)
    // 从数据库获取数据用于渲染模板
    maxid := db.GetMaxID()
    Data := DbData{
        Maxid: maxid}
    //渲染输出
    tem.Execute(w, Data)
}

func UploadHandler(w http.ResponseWriter, r *http.Request) {
    if r.Method == "POST" { //POST方式进行文件上传至static目录下
        //获取普通表单数据
        username := r.FormValue("username")
        fmt.Println(username)
        //获取文件流,第三个返回值是错误对象
        file, header, _ := r.FormFile("upfile")
        //上传文件大小类型限制可参考https://studygolang.com/articles/22643
        //读取文件流为[]byte
        b, _ := ioutil.ReadAll(file)
        //把文件保存到指定位置
        ioutil.WriteFile("./static/"+header.Filename, b, 0777)
        //输出上传时文件名
        fmt.Println("上传文件名:", header.Filename)
    } else if r.Method == "GET" { //GET方式显示上传页面
        // 解析指定文件生成模板对象
        tem, err := template.ParseFiles("v/upload.html")
        checkErr(err)
        // 从数据库获取数据用于渲染模板
        maxid := db.GetMaxID()
        Data := DbData{
            Maxid: maxid}
        //渲染输出
        tem.Execute(w, Data)
    }
}

func checkErr(err error) {
    if err != nil {
        fmt.Println("err", err)
        panic(err)
    }
}

//数据库结构体定义/////////////////
type DbData struct {
    Maxid int
}

db.go

package db

import (
    "database/sql"
    "fmt"

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

func Create() {
    fmt.Println("打开数据库")
    db, err := sql.Open("sqlite3", "./db/db.db")
    defer db.Close()
    checkErr(err)

    //fmt.Println("创建数据表")
    sql_table := `
CREATE TABLE IF NOT EXISTS "userinfo" (
   "uid" INTEGER PRIMARY KEY AUTOINCREMENT,
   "username" VARCHAR(64) NULL,
   "departname" VARCHAR(64) NULL,
   "created" TIMESTAMP default (datetime('now', 'localtime'))  
);
CREATE TABLE IF NOT EXISTS "userdeatail" (
   "uid" INT(10) NULL,
   "intro" TEXT NULL,
   "profile" TEXT NULL,
   PRIMARY KEY (uid)
);
   `
    db.Exec(sql_table)
}

func Insert() {
    fmt.Println("打开数据库")
    db, err := sql.Open("sqlite3", "./db/db.db")
    defer db.Close()
    checkErr(err)

    //插入数据
    fmt.Print("插入数据, ID=")
    stmt, err := db.Prepare("INSERT INTO userinfo(username, departname)  values(?, ?)")
    checkErr(err)
    res, err := stmt.Exec("astaxie", "研发部门")
    checkErr(err)
    id, err := res.LastInsertId()
    checkErr(err)
    fmt.Println(id)
}

func GetMaxID() int {
    fmt.Println("打开数据库")
    db, err := sql.Open("sqlite3", "./db/db.db")
    defer db.Close()
    checkErr(err)

    //查询数据
    fmt.Println("查询数据")
    rows, err := db.Query(" SELECT MAX(uid) AS `MAXUID`  FROM  userinfo")
    checkErr(err)
    var uid int
    for rows.Next() {
        err = rows.Scan(&uid)
        checkErr(err)
        fmt.Println(uid)
    }
    return int(uid)
}

func Update() {
    fmt.Println("打开数据库")
    //先用MAX查询最大uid
    id := GetMaxID()
    db, err := sql.Open("sqlite3", "./db/db.db")
    defer db.Close()
    checkErr(err)
    //更新数据
    fmt.Print("更新数据 ")

    stmt, err := db.Prepare("update userinfo set username=? where uid=?")
    checkErr(err)
    res, err := stmt.Exec("astaxieupdate", id)
    checkErr(err)
    affect, err := res.RowsAffected()
    checkErr(err)
    fmt.Println(affect)
}

func Retrieve() {
    fmt.Println("打开数据库")
    db, err := sql.Open("sqlite3", "./db/db.db")
    defer db.Close()
    checkErr(err)

    //查询数据
    fmt.Println("查询数据")
    rows, err := db.Query("SELECT * FROM userinfo")
    checkErr(err)
    for rows.Next() {
        var uid int
        var username string
        var department string
        var created string
        err = rows.Scan(&uid, &username, &department, &created)
        checkErr(err)
        fmt.Println(uid, username, department, created)
    }
}

func Delete() {
    //先用MAX查询最大uid
    id := GetMaxID()
    fmt.Println("打开数据库")
    db, err := sql.Open("sqlite3", "./db/db.db")
    defer db.Close()
    checkErr(err)

    //删除数据
    fmt.Println("删除数据")
    stmt, err := db.Prepare("delete from userinfo where uid=?")
    checkErr(err)
    res, err := stmt.Exec(id)
    checkErr(err)
    affect, err := res.RowsAffected()
    checkErr(err)
    fmt.Println(affect)
}

func checkErr(err error) {
    if err != nil {
        panic(err)
    }
}

index.html

hello {{.Maxid}}

upload.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>文件上传</title>
</head>
<body>
<form action="/upload" enctype="multipart/form-data" method="post">  
    用户名:<input type="text" name="username"/><br/> 
    上传:<input type="file" name="upfile"/><br/>
    <input type="submit" value="提交"/>
</form>
</body>
</html>

忽然想到重要的事,多个web用户同时写数据库应加锁,大家自己补充代码吧。

posted on 2020-02-11 21:23  pu369com  阅读(497)  评论(0编辑  收藏  举报

导航