亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Golang > 正文

Go語言中http和mysql的實現代碼

2020-04-01 18:51:03
字體:
來源:轉載
供稿:網友

http 編程

Go 原生支持http:

import "net/http"

Go 的http服務性能和nginx比較接近:

就是說用Go寫的Web程序上線,程序前面不需要再部署nginx的Web服務器,這里省掉的是Web服務器。如果服務器上部署了多個Web應用,還是需要反向代理的,一般這也是nginx或apache。

幾行代碼就可以實現一個web服務:

package mainimport ( "fmt" "net/http")func Hello(w http.ResponseWriter, r *http.Request) { fmt.Println(*r) fmt.Fprintf(w, "Hello World")}func main() { http.HandleFunc("/", Hello) err := http.ListenAndServe("0.0.0.0:8000", nil) if err != nil {  fmt.Println("http Listen failed") }}

http client

http 常見的請求方法:

  • Get請求
  • Post請求
  • Put請求
  • Delete請求
  • Head請求

Get 請求

使用Get請求網站的示例:

package mainimport ( "fmt" "io/ioutil" "net/http")func main() { res, err := http.Get("http://edu.51cto.com") if err != nil {  fmt.Println("http get ERRPR:", err)  return } data, err := ioutil.ReadAll(res.Body) if err != nil {  fmt.Println("get data ERROR:", err)  return } fmt.Println(string(data))}

Head請求

Head請求只返回響應頭。如果只想要獲取一些狀態信息的話,可以用Head請求。這樣避免返回響應體,響應體的數據是比較多的,適合做監控。Head請求的示例:

package mainimport ( "fmt" "net/http")var urls = []string{ "http://×××w.baidu.com", "http://×××w.google.com", "http://×××w.sina.com.cn", "http://×××w.163.com",}func main() { for _, v := range urls {  resp, err := http.Head(v)  if err != nil {   fmt.Println("Head request ERROR:", err)   continue  }  fmt.Println(resp.Status) }}

http 常見狀態碼

http.StatusContinue = 100

http.StatusOK = 200

http.StatusFound = 302 跳轉

http.StatusBadRequest = 400 非法請求

http.StatusUnanthorized = 401 沒有權限

http.StatusForbidden = 403 禁止訪問

http.Status.NotFound = 404 頁面不存在

http.StatusInternalServerError = 500 內部錯誤

處理form表單

