golang(10):web開發 & 連接數據庫


http編程

1) Go原生支持 http : import ("net/http")
2) Go 的 http 服務性能和 nginx 比較接近
3) 幾行代碼就可以實現一個 web 服務

http 服務端

// 示例代碼:
package main

import (
    "fmt"
    "net/http"
)

func Hello(w http.ResponseWriter, r *http.Request){
    fmt.Println("hello world\n")
    fmt.Fprintf(w,"hello world")    // 返回響應
}


func main(){
    http.HandleFunc("/",Hello)        // 路由;第一個參數是路徑,第二個參數是視圖函數
    err := http.ListenAndServe("0.0.0.0:8080",nil)        // 監聽並等待請求
    if err != nil{
        fmt.Println("http listened failed")
    }
}

http 客戶端

// 示例代碼:
package main

import (
    "fmt"
    "net/http"
    "io/ioutil"
)

func main(){
    ret,err := http.Get("https://www.baidu.com/")    // 向一個服務器發送 GET 請求;返回的數據都在 ret.Body 里面
    if err != nil {
        fmt.Println("get err:",err)
        return
    }

    data,err := ioutil.ReadAll(ret.Body)    // 返回的數據都在 ret.Body 里面
    if err != nil {
        fmt.Println("get data err:",err)
        return
    }

    fmt.Printf("Type:%T\n",data)
    fmt.Println(string(data))
}


// 運行結果:
[root@NEO example01_http_client]# go run main/main.go
Type:[]uint8
<html>
<head>
    <script>
        location.replace(location.href.replace("https://","http://"));
    </script>
</head>
<body>
    <noscript><meta http-equiv="refresh" content="0;url=http://www.baidu.com/"></noscript>
</body>
</html>
[root@NEO example01_http_client]# 

 

http常見請求方法

1)Get請求
2)Post請求
3)Put請求
4)Delete請求
5)Head請求        -- > 只請求頁面的頭部

發送 HEAD 請求

// 示例代碼:
package main

import (
    "fmt"
    "net/http"
)

var urls = []string{
    "http://www.baidu.com",
    "http://www.google.com",
    "http://www.taobao.com",
}

func main(){
    for _,v := range urls{
        resp,err := http.Head(v)    // 發送 Head 請求
        if err != nil {
            fmt.Printf("head %s failed,err:%v\n",v,err)
            continue
        }
        fmt.Printf("head success,status:%v\n",resp.Status)        // resp.Status --> 狀態碼
    }
}

// 運行結果:
[root@NEO example01_http_head_request]# go run main/main.go
head success,status:200 OK
head http://www.google.com failed,err:Head http://www.google.com: dial tcp 75.126.2.43:80: connect: connection timed out
head success,status:200 OK
[root@NEO example01_http_head_request]# 


// 自定義超時時間
// 示例代碼:
package main

import (
    "fmt"
    "net/http"
    "time"
    "net"
)

var urls = []string{
    "http://www.baidu.com",
    "http://www.google.com",
    "http://www.taobao.com",
}

func main(){
    for _,v := range urls{
        c := http.Client{        // 自定義客戶端
            Transport: &http.Transport{
                Dial: func(network, addr string) (net.Conn, error){
                    timeout := time.Second * 2        // 自定義超時時間
                    return net.DialTimeout(network, addr, timeout)
                },
            },
        }    

        start := time.Now()
        resp,err := c.Head(v)    // 用自定義的客戶端發送請求
        end := time.Now()
        interval := end.Sub(start)
        fmt.Println("interval:",interval)
        //resp,err := http.Head(v)    // 發送 Head 請求
        if err != nil {
            fmt.Printf("head %s failed,err:%v\n",v,err)
            continue
        }
        fmt.Printf("head success,status:%v\n",resp.Status)        // resp.Status --> 狀態碼
    }
}


// 運行結果:
[root@NEO example01_http_head_request]# go run main/main.go
interval: 171.062376ms
head success,status:200 OK
interval: 2.000789206s
head http://www.google.com failed,err:Head http://www.google.com: dial tcp 69.63.184.142:80: i/o timeout
interval: 749.542763ms
head success,status:200 OK
[root@NEO example01_http_head_request]# 

