开发文档

该文档是一个可以在线浏览 Go 相关内容的资料库,用于快速查阅、学习和积累。其中含有许多开箱即用的模板。同时文档也在不断更新中。

Go介绍

Go(又称Golang)是Google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言。罗伯特·格瑞史莫、罗勃·派克及肯·汤普逊于2007年9月开始设计Go,稍后伊恩·兰斯·泰勒(Ian Lance Taylor)、拉斯·考克斯(Russ Cox)加入项目。Go是基于Inferno操作系统所开发的。Go于2009年11月正式宣布推出,成为开放源代码项目,支持Linux、macOS、Windows等操作系统。

官方文档

doc
gowalker

在线运行

https://play.golang.org/
https://play.studygolang.com/
https://goplay.space/

标准库

Go语言标准库
Go语言标准中文库

规范

Uber Go 语言编码规范

学习资料

地鼠文档
Go语言圣经
GO专家编程
Go 语言设计模式
golangFamily
awesome-go-zh
算法模板

源码

Go 语言原本

快速使用

速查清单
常用语法
learning_tools
资料补给包

推荐

离线文档工具

zeal
velocity

数据库

日志

logrus

package main

import (
	"github.com/sirupsen/logrus"
	"os"
)

func init() {
	logrus.SetFormatter(&logrus.JSONFormatter{
		TimestampFormat: "2006-01-02 15:04:05",
	})
	logrus.SetOutput(os.Stdout)
	logrus.SetLevel(logrus.InfoLevel)
}

func main() {
	logrus.WithFields(logrus.Fields{
		"animal": "walrus",
	}).Info("A walrus appears")

	logrus.Info("hello")
}

  • 打印效果
{"animal":"walrus","level":"info","msg":"A walrus appears","time":"2020-11-22 11:34:52"}
{"level":"info","msg":"hello","time":"2020-11-22 11:34:52"}

定时任务

robfig

package main

import (
	"fmt"
	"github.com/robfig/cron/v3"
	"log"
	"time"
)

func main() {
	TimeTask()
}

// TimeTask 定时任务
// cron.New() 分钟级别定时任务
// cron.New(cron.WithSeconds()) 秒级定时任务
func TimeTask() {
	c := cron.New(cron.WithSeconds())

	// 定时表
	cronTab := "*/3 * * * * ?"

	id, err := c.AddFunc(cronTab, task1)
	if err != nil {
		log.Println(err)
	}

	//开启任务
	c.Start() 

	//任务id
	fmt.Println(id)

	time.Sleep(time.Minute * 2) //测试使用
}

// task1 需要执行的任务
func task1() {
	now := time.Now().Format("2006-01-02 15:04:05")
	fmt.Println("定时任务执行时间", "-->", now)

}

文件上传

package main

import (
    "io"
    "io/ioutil"
    "log"
    "net/http"

    "github.com/julienschmidt/httprouter"
)

const (
    MAX_UPLOAD_SIZE = 1024 * 1024 * 20 //50MB
)

func main() {
    r := RegisterHandlers()

    http.ListenAndServe(":8080", r)
}

//RegisterHandlers ...
func RegisterHandlers() *httprouter.Router {
    router := httprouter.New()

    router.POST("/upload", uploadHandler)

    return router
}
func uploadHandler(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
    r.Body = http.MaxBytesReader(w, r.Body, MAX_UPLOAD_SIZE)
    if err := r.ParseMultipartForm(MAX_UPLOAD_SIZE); err != nil {
        log.Printf("File is too big")
        return
    }
    file, headers, err := r.FormFile("file")
    if err != nil {
        log.Printf("Error when try to get file: %v", err)
        return
    }
    //获取上传文件的类型
    if headers.Header.Get("Content-Type") != "image/png" {
        log.Printf("只允许上传png图片")
        return
    }
    data, err := ioutil.ReadAll(file)
    if err != nil {
        log.Printf("Read file error: %v", err)
        return
    }
    fn := headers.Filename
    err = ioutil.WriteFile("./video/"+fn, data, 0666)
    if err != nil {
        log.Printf("Write file error: %v", err)
        return
    }
    w.WriteHeader(http.StatusCreated)
    io.WriteString(w, "Uploaded successfully")
}

