开发文档
该文档是一个可以在线浏览 Go 相关内容的资料库,用于快速查阅、学习和积累。其中含有许多开箱即用的模板。同时文档也在不断更新中。
Go介绍
Go(又称Golang)是Google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言。罗伯特·格瑞史莫、罗勃·派克及肯·汤普逊于2007年9月开始设计Go,稍后伊恩·兰斯·泰勒(Ian Lance Taylor)、拉斯·考克斯(Russ Cox)加入项目。Go是基于Inferno操作系统所开发的。Go于2009年11月正式宣布推出,成为开放源代码项目,支持Linux、macOS、Windows等操作系统。
官方文档
在线运行
https://play.golang.org/
https://play.studygolang.com/
https://goplay.space/
标准库
规范
学习资料
地鼠文档
Go语言圣经
GO专家编程
Go 语言设计模式
golangFamily
awesome-go-zh
算法模板
源码
快速使用
速查清单
常用语法
learning_tools
资料补给包
推荐
离线文档工具
数据库
日志
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
看云:国内专业的产品文档/书籍/用户手册
docsify
一个神奇的文档网站生成器
https://docsify.js.org/#/zh-cn/
docute
Docute 本质上就是一个 JavaScript 文件,它可以获取 Markdown 文件并将它们呈现为单页面应用。 它完全由运行时驱动,因此并不涉及服务端组件,这就意味着没有构建过程。你只需创建一个 HTML 文件和一堆 Markdown 文档,你的网站就差不多完成了!
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
比较简洁
mindoc
Golang实现的基于beego框架的接口在线文档管理系统