跳至主要內容

golang 包推荐

OrangBus大约 5 分钟

官方仓库:https://pkg.go.devopen in new window

示例源码仓库:https://gitee.com/orangbus/study-goopen in new window

m3u8 解析库

go get -u github.com/grafov/m3u8

定时器

https://github.com/robfig/cronopen in new window

go get -u github.com/robfig/cron/v3
func main() {
	c := cron.New()
	ch := make(chan int)
	go func() {
		c.AddFunc("@daily", func() {
			time.Sleep(time.Second * 2)
			fmt.Printf("%s\n", dns)
			ch <- 1
		})
	}()
	c.Start()
	for {
		data := <-ch
		fmt.Println(data)
	}
}

gin

go get -u github.com/gin-gonic/gin

goquery

go get -u github.com/PuerkitoBio/goquery

获取某个节点

func TestNode(t *testing.T) {
	url := "https://www.hf960.com/n5061c23.aspx"
	response, err := http.Get(url)
	if err != nil {
		panic(err)
	}
	defer response.Body.Close()

	doc, err := goquery.NewDocumentFromReader(response.Body)
	if err != nil {
		panic(err)
	}
	selection := doc.Selection.Find("#bodyTd")
	fmt.Println(selection.Find(".aTitle").Text())
	fmt.Println(selection.Find("#content").Html())
}

获取列表

viper

https://github.com/spf13/viperopen in new window

go get github.com/spf13/viper
go get github.com/spf13/cast // 类型转化
APP_NAME=orangbus
APP_KEY=zBqYyQrPNaIUsnRhsGtHLivjqiMjBVLS
APP_DEBUG=true
APP_URL=http://localhost:3000
APP_PORT=3000

/pkg/config/config.go

package config

import (
	"github.com/spf13/cast"
	viperlib "github.com/spf13/viper"
	"orangbus.cn/study-go/index/pkg/helpers"
)

// Initialize 触发加载 config 包的所有 init 函数
func Initialize() {
}

var viper *viperlib.Viper

// ConfigFunc 动态加载配置信息
type ConfigFun func() map[string]interface{}

// ConfigFuncs 先加载到此数据, loadConfig 在动态生成配置信息
var ConfigFuncs map[string]ConfigFun

var configPath = ".env" // main.go 同目录下的 .env 文件

func init() {
	viper = viperlib.New()
	viper.SetConfigType("env")
	viper.AddConfigPath(".")
	viper.SetEnvPrefix("appenv")
	// 读取环境变量
	viper.AutomaticEnv()
	ConfigFuncs = make(map[string]ConfigFun)
}

func InitConfig() {
	// 加载环境变量
	loadEnv()

	// 注册配置信息
	loadConfig()
}

func loadConfig() {
	for name, fn := range ConfigFuncs {
		viper.Set(name, fn())
	}
}

func loadEnv() {
	viper.SetConfigName(configPath)
	if err := viper.ReadInConfig(); err != nil {
		panic(err)
	}
	// 变更时重新加载
	viper.WatchConfig()
}

func internalGet(path string, defaultValue ...interface{}) interface{} {
	if !viper.IsSet(path) || helpers.Empty(viper.Get(path)) {
		if len(defaultValue) > 0 {
			return defaultValue[0]
		}
		return nil
	}
	return viper.Get(path)
}

// 读取环境变量,支持默认值
func Env(envName string, defaultValue ...interface{}) interface{} {
	if len(defaultValue) > 0 {
		return internalGet(envName, defaultValue[0])
	}
	return internalGet(envName)
}

func Add(name string, configFun ConfigFun) {
	ConfigFuncs[name] = configFun
}

// GetString 获取 String 类型的配置信息
func GetString(path string, defaultValue ...interface{}) string {
	return cast.ToString(internalGet(path, defaultValue...))
}

// GetInt 获取 Int 类型的配置信息
func GetInt(path string, defaultValue ...interface{}) int {
	return cast.ToInt(internalGet(path, defaultValue...))
}

// GetBool 获取 Bool 类型的配置信息
func GetBool(path string, defaultValue ...interface{}) bool {
	return cast.ToBool(internalGet(path, defaultValue...))
}

// GetStringMapString 获取结构数据
func GetStringMapString(path string) map[string]string {
	return viper.GetStringMapString(path)
}

/pkg/helpers/helpers.go

// Package helpers 存放辅助方法
package helpers

import "reflect"

// Empty 类似于 PHP 的 empty() 函数
func Empty(val interface{}) bool {
	if val == nil {
		return true
	}
	v := reflect.ValueOf(val)
	switch v.Kind() {
	case reflect.String, reflect.Array:
		return v.Len() == 0
	case reflect.Map, reflect.Slice:
		return v.Len() == 0 || v.IsNil()
	case reflect.Bool:
		return !v.Bool()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return v.Int() == 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return v.Uint() == 0
	case reflect.Float32, reflect.Float64:
		return v.Float() == 0
	case reflect.Interface, reflect.Ptr:
		return v.IsNil()
	}
	return reflect.DeepEqual(val, reflect.Zero(v.Type()).Interface())
}