图片预览

安全map

package main

import (
	"fmt"
	"sync"
)

// NewSafeMap 初始化SafeMap
func NewSafeMap() *SafeMap {
	return &SafeMap{
		Data: map[string]interface{}{},
	}
}

// SafeMap 安全Map
type SafeMap struct {
	Data map[string]interface{} // 自定义map
	Lock sync.RWMutex
}

// Load Get方法
func (c *SafeMap) Load(k string) interface{} {
	c.Lock.RLock()
	defer c.Lock.RUnlock()
	if v, exit := c.Data[k]; exit {
		return v
	}
	return nil
}

// Store Set方法
func (c *SafeMap) Store(k string, v interface{}) {
	c.Lock.Lock()
	defer c.Lock.Unlock()
	if c.Data == nil {
		c.Data = make(map[string]interface{})
	}
	c.Data[k] = v
}

func main() {
	m := SafeMap{
		Data: make(map[string]interface{}),
	}
	var wg sync.WaitGroup

	loopCount := 10
	wg.Add(loopCount)
	for i := 0; i < loopCount; i++ {
		num := i
		go func() {
			m.Store(fmt.Sprintf("%d", num), num+1)
			wg.Done()
		}()
	}
	wg.Wait()
	m.Data["3"] = 18
	fmt.Println(m.Data)
}

常用加密

密码加密

package main

import (
	"errors"
	"fmt"
	"github.com/prometheus/common/log"
	"golang.org/x/crypto/bcrypt"
)

//GeneratePassword 加密明文密码
func GeneratePassword(pwd string) (string, error) {
	encryptedPwd, err := bcrypt.GenerateFromPassword([]byte(pwd), bcrypt.DefaultCost)
	return string(encryptedPwd), err
}

//ValidatePassword 验证密码
// pwd 明文密码
// encryptedPwd 加密的密码
func ValidatePassword(pwd string, encryptedPwd string) (bool, error) {
	if err := bcrypt.CompareHashAndPassword([]byte(encryptedPwd), []byte(pwd)); err != nil {
		return false, errors.New("wrong password")
	}
	return true, nil
}

func main() {
	p := "123456"
	pwd, err := GeneratePassword(p)
	if err != nil {
		log.Error(err)
	}
	fmt.Println("ciphertext:", pwd)

	isOk, _ := ValidatePassword(p, pwd)
	if !isOk {
		log.Error(err)
	}
	fmt.Println(isOk)
}

打印结果

ciphertext: $2a$10$mGB.ml/M/2A..NgIrFSk1ekl0Qi3gIvfk3n0sOFTje9ScZtxxpLfG
true

MD5

package main

import (
	"crypto/md5"
	"fmt"
	"io"
)

func Md5(str string) string {
	h := md5.New()
	_, _ = io.WriteString(h, str)
	return fmt.Sprintf("%x", h.Sum(nil))
}

func main() {
	fmt.Println(Md5("123456"))
}

打印结果

e10adc3949ba59abbe56e057f20f883e

SHA

package main

import (
	"crypto/sha1"
	"crypto/sha256"
	"fmt"
	"io"
)

func SHA1(str string) string {
	h := sha1.New()
	_, _ = io.WriteString(h, str)
	return fmt.Sprintf("%x", h.Sum(nil))
}

func SHA2(str string) string {
	h := sha256.New()
	_, _ = io.WriteString(h, str)
	return fmt.Sprintf("%x", h.Sum(nil))
}

func main() {
	msg := "https://golang.org"
	fmt.Println(SHA1(msg))
	fmt.Println(SHA2(msg))
}


打印结果

0a95b510a2e68b88ebc9bc09e76f7dbcfa1eb90e
bfd04cc20536303bd2c62bad327217f5c94f96578a5e95ca495f1d46c113016b

BASE64

package main

import (
	"encoding/base64"
	"fmt"
)