http 常見狀態碼:

http.StatusContinue = 100
http.StatusOK = 200
http.StatusFound = 302
http.StatusBadRequest = 400
http.StatusUnauthorized = 401
http.StatusForbidden = 403
http.StatusNotFound = 404
http.StatusInternalServerError = 500

表單處理:

// 示例代碼:
package main
import (
    "io"
    "net/http"
)


// 常量 form 是一段 html 代碼
const form = `<html><body><form action="#" method="post" name="bar">
                    <input type="text" name="in"/>
                    <input type="text" name="in"/>
                     <input type="submit" value="Submit"/>
             </form></html></body>`

func SimpleServer(w http.ResponseWriter, request *http.Request) {        // 請求信息都在 request 中
    io.WriteString(w, "<h1>hello, world</h1>")        // 返回給客戶端一段html代碼
}

func FormServer(w http.ResponseWriter, request *http.Request) {
    w.Header().Set("Content-Type", "text/html")            // w.Head().Set(key,val)  --->  設置響應頭
    switch request.Method {                                // request.Method --> 請求方法
    case "GET":
        io.WriteString(w, form)            // 把 form 表單返回給客戶端
    case "POST":
        request.ParseForm()        // 需要先解析表單
        io.WriteString(w, request.Form["in"][0])        // request.Form["in"]    是一個數組
        io.WriteString(w, "\n")
        io.WriteString(w, request.FormValue("in"))        // request.FormValue("in")  ---> 獲取表單中的值(name重復時,取最近的一個);推薦使用這個
    }
}
func main() {
    http.HandleFunc("/test1", SimpleServer)
    http.HandleFunc("/test2", FormServer)
    if err := http.ListenAndServe(":8088", nil); err != nil {
    }
}

模板操作

1) 替換

main.go 文件內容如下:

// 示例代碼:
package main

import (
    "fmt"
    "os"
    "text/template"        // 導入 模板 包
)

type Person struct {
    Name string
    age  string
}

func main() {
    t, err := template.ParseFiles("./index.html")        // 解析模板文件; t 是模板對象
    if err != nil {
        fmt.Println("parse file err:", err)
        return
    }
    p := Person{Name: "Mary", age: "31"}    // 結構體對象首字母大寫的字段可以導入到模板中
    if err := t.Execute(os.Stdout, p); err != nil {        // t.Execute()  --> 執行模板對象,第一個參數表示輸出到終端,第二個參數表示 導入的結構體對象
        fmt.Println("There was an error:", err.Error())
    }
}

index.html 代碼如下:

<html>
    <head> // 結構體對象沒有的字段不能導入,要不然會報錯,如下 
    </head>
    <body>
        <p>{{.}} </p> // .表示 p 那個對象 
        <p> hello, {{.Name}}</p> // .Name 表示 p 對象 的Name字段的值 #}
        // 首字母小寫的字段也不能在模板中渲染 </body>
</html>

運行結果:

// 運行結果:
[root@NEO main]# go run main.go 
<html>
    <head>
        // 結構體對象沒有的字段不能導入,要不然會報錯,如下 
    </head>
    <body>
        <p>{Mary 31} </p>    //  .表示 p 那個對象 
        <p> hello, Mary</p>    //  .Name 表示 p 對象 的Name字段的值 #}
        // 首字母小寫的字段也不能在模板中渲染
    </body>
</html>
[root@NEO main]# 

2) if 判斷 

main.go 文件內容:

// 示例代碼:
package main

import (
    "fmt"
    "text/template"        // 導入 模板 包
    "net/http"
)

type Person struct {
    Name string
    Age  int
}

func RenderTemplate(w http.ResponseWriter, request *http.Request){
    t, err := template.ParseFiles("./index.html")       // 解析模板文件; t 是模板對象
    if err != nil {
        fmt.Println("parse file err:", err)
        return
    } 
    p := Person{Name: "Mary", Age: 31}    // 結構體對象首字母大寫的字段可以導入到模板中 
    if err := t.Execute(w, p); err != nil {     // 模板寫入到在 http.ResponseWriter 中,返回給客戶端 
        fmt.Println("There was an error:", err.Error())
    }    
}