/config/app.go

package config

import "orangbus.cn/study-go/index/pkg/config"

func init() {
	config.Add("app", func() map[string]interface{} {
		return map[string]interface{}{
			"name":  config.Env("APP_NAME", "orangbus"),
			"key":   config.Env("APP_KEY", "33446a9dcf9ea060a0a6532b166da32f304af0de"),
			"debug": config.Env("APP_DEBUG", false),
			"port":  config.Env("APP_PORT", 3000),
			"url":   config.Env("APP_URL", "http://localhost"),
		}
	})
}

main.go

package main

import (
	"fmt"
	"orangbus.cn/study-go/index/pkg/config"
)

func init() {
	config.Initialize()
	config.InitConfig()
}

func main() {
	fmt.Println(config.GetInt("app_port"))
	fmt.Println(config.GetInt("APP_PORT"))
}

示例2

gorm

https://gorm.io/zh_CN/docs/index.htmlopen in new window

go get gorm.io/gorm
go get gorm.io/driver/sqlite
go get gorm.io/driver/mysql

1、初始化

bootstrap/database.go

package bootstrap

import (
	"database-gorm/pkg/database"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
	"os"
	"path/filepath"
)

func SetupDatabase() {
	var dbConfig gorm.Dialector
	dbConfig = sqlite.Open(getDatabasePath())
	database.Connect(dbConfig)
}

func getDatabasePath() string {
	basePath, err := os.Getwd()
	if err != nil {
		return "database/database.sqlite"
	}
	return filepath.Join(basePath, "database/database.sqlite")

}

2、连接数据库

/pkg/database/database.go

package database

import (
	"database/sql"
	"gorm.io/gorm"
	"time"
)

var (
	DB    *gorm.DB
	SqlDB *sql.DB
)

/*
*
连接数据库
*/
func Connect(dbConfig gorm.Dialector) {
	var err error
	DB, err = gorm.Open(dbConfig, &gorm.Config{
		CreateBatchSize: 500,
	})
	if err != nil {
		panic(err)
	}
	SqlDB, err = DB.DB()
	SqlDB.SetMaxIdleConns(10)
	SqlDB.SetMaxOpenConns(10)
	SqlDB.SetConnMaxLifetime(time.Hour)
	if err != nil {
		panic(err)
	}
}

faker

https://pkg.go.dev/github.com/bxcodec/faker/v3open in new window

go get -u github.com/bxcodec/faker/v3
package factories

import (
	"database-gorm/app/models"
	"database-gorm/pkg/database"
	"github.com/bxcodec/faker/v3"
)

func FakerUser(number int) {
	userList := []models.User{}
	for i := 0; i < number; i++ {
		user := models.User{
			Name:     faker.Name(),
			Phone:    faker.Phonenumber(),
			Password: faker.Password(),
		}
		userList = append(userList, user)
	}

	// 插入到数据库中
	database.DB.CreateInBatches(userList, 500)
}

uuid

go get -u github.com/google/uuid
package test

import (
	"fmt"
	"github.com/google/uuid"
	"testing"
)

func TestUUid(t *testing.T) {
	fmt.Println(uuid.NewString()) // 6749b706-bb35-4760-9a23-f3ef65101e6c
}

cron

go get -u github.com/robfig/cron/v3

bcrypt 加密

 go get golang.org/x/crypto/bcrypt
package test

import (
	"fmt"
	"golang.org/x/crypto/bcrypt"
	"testing"
)

var password = "admin666"

// 加密
func TestBcrypt(t *testing.T) {
	passwd, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		fmt.Println(passwd)
		return
	}
	fmt.Println(string(passwd)) // $2a$10$zVPrJ.kiAWKqEKhuYjSpAu9QAjj/Mp7Mnn5P5dRRO8IvMqMkEzXR.
}

// 密码比对
func TestComparePwd(t *testing.T) {
	hashPasswd := "$2a$10$zVPrJ.kiAWKqEKhuYjSpAu9QAjj/Mp7Mnn5P5dRRO8IvMqMkEzXR."
	err := bcrypt.CompareHashAndPassword([]byte(hashPasswd), []byte(password))
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("密码相同")
}

jwt

https://github.com/dgrijalva/jwt-goopen in new window

go get github.com/dgrijalva/jwt-go

pkg/jwtToken/jwtToken

package jwtToken

import (
	"gin-web/app/models"
	"github.com/dgrijalva/jwt-go"
	"time"
)

const app_key = "orangbus.cn"
const expire_at = 30 // 失效天数

type jwtClaims struct {
	ID   uint64 `json:"id"`
	Name string `json:"name"`
	jwt.StandardClaims
}