func Base64Encode(str string) string {
	encoded := base64.StdEncoding.EncodeToString([]byte(str))
	return encoded
}

func Base64Decode(str string) (string, error) {
	decoded, err := base64.StdEncoding.DecodeString(str)
	if err != nil {
		return "", err
	}
	return string(decoded), nil
}

func main() {
	msg := "https://golang.org"
	fmt.Println(Base64Encode(msg))
	fmt.Println(Base64Decode("aHR0cHM6Ly9nb2xhbmcub3Jn"))
}

AES加解密

package main

import (
    "bytes"
    "crypto/aes"
    "crypto/cipher"
    "encoding/base64"
    "errors"
    "fmt"
)

//高级加密标准(Adevanced Encryption Standard ,AES)

//16,24,32位字符串的话,分别对应AES-128,AES-192,AES-256 加密方法
//key不能泄露
var PwdKey = []byte("DIS**#KKKDJJSKDI")

//PKCS7 填充模式
func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
    padding := blockSize - len(ciphertext)%blockSize
    //Repeat()函数的功能是把切片[]byte{byte(padding)}复制padding个,然后合并成新的字节切片返回
    padtext := bytes.Repeat([]byte{byte(padding)}, padding)
    return append(ciphertext, padtext...)
}

//填充的反向操作,删除填充字符串
func PKCS7UnPadding(origData []byte) ([]byte, error) {
    //获取数据长度
    length := len(origData)
    if length == 0 {
        return nil, errors.New("加密字符串错误!")
    } else {
        //获取填充字符串长度
        unpadding := int(origData[length-1])
        //截取切片,删除填充字节,并且返回明文
        return origData[:(length - unpadding)], nil
    }
}

//实现加密
func AesEcrypt(origData []byte, key []byte) ([]byte, error) {
    //创建加密算法实例
    block, err := aes.NewCipher(key)
    if err != nil {
        return nil, err
    }
    //获取块的大小
    blockSize := block.BlockSize()
    //对数据进行填充,让数据长度满足需求
    origData = PKCS7Padding(origData, blockSize)
    //采用AES加密方法中CBC加密模式
    blocMode := cipher.NewCBCEncrypter(block, key[:blockSize])
    crypted := make([]byte, len(origData))
    //执行加密
    blocMode.CryptBlocks(crypted, origData)
    return crypted, nil
}

//实现解密
func AesDeCrypt(cypted []byte, key []byte) ([]byte, error) {
    //创建加密算法实例
    block, err := aes.NewCipher(key)
    if err != nil {
        return nil, err
    }
    //获取块大小
    blockSize := block.BlockSize()
    //创建加密客户端实例
    blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
    origData := make([]byte, len(cypted))
    //这个函数也可以用来解密
    blockMode.CryptBlocks(origData, cypted)
    //去除填充字符串
    origData, err = PKCS7UnPadding(origData)
    if err != nil {
        return nil, err
    }
    return origData, err
}

//加密base64
func EnPwdCode(pwd []byte) (string, error) {
    result, err := AesEcrypt(pwd, PwdKey)
    if err != nil {
        return "", err
    }
    return base64.StdEncoding.EncodeToString(result), err
}

//解密
func DePwdCode(pwd string) ([]byte, error) {
    //解密base64字符串
    pwdByte, err := base64.StdEncoding.DecodeString(pwd)
    if err != nil {
        return nil, err
    }
    //执行AES解密
    return AesDeCrypt(pwdByte, PwdKey)

}
func main() {
    str := []byte("12fff我是ww.topgoer.com的站长枯藤")
    pwd, _ := EnPwdCode(str)
    bytes, _ := DePwdCode(pwd)
    fmt.Println(string(bytes))
}

精确计算

decimal

package main

import (
	"fmt"
	"github.com/prometheus/common/log"
	"github.com/shopspring/decimal"
)

// imprecise 不精确demo
func imprecise() {
	a := 2.07
	b := 1.0
	c := a - b
	fmt.Printf("c=%v\n", c)
	//c=1.0699999999999998
}