func main() {
    http.HandleFunc("/template",RenderTemplate)
    if err := http.ListenAndServe(":8080",nil); err != nil {
    }
}

index.html 文件內容:

<html>
    <head>
    </head>
    <body> /* if 語法: {{if ...}} {{else}} {{end}} */ {# gt 表示大於 #}
        {{if gt .Age 18}}
        <p>hello oldman,{{.Name}} </p>
        {{else}}
        <p>hello young {{.Name}}</p>
        {{end}}
    </body>
</html>

 

if常見操作符:

not 非
{{if not .condition}} 
{{end}}

and 與
{{if and .condition1 .condition2}} 
{{end}}

or 或
{{if or .condition1 .condition2}} 
{{end}}

eq 等於
{{if eq .var1 .var2}} 
{{end}}

ne 不等於
{{if ne .var1 .var2}} 
{{end}}

lt 小於 (less than)
{{if lt .var1 .var2}} 
{{end}}

le 小於等於
{{if le .var1 .var2}} 
{{end}}

gt 大於
{{if gt .var1 .var2}} 
{{end}}

ge 大於等於
{{if ge .var1 .var2}} 
{{end}}

模板中with的用法:

{{with .Var}}
{end}}

示例代碼:

<html>
    <head>
    </head>
    <body>
        {{with .Name}}        <!-- 通過這行的 with ,. 就代表 Name ;只有 with 語句中 . 是 Name -->
        <p>hello, old man, {{.}}</p>
        {{end}}
    </body>
</html>

模板的循環:

{{range.}} 

{{end }}

示例代碼:

<html>
    <head>
    </head>
    <body>
        <!-- 遍歷 變量-->
        {{range .}}
            {{if gt .Age 18}}
            <p>hello, old man, {{.Name}}</p>
            {{else}}
            <p>hello,young man, {{.Name}}</p>
            {{end}}
        {{end}}
    </body>
</html>

 

Mysql

新建測試表

CREATE TABLE person (
    user_id int primary key auto_increment,
    username varchar(260),
    sex varchar(260),
    email varchar(260)
);

CREATE TABLE place (
    country varchar(200),
    city varchar(200),
    telcode int
);

安裝連接數據庫的第三方包:

go get -u github.com/go-sql-driver/mysql        // 安裝 mysql 驅動
go get github.com/jmoiron/sqlx

鏈接mysql:

// 先在 數據庫主機上分配權限,如下:
mysql> grant all privileges on gotest.* to 'root'@'172.16.1.%' identified by '123456';
mysql> flush privileges;
// 代碼運行服務器內網地址: 172.16.1.122

database, err := sqlx.Open("mysql", "root:123456@tcp(172.16.1.51:3306)/gotest")
// 參數說明:
// "mysql"            ---> 數據庫類型
// root                ---> 用戶名
// 123456            ---> 密碼
// tcp                ---> 連接協議
// 172.16.1.50        ---> 數據庫主機地址
// 3306                ---> 端口
// gotest            ---> 數據庫名稱

 

go 數據庫的增刪改查

insert操作

r, err := Db.Exec("insert into person(username, sex, email)values(?, ?, ?)", "stu001", "man", "stu01@qq.com")        // ? 是占位符

示例代碼:

package main

import (
    "fmt"
    _ "github.com/go-sql-driver/mysql"        // _ 表示只是把這個庫引進來做初始化,但並不直接引用這個庫
    "github.com/jmoiron/sqlx"        // sqlx 在 mysql 驅動的層面上又做了封裝,會更好用些
)

type Person struct {
    UserId   int    `db:"user_id"`            // tag 就是數據庫中的列名
    Username string `db:"username"`
    Sex      string `db:"sex"`
    Email    string `db:"email"`
}

type Place struct {
    Country string `db:"country"`
    City    string `db:"city"`
    TelCode int    `db:"telcode"`
}

var Db *sqlx.DB        // Db 就代表一個數據庫;Db 這個變量是線程安全的,因為其內部已經內置實現了一個 連接池