package mainimport ( "fmt" "io" "net/http")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></body></html>`func FormServer(w http.ResponseWriter, request *http.Request) { w.Header().Set("content-Type", "text/html") switch request.Method { case "GET":  io.WriteString(w, form) case "POST":  request.ParseForm()  io.WriteString(w, request.Form["in"][0]) // 注意上面的2個input的name是一樣的  io.WriteString(w, request.Form["in"][1]) // 所以這是一個數組  io.WriteString(w, "</br>")  io.WriteString(w, request.FormValue("in")) // 一般去一個值,就用這個方法 }}func main() { http.HandleFunc("/form", FormServer) if err := http.ListenAndServe(":8000", nil); err != nil {  fmt.Println("監聽端口ERROR:", err) }}

panic 處理

如果處理函數里有panic,會導致整個程序崩潰,所以要 defer revoer() 來處理 panic。在處理函數開頭defer一個匿名函數:

func FormServer(w http.ResponseWriter, request *http.Request) { // 增加一個defer來處理panic defer func() {  if x := recover(); x != nil {   log.Println(request.RemoteAddr, "捕獲到異常:", x)  } }() // 原本的處理函數的內容 w.Header().Set("content-Type", "text/html") switch request.Method { case "GET":  io.WriteString(w, form) case "POST":  request.ParseForm()  io.WriteString(w, request.FormValue("in")) // 一般去一個值,就用這個方法 } // 搞個panic出來 zero := 0 tmp := 1 / zero io.WriteString(w, string(tmp))}

優化統一處理

按照上面的做法,要在每個處理函數的開頭都加上panic的處理。由于每個處理函數的panic處理方法都一樣,所以可以寫一個自定義的處理函數:

// 自定義的panic處理的函數func logPanics(handle http.HandlerFunc) http.HandlerFunc { return func(writer http.ResponseWriter, request *http.Request) {  defer func() {   if x := recover(); x != nil {    log.Println(request.RemoteAddr, "捕獲到異常:", x)   }  }()  // 上面先處理panic,再接著下面調用業務邏輯  handle(writer, request) }}func main() { // http.HandleFunc("/form", FormServer) // 修改調用處理函數的方法 http.HandleFunc("/form", logPanics(FormServer)) // 把處理函數傳給自己寫的封裝了panic處理的函數里 if err := http.ListenAndServe(":8000", nil); err != nil {  fmt.Println("監聽端口ERROR:", err) }}

原本直接調用處理函數?,F在調用自定義的函數,把處理函數傳進去。在自定義的函數里先加載defer,然后再調用執行原本的處理函數。邏輯很簡單,就是把處理函數作為參數傳給自定義的函數,在自定義的函數里再調用處理函數。在自定義的函數里寫上defer,這樣就相當于所有的處理函數都有defer了。

模板

使用模板需要用到 "text/template" 包。然后調用模板的t.Execute()方法輸出。

替換

先準備一個簡單的模板:

<p>Hello {{.Name}}</p><p>Age: {{.Age}}</p>

然后在Go里使用模板:

package mainimport ( "fmt" "os" "text/template")type Person struct { Name string Age int}func main() { t, err := template.ParseFiles("index.html") if err != nil {  fmt.Println("模板解析異常:", err)  return } p := Person{"Bob", 32} if err := t.Execute(os.Stdout, p); err != nil {  fmt.Println("模板加載數據異常:", err) }}/* 執行結果PS H:/Go/src/go_dev/day10/http/use_template> go run main.go<p>Hello Bob</p><p>Age: 32</p>PS H:/Go/src/go_dev/day10/http/use_template>*/

如果直接用 {{.}} 不加字段名的話,就是輸出結構體打印的效果。

輸出到瀏覽器里

要輸出到瀏覽器里,只需要在 t.Execute(os.Stdout, p) 里,把原本輸出到終端換成輸出到處理函數的 w http.ResponseWriter 類型,就好了。

html模板的內容不變,下面是go的代碼:

package mainimport ( "fmt" "net/http" "text/template")func Hello(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello World")}type Person struct { Name string Age int}func Index(w http.ResponseWriter, r *http.Request) { p := Person{"Cara", 18} t, err := template.ParseFiles("index.html") if err != nil {  fmt.Println("加載模板ERROR:", err)  return } t.Execute(w, p)}func main() { http.HandleFunc("/", Hello) http.HandleFunc("/index", Index) err := http.ListenAndServe("0.0.0.0:8000", nil) if err != nil {  fmt.Println("http Listen failed") }}

判斷

用法示例:

<body>{{if gt .Age 18}}<p>已成年</p>{{else}}<p>未成年</p>{{end}}</body>

更多判斷邏輯:

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 小于

{{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語句就是創建一個封閉的作用域,在其范圍內,{{.}}代表with的變量,而與外面的{{.}}無關,只與with的參數有關:

<body>{{with .Name}}<p>{{.}}</p>{{end}}</body>

上面這樣包在 {{with .Var}} 里,with 里的 {{.}} 代表的就是 Var 這個變量。

with 可以封裝常數:

{{ with "world"}} Now the dot is set to {{ . }}{{ end }}

循環(遍歷)

golang的template支持range循環來遍歷map、slice內的內容,在range循環內,還可以使用$設置循環變量,我們可以通過 $i $v 來訪問遍歷的值。語法為:

{{range $i, $v := .slice}} <li>key: {{ $key }}, value: {{ $value }}</li>{{end}}

這是另外一種遍歷方式,這種方式無法訪問到index或者key的值,需要通過點來訪問對應的value:

{{range .slice}}{{.field}}{{end}}

在循環內,點是代表遍歷的值。原本使用點來訪問的變量,那么在循環內部就要用 $. 來訪問。下面的例子表示循環內和循環外 ArticleConten 這個變量訪問的方式:

{{.ArticleContent}}{{range .slice}}{{$.ArticleContent}}{{end}}

定義變量

模板的參數可以是go中的基本數據類型,如字串,數字,布爾值,數組切片或者一個結構體。在模板中設置變量可以使用 $variable := value。我們在range迭代的過程使用了設置變量的方式。

{{$article := "hello"}}{{$name := .Name}}

mysql 使用

這里只簡單講了數據的增刪改查,所以測試代碼前,需要先把數據庫準備好。

先創建一個數據庫,指定了編碼,這樣應該可以支持中文:

CREATE DATABASE 庫名 CHARSET "utf8";

然后建2張表:

CREATE TABLE person (  user_id int primary key auto_increment,  username varchar(260),  gender varchar(260),  email varchar(260));CREATE TABLE place (  country varchar(200),  city varchar(200),  telcode int);

 

導入數據庫驅動

sql 包提供了通用的SQL(或類SQL)數據庫接口。

sql 包必須與數據庫驅動結合使用。

驅動包需要安裝:

go get -u github.com/go-sql-driver/mysql

使用前,先要導入mysql的包:

import (  "database/sql"  _ "github.com/go-sql-driver/mysql")

上面導入了2個包。第一個是sql包,就是我們調用操作數據庫用的。

第二個是驅動包,這里前面加了占位符,所以這個包只是引入,但是不使用它。并且如果要操作別的數據庫的話,只需要修改驅動包就行了。

連接數據庫

構建連接, 格式是:”用戶名:密碼@tcp(IP:端口)/數據庫?charset=utf8” :

package mainimport (  "fmt"  "time"  "database/sql"  _ "github.com/go-sql-driver/mysql")var DB *sql.DBfunc init() {  database, err := sql.Open("mysql", "admin:admin123@tcp(192.168.3.103:3306)/Golang_week10")  if err != nil {    fmt.Println("連接數據庫失敗:", err)    return  }  DB = database}func main() {  fmt.Println(DB)  DB.SetMaxIdleConns(16) //設置閑置連接數  DB.SetMaxOpenConns(100) //設置最大連接數  DB.SetConnMaxLifetime(100*time.Second) //最大連接周期,超過時間的連接就close  fmt.Println(DB)}

 

插入數據

下面是插入數據,并且再獲取id的示例:

// 數據庫連接的init函數就省略了func insert() {  r, err := DB.Exec("insert into person(username,gender,email) values(?,?,?)", "Barry", "Male", "Barry@go.net")  if err != nil {    fmt.Println("插入數據ERROR:", err)    return  }  fmt.Println(r)  id, err := r.LastInsertId()  if err != nil {    fmt.Println("獲取id ERROR:", err)    return  }  fmt.Println(id)}func main() {  insert()}

 

上面的 values(?,?,?) 里的問號,是占位符,具體的值可以寫在后面的參數里。當然如果不用占位符,直接就傳1個字符串作為參數也是可以的。

查詢

查詢單個字段:

func query() {  row := DB.QueryRow("select username from person where user_id=?", 1)  var name string // 創建變量用于存放查詢到的數據  if err := row.Scan(&name); err != nil {    fmt.Println("Scan Failed:", err)    return  }  fmt.Println(name)}func main() {  query()}

也可以一次查詢多個字段或所有字段,查詢之前按照表的類型創建結構體,用查詢到的數據為結構體賦值:

type Person struct {  ID int `db:"user_id"`  Username sql.NullString `db:"username"`  Gender sql.NullString `db:"gender"`  Email sql.NullString `db:"email"`}func query() {  row := DB.QueryRow("select * from person where user_id=?", 6)  var person = new(Person)  // row.scan中的字段必須是按照數據庫存入字段的順序,否則報錯  if err := row.Scan(&person.ID, &person.Username, &person.Gender, &person.Email); err != nil {    fmt.Println("Scan Failed:", err)    return  }  fmt.Println(person)}func main() {  query()}

 

數據模型,就是上面定義的結構體。這里的類型可以是Go的標準數據類型。但是如果數據庫的字段允許為空,并且該字段的值也為空,那么查詢后該字段會返回nil。如果是string類型,則無法接收nil,但sql.NullString則可以接收nil值。

另外,結構體里的tag標簽在這里沒有意義。不過上面的tag標注了該字段在數據庫里對應的字段名,可能在別處會有用。

查詢多行

func query() {  rows, err := DB.Query("select * from person where user_id > ?", 1)  defer func() {    if rows != nil {      rows.Close()    }  }()  if err != nil {    fmt.Println("Query 查詢 ERROR:", err)    return  }  var person = new(Person)  for rows.Next() {    if err = rows.Scan(&person.ID, &person.Username, &person.Gender, &person.Email); err != nil {      fmt.Println("Scan Failed:", err)      return    }    fmt.Println(person)  }}func main() {  query()}

 

查詢用起來還是不太方法,不過還可以選擇其他第三方庫,那里會有一些很好的擴展。后面會舉例。

其他操作

由于基本都是用SQL的命令進行操作,所以其他操作就不一個一個舉例了

update 更新數據

result, err := DB.Exec("UPDATE person set email=? where username=?", "Cara", Cara@catco.org)

delete 刪除數據

result,err := DB.Exec("DELETE FROM person where id=?",1)

注意:更新數據不返回LastInsertID,所以result.LastInsertID一直為0。刪除數據可以拿到LastInsertID,用法和插入數據里一樣。

第三方庫 sqlx

sqlx是一個go語言包,在內置database/sql包之上增加了很多擴展,簡化數據庫操作代碼的書寫。

由于database/sql接口是sqlx的子集,所有database/sql的用法,在sqlx中一樣可以用。不過sqlx還有更多擴展,用起來更方便。

安裝:

go get github.com/jmoiron/sqlx

查詢 Select() 方法

Select是一個非常省時的擴展。它們把query和非常靈活的scan語法結合起來。Select用來獲取結果切片:

// 這里的tag標簽就有意義了,下面的Select()方法應該就是根據tag標簽對號入座的type Person struct {  ID int `db:"user_id"`  Username sql.NullString `db:"username"`  Gender sql.NullString `db:"gender"`  Email sql.NullString `db:"email"`}func select() {  var persons []Person // 這里創建的是存放結構體的切片  if err := DB.Select(&person, "select * from person where userid > ?", 1); err != nil {    fmt.Println("Select ERROR:", err)    return  }  fmt.Println(person)}

 

Select可以提高編碼效率,還有更多擴展。sqlx 號稱 golang 數據庫開發神器,這里就提一下,等到真正用的時候再去深入學習了。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲精品国产精品乱码不99按摩| 日韩欧美第一页| 亚洲国产精品资源| 亚洲视频自拍偷拍| 91精品国产色综合久久不卡98口| 黑人精品xxx一区一二区| 精品久久久香蕉免费精品视频| 成人97在线观看视频| 国产精品一区二区久久久久| 国产日韩欧美影视| 91在线无精精品一区二区| 欧美性猛交xxxx| 国产精品久久久久久久久久ktv| 亚洲欧美在线x视频| 日韩欧美主播在线| 日韩免费在线观看视频| 国产精品xxx视频| 午夜精品久久久久久久男人的天堂| 国产日韩欧美在线观看| 国产精品video| 亚洲色图18p| 亚洲精品美女在线观看| 奇米4444一区二区三区| 成人在线国产精品| 亚洲自拍高清视频网站| 亚洲欧洲在线播放| 日韩激情视频在线播放| 国产69精品99久久久久久宅男| 亚洲午夜精品视频| 福利一区福利二区微拍刺激| 精品国产乱码久久久久久婷婷| 精品亚洲va在线va天堂资源站| 97久久伊人激情网| 欧美激情亚洲自拍| 国产婷婷成人久久av免费高清| 欧美日韩在线视频一区二区| 三级精品视频久久久久| 色噜噜狠狠狠综合曰曰曰| 日韩精品免费观看| 中文字幕久精品免费视频| 国产精品久久久久久婷婷天堂| 亚洲综合最新在线| 国产丝袜一区二区三区| 亚洲最大成人在线| 国产亚洲精品va在线观看| 日韩成人av网| 国产一区二区三区在线免费观看| 久久91精品国产91久久跳| 激情av一区二区| 日韩精品在线免费观看视频| 欧美性猛交99久久久久99按摩| 日韩不卡在线观看| 亚洲精品国产精品国自产在线| 18一19gay欧美视频网站| 亚洲精品网站在线播放gif| 九九热r在线视频精品| 欧美一级高清免费| 亚洲精品av在线播放| 日韩av免费一区| 色先锋资源久久综合5566| 最新亚洲国产精品| 一区二区国产精品视频| 久久久国产91| 97视频在线观看免费高清完整版在线观看| 亚洲品质视频自拍网| 欧美成年人视频网站欧美| 亚洲毛片在线免费观看| 日韩免费在线看| 色综合久久88| 热久久视久久精品18亚洲精品| 久久精品视频在线| 国产成人在线视频| 欧洲日韩成人av| 成人有码视频在线播放| 久久6精品影院| 欧美成人精品一区| 欧美性猛交xxx| 日韩毛片在线看| 午夜剧场成人观在线视频免费观看| 97超碰国产精品女人人人爽| 久久久久久九九九| 亚洲成色999久久网站| 大量国产精品视频| 美日韩精品免费视频| 欧美性感美女h网站在线观看免费| 日本a级片电影一区二区| 亚洲无限乱码一二三四麻| 日韩欧美国产激情| zzijzzij亚洲日本成熟少妇| 亚洲一区av在线播放| 亚洲第一区在线| 欧美电影在线观看完整版| 91精品综合久久久久久五月天| 高清欧美性猛交xxxx黑人猛交| 欧美色欧美亚洲高清在线视频| 伊人久久男人天堂| 亚洲精品久久久久中文字幕二区| 国产一区二区久久精品| 成人乱色短篇合集| 原创国产精品91| 久久综合色88| 57pao国产精品一区| 日韩美女免费线视频| 精品视频久久久| 欧美贵妇videos办公室| 96pao国产成视频永久免费| 日本精品久久久久影院| 成人a级免费视频| 日韩性xxxx爱| 成人a免费视频| 亚洲深夜福利网站| 久久免费视频网| 51色欧美片视频在线观看| 性欧美亚洲xxxx乳在线观看| 亚洲激情 国产| 欧美成人自拍视频| 欧美在线一区二区视频| 久久久成人av| 亚洲石原莉奈一区二区在线观看| 亚洲精品福利免费在线观看| 不卡伊人av在线播放| 狠狠躁夜夜躁人人爽超碰91| 91在线观看免费| 国产一区二区三区在线观看视频| 国产精品av电影| 97欧美精品一区二区三区| 久久亚洲影音av资源网| 欧美日韩精品中文字幕| 日韩精品中文字幕在线观看| 亚洲xxxx在线| 国产成人av在线| 国产精品成人久久久久| 成人精品在线视频| 欧美成人精品xxx| 国产精品流白浆视频| 欧美激情视频给我| 国产一区二区在线播放| 欧美xxxx做受欧美| 亚洲欧洲av一区二区| 精品国产自在精品国产浪潮| 国产精品极品在线| 中文字幕精品—区二区| 97精品伊人久久久大香线蕉| 国产综合在线视频| 色多多国产成人永久免费网站| 欧美性生活大片免费观看网址| 欧美体内谢she精2性欧美| 日本久久久久久久久久久| 国产日韩av在线播放| 日韩电影中文字幕在线观看| 欧美电影免费观看网站| 久久99视频免费| 91精品国产九九九久久久亚洲| 日韩资源在线观看| 欧美电影免费观看大全| 日韩av中文字幕在线播放| 国产日产欧美a一级在线| 日韩麻豆第一页| 欧美精品一区二区免费| 欧美激情一区二区三区成人| 亚洲精品国产精品国自产观看浪潮| 91精品久久久久久久久久久久久| 欧美成人精品三级在线观看| 国产精品高清在线|