func main() {
	a := "2.07"
	b := "1.0"
	ad, err := decimal.NewFromString(a)
	if err != nil {
		log.Error(err)
	}
	bd, err := decimal.NewFromString(b)
	if err != nil {
		log.Error(err)
	}
	cd := ad.Sub(bd)
	c, _ := cd.Float64()
	fmt.Printf("c=%v\n", c)
}


官方包

// Pct x,y百分比值
func Pct(x, y float64) float64 {
	xb := big.NewFloat(x)
	yb := big.NewFloat(y)
	pct := big.NewFloat(100)

	res, _ := xb.Mul(xb.Quo(xb, yb), pct).Float64()
	res = math.Trunc(res*1e2) * 1e-2
	return res
}

func main() {
	// 有理数
	price := big.NewRat(48, 1) // 48/1
	total := big.NewRat(95, 1) // 95/1
	pct := big.NewRat(100, 1)  // 100/1

	// 注:Rat结构体对应方法,只针对结果,故无论是price.Mul或者total.Mul效果是一样的
	tf, _ := total.Mul(total.Quo(price, total), pct).Float64() // 该表达式等价于-->价格/总价*100
	t := math.Trunc(tf*1e2) * 1e-2                             // 浮点类型保留小数点2位
	fmt.Println(t)

	fmt.Println(Pct(3,78))
}

验证器

validator

package main

import (
	"fmt"
	"github.com/go-playground/validator/v10"
)

// Validate 全局验证器
var Validate *validator.Validate

func init() {
	Validate = validator.New()
}

// User 结构体
type User struct {
	Name   string `json:"name" validate:"required"`        //名称,必须
	Gender int    `json:"gender"`                          //性别,不做要求
	Age    int    `json:"age" validate:"gte=0,lte=130"`    //年龄,0-130
	Email  string `json:"email" validate:"required,email"` //邮箱,必须
	Book   Book   `json:"book validate,dive,validate"`     //书籍结构体,必须
}

// Book 书籍
type Book struct {
	Edu     string `json:"edu"`
	Fiction string `json:"fiction" validate:"required"` // 必须
}

// Validate 结构体封装验证器
func (c *User) Validate() {
	err := Validate.Struct(c)
	if err != nil {
		c.ErrArgs(err)
	}
	return
}

// ErrArgs 结构体封装错误返回
func (c *User) ErrArgs(err error) {
	fmt.Println(err)
}

func main() {

	// 1.模拟前端传值
	user := &User{
		Name:  "小明",           // 不能为空
		Age:   23,             //年龄超过130岁
		Email: "foo@@bar.com", // 不能为空,且为邮箱格式
		Book: Book{
			Edu: "离散数学及其应用", // 无要求
			//Fiction: "鹿鼎记",      //  不能为空
		},
	}

	// 2.使用验证器校验
	// 注:验证不通过直接返回错误给web端
	user.Validate()
}


打印结果

Key: 'User.Email' Error:Field validation for 'Email' failed on the 'email' tag
Key: 'User.Book.Fiction' Error:Field validation for 'Fiction' failed on the 'required' tag

jwt

jwt-go

package jwtgo

import (
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"time"
)

const (
	// secretKey 加密key
	secretKey = "Q6jhLn8vsD04WmAR"
)

// expTime token有效时间
var expTime = time.Now().Add(time.Hour * 2).Unix()

// JwtClaims 自定义 Claims 结构体
type JwtClaims struct {
	// 按需求自定义下方参数
	Id   string
	Name string
	Role string
	jwt.StandardClaims
}

// GenerateToken
// 利用JwtClaims生成token字符串
// 加密方式; SHA256
func GenerateToken(id, name, role string) (tokenStr string, err error) {

	jwtClaims := &JwtClaims{
		Id:   id, //用户id
		Name: name,
		Role: role,
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: expTime,
			//Issuer:    issuer, //发行人
		},
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwtClaims)
	tokenStr, err = token.SignedString([]byte(secretKey))
	return
}

//ParseToken 解析token
func ParseToken(tokenString string) (*JwtClaims, error) {
	token, err := jwt.ParseWithClaims(tokenString, &JwtClaims{}, func(token *jwt.Token) (interface{}, error) {
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("unexpected signing method %v ", token.Header["alg"])
		}
		return []byte(secretKey), nil
	})

	if claims, ok := token.Claims.(*JwtClaims); ok && token.Valid {
		return claims, nil
	} else {
		return nil, err
	}
}

使用

package main

import (
	"fmt"
	"gotoys/plugins/jwtgo"
	"log"
)

func main() {

	// 生成token
	token, err := jwtgo.GenerateToken(
		"cc6a6e14-2f11-4b61-b077-1b0f7b9c7944",
		"xiao ming",
		"administrator")

	if err != nil {
		log.Printf("%v", err)
	} else {
		fmt.Printf("token:%s\n", token)
	}

	// 解析token
	jwtClaims, err := jwtgo.ParseToken(token)
	if err != nil {
		log.Printf("%v", err)
	} else {
		fmt.Printf("id:%s\nname:%s\nrole:%s\nexp:%d", jwtClaims.Id, jwtClaims.Name, jwtClaims.Role, jwtClaims.ExpiresAt)
	}

}

打印结果

token:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJJZCI6ImNjNmE2ZTE0LTJmMTEtNGI2MS1iMDc3LTFiMGY3YjljNzk0NCIsIk5hbWUiOiJ4aWFvIG1pbmciLCJSb2xlIjoiYWRtaW5pc3RyYXRvciIsImV4cCI6MTYwODk5Nzk5NH0.RuPNtNzoUQiaRb2qQYgfR2FBoi4rpox3kzMdO_WgUt0
id:cc6a6e14-2f11-4b61-b077-1b0f7b9c7944
name:xiao ming
role:administrator
exp:1608997994

微信SDK

silenceper

配置参数

package wx

// 公众号配置
const (
	AppID          = "wx7fa401xe810n1eb7"
	AppSecret      = "35673237f5676a727b45b22f4ca8e34a"
	EncodingAESKey = ""
)

// 微信支付配置
const (
	MchID     = "1602872469"                       // 商户ID
	Key       = "454dawdahhWWW441D8EXDle454741211" // 商户Key
	NotifyURL = "http://www.test.com/v1/notify"    // 通知回调链接
)

初始化

package wx

import (
	"github.com/silenceper/wechat/v2"
	"github.com/silenceper/wechat/v2/cache"
	"github.com/silenceper/wechat/v2/miniprogram"
	miniConfig "github.com/silenceper/wechat/v2/miniprogram/config"
	"github.com/silenceper/wechat/v2/officialaccount"
	offConfig "github.com/silenceper/wechat/v2/officialaccount/config"
	"github.com/silenceper/wechat/v2/pay"
	payConfig "github.com/silenceper/wechat/v2/pay/config"
)

var WC *wechat.Wechat                         // 微信
var Official *officialaccount.OfficialAccount // 微信公众号
var MiniProgram *miniprogram.MiniProgram      // 微信小程序
var Pay *pay.Pay                              // 微信支付
var memory *cache.Memory                      // 微信缓存

func init() {
	WC = wechat.NewWechat()
	memory = cache.NewMemory()
	InitOfficial()
	InitMiniProgram()
	InitPay()
}

func InitOfficial() {
	cfg1 := &offConfig.Config{
		AppID:     AppID,
		AppSecret: AppSecret,
		Cache:     memory,
	}
	Official = WC.GetOfficialAccount(cfg1)
}

func InitMiniProgram() {
	cfg2 := &miniConfig.Config{
		AppID:     AppID,
		AppSecret: AppSecret,
		Cache:     memory,
	}
	MiniProgram = WC.GetMiniProgram(cfg2)
}

func InitPay() {
	cfg3 := &payConfig.Config{
		AppID:     AppID,
		MchID:     MchID,
		Key:       Key,
		NotifyURL: NotifyURL,
	}
	Pay = WC.GetPay(cfg3)
}

使用

package main

import (
	"fmt"
	"os"
)

func main() {
	// 注:使用该工具无需关注AccessToken的获取&失效问题
	// 工具内部已经封装对AccessToken的缓存与刷新逻辑
	// 用户只需关注实际需要调用的API即可
	// 示例:获取公众号所有用户openid
	ds, err := wx.Official.GetUser().ListAllUserOpenIDs()
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Println("count", len(ds))
		for i, v := range ds {
			fmt.Println(i, v)
		}
	}
}

打印结果

count 59
0 otlUS1HpVEUEnE-64Q3EZDbxvV2g
1 otlUS1BxyVhVUD44QoJZ-mSokB_c
2 otlUS1O64PI6svk4tvGa6oU3rfSk
3 otlUS1DEse6XKfyJd2WyV5hliNCs
...
57 otlUS1DdGvBajcxni1szCyNeiYsk
58 otlUS1EH6jiBHlXzMLqBgFz2vvBs

排序&二分查找

package main

import (
	"fmt"
	"sort"
)

var nums = []int{6, 42, 45, 81, 85, 42, 40, 57, 8, 1}
var cs = []string{"HA", "mmo0", "shSEpJ", "4C", "DKaHg", "B", "KI", "G", "Pnf", "2k8eQ"}
var persons = []Person{{"zeng qiang", 28}, {"xiao ming", 18}, {"yu wei", 36}}

func main() {
	sort.Ints(nums) // 升序
	fmt.Println("nums asc", nums)

	keyword1 := 57
	i := sort.SearchInts(nums, 57) // 二分法查找元素(仅升序)
	fmt.Println(keyword1, "in", i)
	sort.Sort(sort.Reverse(sort.IntSlice(nums))) // 降序
	fmt.Println("nums desc", nums)

	fmt.Println()

	sort.Strings(cs) // 升序
	fmt.Println("cs asc", cs)
	keyword2 := "4C"
	i = sort.SearchStrings(cs, keyword2)
	fmt.Println(keyword2, "in", i)
	sort.SliceStable(cs, func(i, j int) bool { // 按字符串最后一个字符升序
		return cs[i][len(cs[i])-1] < cs[j][len(cs[j])-1]
	})
	fmt.Println(cs)

	fmt.Println()

	sort.SliceStable(persons, func(i, j int) bool { // 结构体按年龄升序
		return persons[i].Age < persons[j].Age
	})
	fmt.Println("persons age asc", persons)

	age := 28                                                                        // 按年龄查询下标
	i = sort.Search(len(persons), func(i int) bool { return persons[i].Age >= age }) // 二分查找结构体
	fmt.Println(age, "in", i)

	sort.SliceStable(persons, func(i, j int) bool { // 结构体按名称(字符串)升序
		return persons[i].Name < persons[j].Name
	})
	fmt.Println("persons name asc", persons)

	name := "zeng qiang"                                                               // 按名字(字符串)查询下标
	i = sort.Search(len(persons), func(i int) bool { return persons[i].Name >= name }) // 二分查找结构体
	fmt.Println(name, "in", i)

}

type Person struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

生成数组

在线1:https://play.golang.org/
在线2:https://play.studygolang.com/

package main

import (
	"encoding/json"
	"fmt"
	"math/rand"
	"strings"
	"time"
)

//在线1:https://play.golang.org/
//在线2:https://play.studygolang.com/

func init() {
	t := time.Now().UnixNano()
	rand.Seed(t)
}

func main() {
	ints(10)  // 生成整数数组
	chars(10) // 生成字符串数组
}

func ints(length int) {
	if length <= 0 {
		length = 10
	}

	var arr []int
	for i := 0; i < length; i++ {
		arr = append(arr, rand.Intn(100))
	}
	s, _ := json.Marshal(arr)
	nums := strings.Trim(string(s), "[]")
	fmt.Printf("%s{%s}\n", "var arr = []int", nums)
}

