go的三方包学习
目录
go的三方包学习
本博文源于博主的学习,内容包含第三方包fasthttp,jsoniterator,gorm,xorm,yaml,toml,excel的学习
fasthttp
为什么比net/http快
- 使用连接池,不再像net/http一样每accept一个请求就分配一个新的goroutine处理请求(在请求量大的时候会有性能问题)
- 对象池化
- 使用[]byte缓冲池,减少内存分配
- 避免[]byte和string之间的转化,[]byte和string和转化会产生内存拷贝,fasthttp实现了无需内存拷贝的转化方法
例子1:hello,server
package main
import (
"flag"
"fmt"
"github.com/valyala/fasthttp"
"log"
)
var (
addr = flag.String("addr", ":8080", "TCP address to listen to")
compress = flag.Bool("compress", false, "whether to enable transparent response compression")
)
func main() {
flag.Parse()
h := requestHandler
if *compress {
h = fasthttp.CompressHandler(h)
}
if err := fasthttp.ListenAndServe(*addr, h); err != nil {
log.Fatalf("Error in ListenAndServe: %s", err)
}
}
func requestHandler(ctx *fasthttp.RequestCtx) {
fmt.Fprintf(ctx, "Hello, world!\n\n")
fmt.Fprintf(ctx, "Request method is %q\n", ctx.Method())
fmt.Fprintf(ctx, "RequestURI is %q\n", ctx.RequestURI())
fmt.Fprintf(ctx, "Request path is %q\n", ctx.Path())
fmt.Fprintf(ctx, "Host is %q\n", ctx.Host())
fmt.Fprintf(ctx, "Query string is %q\n", ctx.QueryArgs())
fmt.Fprintf(ctx, "User-Agent is %q\n", ctx.UserAgent())
fmt.Fprintf(ctx, "Connectioin has been established at %s\n", ctx.ConnTime())
fmt.Fprintf(ctx, "Request has been started at %s \n", ctx.Time())
fmt.Fprintf(ctx, "Serial request number for the current cnnection is %d\n", ctx.ConnRequestNum())
fmt.Fprintf(ctx, "Your ip is %q\n", ctx.RemoteIP())
fmt.Fprintf(ctx, "Raw request is:\n---CUT---\n%s\n---CUT---", &ctx.Request)
ctx.SetContentType("text/plain; charset=utf-8")
ctx.Response.Header.Set("X-My-Header", "my-header-value")
var c fasthttp.Cookie
c.SetKey("cookie-name")
c.SetValue("cookie-value")
ctx.Response.Header.SetCookie(&c)
}
或者另外一种精简的方式
func requestHandler(ctx *fasthttp.RequestCtx) {
ctx.SetStatusCode(fasthttp.StatusOK)
ctx.SetBodyString("Hello,FastHTTP")
}
func main() {
fmt.Println("http://127.0.0.1:8083")
if err := fasthttp.ListenAndServe(":8083", requestHandler); err != nil {
fmt.Printf("Error in ListenAndServe: %s", err)
}
}
请求路径上的参数
func requestHandler(ctx *fasthttp.RequestCtx) {
name := string(ctx.QueryArgs().Peek("name"))
if name == "" {
name = "Guest" // 如果没有提供 name 参数,默认使用 "Guest"
}
// 设置响应内容
ctx.SetStatusCode(fasthttp.StatusOK)
ctx.SetBodyString(fmt.Sprintf("Hello %s", name))
}
func main() {
fmt.Println("http://127.0.0.1:8084?name=zhangsan")
handler := fasthttp.RequestHandler(requestHandler)
err := fasthttp.ListenAndServe(":8084", handler)
if err != nil {
fmt.Printf("Error in ListenAndServe: %s", err)
}
}
处理json请求和响应,建议用postman进行认证
type Message struct {
Name string `json:"name"`
Message string `json:"message"`
}
func requestHandler(ctx *fasthttp.RequestCtx) {
if string(ctx.Method()) == "POST" {
var msg Message
if err := json.Unmarshal(ctx.PostBody(), &msg); err != nil {
ctx.SetStatusCode(fasthttp.StatusBadRequest)
ctx.SetBodyString("Invalid JSON")
return
}
response := Message{
Name: msg.Name,
Message: fmt.Sprintf("Hello %s,Your message was :%s", msg.Name, msg.Message),
}
ctx.SetContentType("application/json")
responseJSON, _ := json.Marshal(response)
ctx.SetStatusCode(fasthttp.StatusOK)
ctx.SetBody(responseJSON)
} else {
ctx.SetStatusCode(fasthttp.StatusMethodNotAllowed)
ctx.SetBodyString("Method Not Allowed")
}
}
采用中间件
func logRequest(ctx *fasthttp.RequestCtx) {
startTime := time.Now()
requestHandler(ctx)
duration := time.Since(startTime)
fmt.Printf("Request %s %s took %v\n", ctx.Method(), ctx.RequestURI(), duration)
}
func requestHandler(ctx *fasthttp.RequestCtx) {
ctx.SetStatusCode(fasthttp.StatusOK)
ctx.SetBodyString("hello, fasthttp with middleware!")
}
func main() {
handler := fasthttp.RequestHandler(func(ctx *fasthttp.RequestCtx) {
logRequest(ctx)
})
fmt.Println("http://127.0.0.1:8085/")
err := fasthttp.ListenAndServe(":8085", handler)
if err != nil {
fmt.Printf("Error starting server: %s\n", err)
}
}
文件服务器
func requestHandler(ctx *fasthttp.RequestCtx) {
filePath := filepath.Join("E:", string(ctx.Path()))
fasthttp.ServeFile(ctx, filePath)
ctx.SetStatusCode(fasthttp.StatusOK)
}
func main() {
fmt.Println("http://127.0.0.1:8086/b.txt")
err := fasthttp.ListenAndServe(":8086", requestHandler)
if err != nil {
fmt.Printf("Error starting server:%s\n", err)
}
}
json-iterator
package main
import (
"fmt"
"github.com/json-iterator/go"
)
type UserInfo struct {
Id int `json:"id"`
Age int `json:"age"`
}
func main() {
//js := jsoniter.ConfigCompatibleWithStandardLibrary
//user := UserInfo{Id: 1, Age: 10}
//marshal, err := js.Marshal(&user)
//if err != nil {
// fmt.Println(err)
//}
//fmt.Println(string(marshal))
js := jsoniter.ConfigCompatibleWithStandardLibrary
s := `{"Id":110,"Age":20}`
var user UserInfo
err := js.Unmarshal([]byte(s), &user)
if err != nil {
fmt.Println(err)
}
fmt.Println(user)
}
gorm
gorm的增删查改、事务、聚合查询
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
var db *gorm.DB
var err error
type User struct {
ID uint `gorm:"primarykey"`
Name string `gorm:"size:100;not null"`
Age int
}
func main1() {
dsn := "ad:123456@tcp(127.0.0.1:3306)/goGateWay?charset=utf8"
db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
fmt.Println("数据库连接失败", err)
}
//迁移数据库
err := db.AutoMigrate(&User{})
if err != nil {
fmt.Println("数据库迁移失败", err)
return
}
//插入数据库
user := User{Name: "John Deo", Age: 15}
result := db.Create(&user)
if result.Error != nil {
fmt.Println("插入数据库失败", result.Error)
return
}
users := []User{
{Name: "Alice", Age: 5},
{Name: "Jane", Age: 16},
{Name: "Alex", Age: 26},
{Name: "WuYiFan", Age: 56},
}
result = db.Create(&users)
if result.Error != nil {
fmt.Println("插入数据库失败", result.Error)
return
}
fmt.Println("成功插入数据库", user)
//查询数据
var queryUser User
result = db.First(&queryUser, "name = ?", "Alice")
if result.Error != nil {
fmt.Println("查询失败", result.Error)
return
}
//查询多个记录
var queryUsers []User
result = db.Find(&queryUsers)
if result.Error != nil {
fmt.Println("查询失败", result.Error)
return
}
fmt.Println("查询到所有数据")
for _, user := range queryUsers {
fmt.Println("id:", user.ID, "name", user.Name, "age", user.Age)
}
//更新数据
queryUser.Age = 24
result = db.Save(&queryUser)
if result.Error != nil {
fmt.Println("更新失败...", result.Error)
return
}
fmt.Println("成功更新用户", queryUser)
tx := db.Delete(&User{}, "age = ?", 56)
if tx.Error != nil {
fmt.Println("删除失败:", tx.Error)
return
}
fmt.Println("删除用户成功...")
}
func main2() {
///开启事务1
dsn := "ad:123456@tcp(127.0.0.1:3306)/goGateWay?charset=utf8"
db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
fmt.Println("数据库连接失败", err)
}
tx := db.Begin()
user := User{Name: "Leo", Age: 15}
if err := tx.Create(&user).Error; err != nil {
tx.Rollback()
fmt.Println("插入用户1失败", err)
return
}
user2 := User{Name: "Amy", Age: 43}
if err := tx.Create(&user2).Error; err != nil {
tx.Rollback()
fmt.Println("插入用户2失败", err)
return
}
tx.Commit()
fmt.Println("事务成功,插入两个用户")
}
func main3() {
dsn := "ad:123456@tcp(127.0.0.1:3306)/goGateWay?charset=utf8"
db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
var avgAge float64
result := db.Model(&User{}).Select("avg(age)").Scan(&avgAge)
if result.Error != nil {
fmt.Println("查询失败", result.Error)
return
}
fmt.Println("平均年龄:", avgAge)
}
xorm
映射数据库
dsn := "ad:123456@tcp(127.0.0.1:3306)/goGateWay?charset=utf8"
var err error
engine, err = xorm.NewEngine("mysql", dsn)
if err != nil {
log.Fatal(err)
}
engine.ShowSQL(true)
迁移数据表
err = engine.Sync2(new(User))
if err != nil {
log.Fatal("表创建关联: %v", err)
}
fmt.Println("表创建成功")
创建记录
user := &User{Name: "John", Age: 18}
_, err = engine.Insert(user)
if err != nil {
log.Fatal("插入失败", err)
}
fmt.Println("插入成功:", user)
查询记录
user := User{}
has, err := engine.ID(1).Get(&user)
if err != nil {
log.Fatal("查询失败:%v", err)
}
if has {
fmt.Println("查询到用户", user)
} else {
fmt.Println("没有找到该用户")
}
users := []User{
{Name: "Alice", Age: 18},
{Name: "Amy", Age: 48},
{Name: "Alex", Age: 18},
}
_, err = engine.Insert(users)
if err != nil {
log.Fatal(err)
}
fmt.Println("insert success")
查询所有记录
var users []User
err = engine.Find(&users)
if err != nil {
log.Fatal(err)
}
for _, user := range users {
log.Println(user)
}
更新记录
user := User{}
has, err := engine.ID(2).Get(&user)
if err != nil {
log.Fatal(err)
}
if has {
user.Age = 77
_, err = engine.ID(2).Update(&user)
if err != nil {
log.Fatal("更新失败", err)
}
fmt.Println("成功更新用户:", user)
} else {
fmt.Println("未找到该用户")
}
删除记录
user := User{ID: 2}
_, err = engine.Delete(&user)
if err != nil {
log.Fatal("删除失败:", err)
}
fmt.Println("成功删除用户")
聚合查询
var result struct {
Average float64 `xorm:"avg(age)"`
}
has, err := engine.Table("user").Select("avg(age)").Get(&result)
if err != nil {
log.Fatal(err)
}
if has {
fmt.Println(result.Average)
} else {
fmt.Println("没有数据")
}
事务
session := engine.NewSession()
defer session.Close()
//开始事务
err = session.Begin()
if err != nil {
log.Fatal("事务开始失败", err)
}
user1 := User{Name: "Mini", Age: 18}
_, err = session.Insert(&user1)
if err != nil {
session.Rollback()
log.Fatal("插入用户失败", err)
}
user2 := User{Name: "Bob", Age: 18}
_, err = session.Insert(&user2)
if err != nil {
session.Rollback()
log.Fatal("插入用户失败", err)
}
err = session.Commit()
if err != nil {
log.Fatal(err)
}
fmt.Println("事务成功,插入两个用户")
yaml
unmarshal 与marshal
文件example.yaml
a: Easy!
b:
c: 2
d: [3, 4]
package main
import (
"fmt"
"gopkg.in/yaml.v3"
"io/ioutil"
"log"
)
var data = `
a: Easy!
b:
c: 2
d: [3, 4]
`
type T struct {
A string
B struct {
RenamedC int `yaml:"c"`
D []int `yaml:",flow"`
}
}
func main() {
//将文件映射到结构体中
t := T{}
data, err := ioutil.ReadFile("./example.yaml")
if err != nil {
log.Fatal(err)
}
err = yaml.Unmarshal([]byte(data), &t)
if err != nil {
log.Fatal(err)
}
fmt.Println("将文件进行解析成结构体变量", t.A, t.B)
m := make(map[interface{}]interface{})
err = yaml.Unmarshal([]byte(data), &m)
if err != nil {
log.Fatalf("error:%v", err)
}
fmt.Printf("----m:\n%v\n\n", m)
d, err := yaml.Marshal(&t)
if err != nil {
log.Fatalf("error:%v", err)
}
fmt.Printf("---------t dump:\n%s\n\n", string(d))
d, err = yaml.Marshal(&m)
if err != nil {
log.Fatalf("error:%v", err)
}
fmt.Printf("---------t dump:\n%s\n\n", string(d))
}
toml
文件映射到结构体
变量映射
doc := `
version = 2
name = "go-toml"
tags = ["tag1", "tag2"]
`
var conf MyConfig
err := toml.Unmarshal([]byte(doc), &conf)
if err != nil {
panic(err)
}
fmt.Println(conf.Name, conf.Tags, conf.Version)
文件里读取
func main() {
file, err := os.Open("./abc.toml")
if err != nil {
log.Fatal(err)
}
defer file.Close()
fileContent, err := os.ReadFile("./abc.toml")
if err != nil {
log.Fatal(err)
}
var conf MyConfig
err = toml.Unmarshal(fileContent, &conf)
if err != nil {
log.Fatal(err)
}
fmt.Println(conf.Name, conf.Tags, conf.Version)
}
结构体映射到toml里
cfg := MyConfig{
Version: 3,
Name: "test",
Tags: []string{"go", "toml"},
}
b, err := toml.Marshal(cfg)
if err != nil {
panic(err)
}
fmt.Println(string(b))
另一种方式进行映射
package main
import (
"fmt"
"github.com/BurntSushi/toml"
"log"
"os"
)
type Config struct {
Title string
Owner struct {
Name string
Org string
}
}
func main() {
config := Config{
Title: "Example Config",
}
config.Owner.Name = "Alex"
config.Owner.Org = "GoLang"
file, err := os.Create("./config.toml")
if err != nil {
log.Fatal(err)
}
defer file.Close()
err = toml.NewEncoder(file).Encode(config)
if err != nil {
log.Fatal(err)
}
fmt.Println("Created config file.")
}
嵌套结构体映射
abc.toml文件
[owner]
name = "Tom Preston-Werner"
dob = 1979-05-27T07:32:00Z
[database]
server = "192.168.1.1"
ports = [8001, 8002]
Connectionmax = 5000
enabled = true
import (
"fmt"
"github.com/BurntSushi/toml"
"log"
"time"
)
type Owner struct {
Name string
Dob time.Time
}
type Database struct {
Server string
Ports []int
ConnectionMax int
Enabled bool
}
type Config struct {
Owner Owner
Database Database
}
func main() {
var config Config
_, err := toml.DecodeFile("./abc.toml", &config)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Owner:%s,Date of Birth:%v\n", config.Owner.Name, config.Owner.Dob)
fmt.Printf("Database:%v\n", config.Database.Server)
fmt.Printf("Ports:%v\n", config.Database.Ports)
fmt.Printf("Max Connections:%d\n", config.Database.ConnectionMax)
fmt.Printf("Database Enabled:%v\n", config.Database.Enabled)
}
嵌套版本
[server]
name = "My Server"
enabled = true
address = "127.0.0.1"
[server.ports]
http = 80
https = 443
[logging]
level = "debug"
files = ["app.log", "error.log"]
[[databases]]
name = "db1"
enabled = true
host = "192.168.0.2"
[[databases]]
name = "db2"
enabled = false
host = "192.168.0.3"
编写的代码
package main
import (
"fmt"
"github.com/BurntSushi/toml"
"log"
)
type Server struct {
Name string
Enabled bool
Address string
Ports map[string]int
}
type Logging struct {
Level string
Files []string
}
type Database struct {
Name string
Enabled bool
Host string
}
type Config struct {
Server Server
Logging Logging
Databases []Database
}
func main() {
var config Config
_, err := toml.DecodeFile("./abc.toml", &config)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Server Name:%s\n", config.Server.Name)
fmt.Printf("Server Enabled:%v\n", config.Server.Enabled)
fmt.Printf("Server Address:%s\n", config.Server.Address)
fmt.Printf("Server Ports:%v\n", config.Server.Ports)
fmt.Printf("Server Level:%s\n", config.Logging.Level)
fmt.Printf("Logging Files:%v\n", config.Logging.Files)
for _, db := range config.Databases {
fmt.Printf("Database Name:%s,Enabled:%v,Host:%s\n", db.Name, db.Enabled, db.Host)
}
}
excel
某个单元格写入内容,保存成excel
package main
import (
"fmt"
"github.com/xuri/excelize/v2"
)
func main() {
//将文件映射到结构体中
f := excelize.NewFile()
defer func() {
if err := f.Close(); err != nil {
fmt.Println(err)
}
}()
index, err := f.NewSheet("Sheet1")
if err != nil {
fmt.Println(err)
return
}
f.SetCellValue("Sheet1", "A2", "Hello World")
f.SetCellValue("Sheet1", "B2", 100)
f.SetActiveSheet(index)
if err := f.SaveAs("Book1.xlsx"); err != nil {
fmt.Println(err)
}
}
从excel读取数据
package main
import (
"fmt"
"github.com/xuri/excelize/v2"
)
func main() {
f, err := excelize.OpenFile("./Book1.xlsx")
if err != nil {
fmt.Println(err)
return
}
defer func() {
if err := f.Close(); err != nil {
fmt.Println(err)
}
}()
cell, err := f.GetCellValue("Sheet1", "B2")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(cell)
rows, err := f.GetRows("Sheet1")
if err != nil {
fmt.Println(err)
return
}
for _, row := range rows {
for _, colCell := range row {
fmt.Println(colCell, "\t")
}
fmt.Println()
}
}
用代码绘制excel表格
package main
import (
"fmt"
"github.com/xuri/excelize/v2"
)
func main() {
f := excelize.NewFile()
defer func() {
if err := f.Close(); err != nil {
fmt.Println(err)
}
}()
for idx, row := range [][]interface{}{
{nil, "Apple", "Orange", "Pear"}, {"Small", 2, 3, 3},
{"Normal", 5, 2, 4}, {"Large", 6, 7, 8},
} {
cell, err := excelize.CoordinatesToCellName(1, idx+1)
if err != nil {
fmt.Println(err)
return
}
f.SetSheetRow("Sheet1", cell, &row)
}
if err := f.AddChart("Sheet1", "E1", &excelize.Chart{
Type: excelize.Col3DClustered,
Series: []excelize.ChartSeries{
{
Name: "Sheet1!$A$2",
Categories: "Sheet1!$B$1:$D$1",
Values: "Sheet1!$B$2:$D$2",
},
{
Name: "Sheet1!$A$3",
Categories: "Sheet1!$B$1:$D$1",
Values: "Sheet1!$B$3:$D$3",
},
{
Name: "Sheet1!$A$4",
Categories: "Sheet1!$B$1:$D$1",
Values: "Sheet1!$B$4:$D$4",
}},
Title: []excelize.RichTextRun{
{
Text: "Fruit 3D Clustered Column Chart",
},
},
}); err != nil {
fmt.Println(err)
return
}
if err := f.SaveAs("Book2.xlsx"); err != nil {
fmt.Println(err)
}
}
遍历一个excel的多个sheet
package main
import (
"github.com/xuri/excelize/v2"
"log"
)
func main() {
f, err := excelize.OpenFile("./book3.xlsx")
if err != nil {
log.Fatal(err)
}
sheets := f.GetSheetList()
for _, sheet := range sheets {
log.Printf("Reading data from sheet:%s", sheet)
rows, err := f.GetRows(sheet)
if err != nil {
log.Fatal(err)
}
for _, row := range rows {
for _, cell := range row {
log.Print(cell, "\t")
}
log.Println()
}
}
}