func GenerateToken(user models.User) (string, error) {
	claims := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
		"id":    user.ID,
		"name":  user.Name,
		"phone": user.Phone,
		"exp":   time.Now().Add(time.Hour * 24 * expire_at).Unix(),
		"iat":   time.Now().Unix(), // 发布时间
	})
	token, err := claims.SignedString([]byte(app_key))
	if err != nil {
		return "", err
	}
	return token, nil
}

func Parse(token string) (models.User, error) {
	user := models.User{}
	parse, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
		return []byte(app_key), nil
	})
	if err != nil {
		return models.User{}, err
	}
	if claims, ok := parse.Claims.(jwt.MapClaims); ok && parse.Valid {
		user.ID = int64(uint64(claims["id"].(float64)))
		user.Name = claims["name"].(string)
		user.Phone = claims["phone"].(string)
	}
	return user, nil
}

func ValidateToken(token string) (bool, error) {

	return true, nil
}

webscoket

go-redis

https://redis.uptrace.devopen in new window

go get github.com/redis/go-redis/v9

pkg/cache/redis

package cache

import (
	"context"
	"github.com/redis/go-redis/v9"
	"movie-cloud/pkg/config"
	"runtime"
	"time"
)

var (
	Redis  *redis.Client
	prefix = "movie_cloud_"
	ctx    = context.Background()
)

/*
*
连接数据库
*/
func ConnectRedis() {
	Redis = redis.NewClient(&redis.Options{
		Addr:     config.GetRedisHost(),
		Password: config.GetRedisPassword(),
		DB:       config.GetRedisDB(),
		PoolSize: runtime.GOMAXPROCS(100),
		// 最小空闲连接数,受PoolSize限制
		MinIdleConns: 10,
	})
}

func Put(key, value string, duration ...int) {
	t := time.Duration(0)
	if len(duration) == 0 {
		t = time.Duration(duration[0])
	}
	Redis.Set(ctx, prefix+key, value, t)
}
func Get(key string) (string, error) {
	return Redis.Get(ctx, prefix+key).Result()
}

ip2region

https://github.com/lionsoul2014/ip2region?tab=readme-ov-fileopen in new window

https://github.com/lionsoul2014/ip2region/tree/master/binding/golangopen in new window

package service

import (
	"github.com/lionsoul2014/ip2region/binding/golang/xdb"
	"strings"
)

var dbPath = "ip2region.xdb"

func GetIpInfo(ip string) (map[string]string, error) {
	searcher, err := xdb.NewWithFileOnly(dbPath)
	return nil, err
	defer searcher.Close()
	ipInfo, err := searcher.SearchByStr(ip)
	return nil, err

	info := strings.Split(ipInfo, "|")
	region := map[string]string{}
	region["ip"] = ip
	region["county"] = info[0]
	region["area"] = info[1]
	region["region"] = info[2]
	region["city"] = info[3]
	region["isp"] = info[4]
	return region, nil
}

markdown 解析

https://github.com/russross/blackfriday/v2open in new window

func GetReadme() (string, error) {
	file, err := os.Open(readmePath)
	if err != nil {
		return "", err
	}
	defer file.Close()
	bytes, err := io.ReadAll(file)
	if err != nil {
		return "", err
	}
	content := blackfriday.Run(bytes)
	return string(content), nil
}

mapstructure

结构体绑定

go get github.com/mitchellh/mapstructure

air

github.com/cosmtrek/air

go install github.com/cosmtrek/air@latest
 air -v

webscoket

go get -u github.com/gorilla/websocket

前端连接

https://www.npmjs.com/package/vue3-websocketopen in new window

npm i vue3-websocket

main.js

import { createApp } from 'vue'
import App from './App.vue'
import socket from 'vue3-websocket'

const app = createApp(App)

// app.use(socket, 'ws://localhost:9000')
app.use(socket, {
    secured: false,
    host: 'localhost:9000/ws',
    protocols: ['soap']
})

app.mount('#app')

vue-templet

<template>
    <input v-model="text" />
    <button @click="sendMessage">Send a message</button>
</template>

<script setup>
import { ref, inject } from 'vue'
import { onMessage, onOpen, onClose, onError } from 'vue3-websocket'

const text = ref('')

const socket = inject('socket')

const sendMessage = () => socket.value.send(text.value)
//

onOpen(() => {
    console.log('WS connection is stable! ~uWu~')
})

onMessage(message => {
    console.log('Got a message from the WS: ', message)
})

onClose(() => {
    console.log('No way, connection has been closed 😥')
})

onError(error => {
    console.error('Error: ', error)
})
</script>

MongoDB

go get -u go.mongodb.org/mongo-driver

发送邮箱

excel 转化

pdf转化

调用系统命令

package main

import (
	"fmt"
	"os"
	"os/exec"
)

func main() {
	cmd := exec.Command("ls", "-l")
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err := cmd.Run()
	if err != nil {
		fmt.Println(err)
		return
	}
}