func chars(length int) {

	if length <= 0 {
		length = 10
	}
	var arr []string
	for i := 0; i < length; i++ {
		l := 1
		t := rand.Intn(6)
		if t > 0 {
			l = t
		}
		arr = append(arr, monoStr(l))
	}

	for i := 0; i < len(arr); i++ {
		arr[i] = fmt.Sprintf("\"%s\"", arr[i])
	}
	fmt.Printf("%s{%s}\n", "var chars = []string", strings.Join(arr, ","))
}

const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
const (
	letterIdxBits = 6                    // 6 bits to represent a letter index
	letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
	letterIdxMax  = 63 / letterIdxBits   // # of letter indices fitting in 63 bits
)

var src = rand.NewSource(time.Now().UnixNano())

func monoStr(n int) string {

	b := make([]byte, n)
	for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
		if remain == 0 {
			cache, remain = src.Int63(), letterIdxMax
		}
		if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
			b[i] = letterBytes[idx]
			i--
		}
		cache >>= letterIdxBits
		remain--
	}
	return string(b)
}

数据库

Gin

Gin 是什么?

Gin 是一个用 Go (Golang) 编写的 HTTP web 框架。 它是一个类似于 martini 但拥有更好性能的 API 框架, 优于 httprouter,速度提高了近 40 倍。如果你需要极好的性能,使用 Gin 吧。

官方文档

https://gin-gonic.com/zh-cn/docs/

数据库

mongodb

mgo

连接mgo

const (
	uri = "mongodb://127.0.0.1:27017/admin"
	
	//poolSize 连接池大小
	poolSize = 100
)

var (
	// Client mongodb client
	Client *mgo.Session
)

func init() {
	var err error
	Client, err = mgo.Dial(uri)
	if err != nil {
		panic("database connection failed:" + err.Error())
	}

	Client.SetPoolLimit(poolSize)
}

插入数据

package main

import (
	"fmt"
	"github.com/prometheus/common/log"
)

type User struct {
	Name   string `bson:"name"`
	Gender int    `bson:"gender"`
	Age    int    `bson:"age"`
}

const (
	GeneralGender = iota
	Male
	Female
)

const (
	DBName   = "redcoast"
	UserColl = "user"
)

func main() {
	user := &User{
		Name:   "jack",
		Gender: Male,
		Age:    21,
	}
	session := Client.Copy()
	err := session.DB(DBName).C(UserColl).Insert(user)
	if err != nil {
		log.Error(err)
	} else {
		fmt.Println(user)
	}

}

相关语法

官网文档

https://www.elastic.co/guide/cn/elasticsearch/guide/current/index.html

https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html

按时间查找
{
    "query": {
        "bool": {
            "filter": [
                {
                    "range": {
                        "update_time": {
                            "gte": "2021-04-06 21:18:25"
                        }
                    }
                }
            ]
        }
    }
}

按关键词+范围搜索

{
    "query": {
        "bool": {
            "must_not": {
                "match": {
                    "online_count": 0
                }
            },
            "filter": [
                {
                    "range": {
                        "update_time.keyword": {
                            "gte": "2021-04-14 12:00:00"
                        }
                    }
                }
            ]
        }
    }
}

多条件+范围搜索

{
    "query": {
        "bool": {
            "must": [
                {
                    "term": {
                        "online_status": 1
                    }
                },
                {
                    "exists": {
                        "field": "access_time"
                    }
                }
            ],
            "filter": [
                {
                    "range": {
                        "update_time": {
                            "gte": "now+8h-23m"
                        }
                    }
                }
            ]
        }
    },
    "size": 260
}

查询数量查询

{
    "query": {
        "match_all": {}
    },
    "size": 10
}

精确查找

{
    "query": {
        "term": {
            "userName": "jack"
        }
    },
    "size": 10
}

聚合查询

{
    "size": 0,
    "aggs": {
        "indexs": {
            "terms": {
                "field": "index_code.keyword",
                "order": {
                    "maxValue": "asc"
                },
                "size": 3
            },
            "aggs": {
                "maxValue": {
                    "sum": {
                        "field": "online_count"
                    }
                }
            }
        }
    }
}

模糊查询