func init() {        // init() 函數在 main 函數之前自動執行
    database, err := sqlx.Open("mysql", "root:123456@tcp(172.16.1.51:3306)/gotest")        // database 是一個數據庫實例
    if err != nil {
        fmt.Println("open mysql failed,", err)
        return
    }
    Db = database
}

func main() {
    r, err := Db.Exec("insert into person(username, sex, email)values(?, ?, ?)", "stu001", "man", "stu01@qq.com")

    if err != nil {
        fmt.Println("exec failed, ", err)
        return
    }
    id, err := r.LastInsertId()        // 剛插入的那條記錄的 id
    if err != nil {
        fmt.Println("exec failed, ", err)
        return
    }

    fmt.Println("insert succ:", id)
}

Select 操作

err := Db.Select(&person, "select user_id, username, sex, email from person where user_id=?", 1)

示例代碼:

package main

import (
    "fmt"
    _ "github.com/go-sql-driver/mysql"
    "github.com/jmoiron/sqlx"
)

type Person struct {
    UserId   int    `db:"user_id"`
    Username string `db:"username"`
    Sex      string `db:"sex"`
    Email    string `db:"email"`
}

type Place struct {
    Country string `db:"country"`
    City    string `db:"city"`
    TelCode int    `db:"telcode"`
}
var Db *sqlx.DB
func init() {

    database, err := sqlx.Open("mysql", "root:123456@tcp(172.16.1.51:3306)/gotest")
    if err != nil {
        fmt.Println("open mysql failed,", err)
        return
    }

    Db = database
}

func main() {

    var person []Person
    err := Db.Select(&person, "select user_id, username, sex, email from person where user_id=?", 1)    // 從數據庫中查詢出來結果會自動填充到 person 這個結構體中
    if err != nil {
        fmt.Println("exec failed, ", err)
        return
    }

    fmt.Println("select succ:", person)
}


// 運行結果:
[root@NEO example02_mysql_select]# go run main/main.go
select succ: [{1 stu001 man stu01@qq.com}]
[root@NEO example02_mysql_select]#

update操作

_, err := Db.Exec("update person set username=? where user_id=?", "stu0001", 1)

示例代碼:

package main

import (
    "fmt"
    _ "github.com/go-sql-driver/mysql"
    "github.com/jmoiron/sqlx"
)

type Person struct {
    UserId   int    `db:"user_id"`
    Username string `db:"username"`
    Sex      string `db:"sex"`
    Email    string `db:"email"`
}

type Place struct {
    Country string `db:"country"`
    City    string `db:"city"`
    TelCode int    `db:"telcode"`
}

var Db *sqlx.DB

func init() {

    database, err := sqlx.Open("mysql", "root:123456@tcp(172.16.1.51:3306)/gotest")
    if err != nil {
        fmt.Println("open mysql failed,", err)
        return
    }

    Db = database
}

func main() {

    _, err := Db.Exec("update person set username=? where user_id=?", "stu0001", 1)        // 更新操作
    if err != nil {
        fmt.Println("exec failed, ", err)
        return
    }

}

Delete 操作

_, err := Db.Exec("delete from person where user_id=?", 1)

示例代碼:

package main

import (
    "fmt"
    _ "github.com/go-sql-driver/mysql"
    "github.com/jmoiron/sqlx"
)

type Person struct {
    UserId   int    `db:"user_id"`
    Username string `db:"username"`
    Sex      string `db:"sex"`
    Email    string `db:"email"`
}

type Place struct {
    Country string `db:"country"`
    City    string `db:"city"`
    TelCode int    `db:"telcode"`
}

var Db *sqlx.DB

func init() {

    database, err := sqlx.Open("mysql", "root:123456@tcp(172.16.1.51:3306)/gotest")
    if err != nil {
        fmt.Println("open mysql failed,", err)
        return
    }

    Db = database
}

func main() {

    _, err := Db.Exec("delete from person where user_id=?", 1)
    if err != nil {
        fmt.Println("exec failed, ", err)
        return
    }

    fmt.Println("delete succ")
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM