目录

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()
		}
	}
}