{
    "query": {
        "bool": {
            "filter": {
                "term": {
                    "hazard_code.keyword": "141110089005"
                }
            },
            "should": [
                {
                    "wildcard": {
                        "target_name.keyword": "*合成塔塔壁上部*"
                    }
                },
                {
                    "wildcard": {
                        "quota_id.keyword": "*41110089005P0002WD01*"
                    }
                },
                {
                    "wildcard": {
                        "equip_name.keyword": "*10万吨合成氨氨合成塔*"
                    }
                },
                {
                    "wildcard": {
                        "equip_code.keyword": "*41110089005P000"
                    }
                }
            ]
        }
    }
}

错误定位

ignore_malformed 错误数据无法匹配问题

https://www.coder.work/article/7401749

出发ignore_malformed后, 该错误字段不会索引, 故可以使用exists匹配该字段,从而达到搜索的目的

mysql

MySQL数据库服务是一个完全托管的数据库服务,可使用世界上最受欢迎的开源数据库来部署云原生应用程序。 它是百分百由MySQL原厂开发,管理和提供支持。

速查清单


SELECT VERSION(); -- mysql版本

begin;rollback;commit; -- 事务:开始、回滚、提交  

SELECT DATE_FORMAT(NOW(),'%Y-%m-%d'); -- 格式化今日(2021-08-16)

SELECT DATE_FORMAT(NOW(),'%Y-%m-%d %H:%i:%s'); -- 格式化今日(2021-08-16 06:52:06)

SELECT DATE_SUB(NOW(),INTERVAL 1 DAY); -- 一天前

SELECT DATE_FORMAT(DATE_SUB(NOW(),INTERVAL 1 DAY),'%Y-%m-%d');-- 格式化一天前

SELECT STR_TO_DATE('2021-06-01 14:03:26','%Y-%m-%d %H:%i:%s'); -- 字符串转时间

SELECT SUBSTRING('abcdefghijk',5); -- 正向范围截取子串 result:efghijk
SELECT SUBSTRING('abcdefghijk',-4); -- 反向范围截取子串 result: hijk

SELECT CONCAT('My', 'S', 'QL'); -- 连接字符串

SELECT IF(1>2,2,3);  -- 选择条件

SELECT IFNULL(1,2);  -- 过滤null

SELECT CASE WHEN 1>0 THEN 'true' ELSE 'false' END column_name; -- 选择条件

SELECT CASE WHEN 1>0 THEN 'one' WHEN 2>0 THEN 'two' ELSE 'more' END column_name; --选择条件

SELECT 1 <=> 1, NULL <=> NULL, 1 <=> NULL, 1 = NULL; -- 可比较NULL值操作符

xorm

https://gobook.io/read/gitea.com/xorm/manual-zh-CN/

xormplus增强版版文档

https://www.kancloud.cn/xormplus/xorm/167077

相关文档工具

gitbook

开源制作电子书工具

https://github.com/GitbookIO/gitbook-cli

mdbook

与gitbook相似度极高,使用简单

https://rust-lang.github.io/mdBook/

kancloud

看云:国内专业的产品文档/书籍/用户手册

https://www.kancloud.cn/

docsify

一个神奇的文档网站生成器

https://docsify.js.org/#/zh-cn/

docute

Docute 本质上就是一个 JavaScript 文件,它可以获取 Markdown 文件并将它们呈现为单页面应用。 它完全由运行时驱动,因此并不涉及服务端组件,这就意味着没有构建过程。你只需创建一个 HTML 文件和一堆 Markdown 文档,你的网站就差不多完成了!

https://docute.org/zh/

slate

双屏显示(类似于postman接口文档样式)

https://slatedocs.github.io/slate/

docusaurus

帮你快速构建并优化网站,让你专注于创作内容 facebook

https://docusaurus.io/zh-CN/docs/

docusaurus

The source code that powers readthedocs.org 网站比较素

https://github.com/readthedocs/readthedocs.org

docpress

比较简洁

http://docpress.github.io/

mindoc

Golang实现的基于beego框架的接口在线文档管理系统

https://github.com/mindoc-org/mindoc